diff --git a/.github/workflows/build-and-push.yml b/.github/workflows/build-and-push.yml
index bb7f080..78827ff 100644
--- a/.github/workflows/build-and-push.yml
+++ b/.github/workflows/build-and-push.yml
@@ -21,8 +21,10 @@ jobs:
include:
- image: mcp-server
dockerfile: mcp_server/Dockerfile
- - image: ui
- dockerfile: ui/Dockerfile
+ - image: api
+ dockerfile: api/Dockerfile
+ - image: frontend
+ dockerfile: frontend/Dockerfile
steps:
- uses: actions/checkout@v4
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 7124ac5..0ff1a71 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -36,9 +36,19 @@ jobs:
python-version: '3.11'
cache: pip
- - name: Install dependencies
+ - uses: actions/setup-node@v4
+ with:
+ node-version: '22'
+
+ - name: Install Python dependencies
run: pip install -r tests/requirements.txt
+ - name: Install frontend dependencies
+ run: |
+ cd frontend
+ corepack enable
+ yarn install --immutable
+
- name: Apply database migrations
run: |
for f in db/*.sql; do
@@ -46,5 +56,12 @@ jobs:
PGPASSWORD=prdforge psql -h localhost -U prdforge -d prdforge -f "$f"
done
- - name: Run tests
+ - name: Run Python tests
run: python -m pytest tests/test_mcp_tools.py tests/test_ui_api.py -v --tb=short
+
+ - name: Run frontend checks
+ run: |
+ cd frontend
+ yarn lint
+ yarn typecheck
+ yarn test --run
diff --git a/AGENTS.md b/AGENTS.md
index e0be825..d83a21c 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -6,11 +6,12 @@ PRD Forge is a self-hosted sectional PRD management system. It stores documents
## Architecture
-Three Docker Compose services:
-- **PostgreSQL 16** (`postgres:16-alpine`) — 10 tables, 2 views, schema in `db/01_init.sql`, seed in `db/02_seed.sql` (SnapHabit sample, 12 sections), comments in `db/03_comments.sql`, replies+settings in `db/04_replies_and_settings.sql`, token stats in `db/05_token_stats.sql`, chat memory in `db/06_chat.sql`
-- **MCP Server** (`mcp_server/server.py`, ~850 lines) — FastMCP with 31 tools, asyncpg, stdio + HTTP transports
-- **Web UI** (`ui/app.py`, ~1637 lines) — FastAPI, dark theme with vertical nav rail, inline comments with replies, project settings, project creation/switching, force-directed dependency graph, and always-visible streaming Claude chat with selection-context injection
-- **Shared** (`shared/settings.py`) — Settings schema + validation, imported by both MCP server and UI
+Four Docker Compose services:
+- **PostgreSQL 16** (`postgres:16-alpine`) — 11 tables, 2 views, schema in `db/01_init.sql`, seed in `db/02_seed.sql` (SnapHabit sample, 12 sections), comments in `db/03_comments.sql`, replies+settings in `db/04_replies_and_settings.sql`, token stats in `db/05_token_stats.sql`, chat memory in `db/06_chat.sql`, MCP activity in `db/08_mcp_activity.sql`
+- **MCP Server** (`mcp_server/server.py`, ~1560 lines) — FastMCP with 31 tools, asyncpg, stdio + HTTP transports
+- **Python API** (`api/app.py`, ~1620 lines) — FastAPI backend, REST endpoints for projects/sections/chat/comments/token-stats
+- **Frontend** (`frontend/`, Next.js 15) — React 19, Tailwind v4, shadcn/ui. Proxies `/api/*` to Python API
+- **Shared** (`shared/settings.py`) — Settings schema + validation, imported by both MCP server and Python API
## Key Design Principles
@@ -30,27 +31,33 @@ Three Docker Compose services:
| File | Purpose | ~Lines |
|------|---------|--------|
-| `docker-compose.yml` | 3-service stack definition | 68 |
+| `docker-compose.yml` | 4-service stack definition | 75 |
| `db/01_init.sql` | Schema DDL (tables, indexes, triggers, views) | 154 |
| `db/02_seed.sql` | SnapHabit sample seed (12 sections, 12 deps) | 570 |
| `db/05_token_stats.sql` | Token usage estimates table | 12 |
| `db/06_chat.sql` | Chat tables migration (project chats + messages) | 41 |
+| `db/08_mcp_activity.sql` | MCP write activity tracking | 12 |
| `docs/tool-reference.md` | MCP tool table and usage examples | 100 |
| `docs/data-model.md` | ER diagram, dependency types, statuses, tags | 141 |
| `docs/scaling.md` | Multi-user and scaling guidance | 90 |
| `db/03_comments.sql` | Inline comments table (section_comments) | 20 |
| `db/04_replies_and_settings.sql` | Comment replies + project settings tables | 40 |
| `shared/settings.py` | Settings schema, defaults, validation (shared) | 30 |
-| `mcp_server/server.py` | MCP server with 31 tools | 1290 |
-| `ui/app.py` | FastAPI web UI with nav rail, replies, settings, project creation/switching, always-visible streaming chat (selection context), light/dark theme | 1637 |
-| `ui/static/fonts.css` | Vendored Google Fonts (@font-face declarations) | 200+ |
-| `ui/static/fonts/` | Vendored woff2 font files (Inter + JetBrains Mono) | — |
+| `mcp_server/server.py` | MCP server with 31 tools + activity tracking | 1560 |
+| `api/app.py` | FastAPI Python API (REST endpoints, chat, auth) | 1620 |
+| `api/auth.py` | Python auth middleware (session validation, role resolution) | 100 |
+| `api/auth_contract.py` | Better Auth table/column contract verification | 50 |
+| `api/errors.py` | Structured error responses (9 error codes) | 70 |
+| `api/ws.py` | WebSocket token minting + verification (HMAC-SHA256) | 80 |
+| `frontend/` | Next.js 15 frontend (React 19, Tailwind v4, shadcn/ui) | — |
+| `frontend/server.ts` | Custom Node server with WS proxy | 45 |
+| `frontend/prisma/schema.prisma` | Better Auth tables (7 models) | 110 |
| `tests/conftest.py` | Test fixtures (db pool, cleanup, monkeypatch) | 64 |
| `tests/test_mcp_tools.py` | MCP tool tests (53 tests) | 700+ |
| `tests/test_ui_api.py` | UI endpoint tests (71 tests) | 940+ |
| `tests/test_smoke.py` | CI smoke tests (MCP, DB, UI, seed data) | 85 |
| `.github/workflows/test.yml` | CI: runs 124 tests on every PR to main | 50 |
-| `.github/workflows/build-and-push.yml` | CD: builds Docker images on tag push | 63 |
+| `.github/workflows/build-and-push.yml` | CD: builds 3 Docker images on tag push | 65 |
## MCP Tool Groups
@@ -76,16 +83,22 @@ Three Docker Compose services:
## Database Schema Quick Reference
-- **projects** — id, name, slug (unique), description, version, created_at, updated_at
-- **sections** — id, project_id, parent_section_id, slug, title, section_type, sort_order, status, content, summary, tags[], notes, word_count (generated), created_at, updated_at. UNIQUE(project_id, slug), UNIQUE(project_id, id)
-- **section_revisions** — id, section_id, revision_number, content, summary, change_description, created_at. UNIQUE(section_id, revision_number)
+- **projects** — id, name, slug (unique), description, version, organization_id, created_by, created_at, updated_at
+- **sections** — id, project_id, parent_section_id, slug, title, section_type, sort_order, status, content, summary, tags[], notes, word_count (generated), updated_by, created_at, updated_at. UNIQUE(project_id, slug), UNIQUE(project_id, id)
+- **section_revisions** — id, section_id, revision_number, content, summary, change_description, created_by, created_at. UNIQUE(section_id, revision_number)
- **section_dependencies** — id, project_id, section_id, depends_on_id, dependency_type, description. Composite FKs enforce same-project. UNIQUE(section_id, depends_on_id)
-- **section_comments** — id, section_id, anchor_text, anchor_prefix, anchor_suffix, body, resolved, created_at, updated_at. Text anchoring uses prefix/suffix context (~40 chars each) for disambiguation.
-- **comment_replies** — id, comment_id (FK section_comments), author ('user'|'claude' CHECK), body, created_at. Threaded replies on comments.
-- **project_settings** — project_id (PK, FK projects), settings (JSONB, merged with defaults at read time), updated_at. Auto-trigger on update.
-- **token_estimates** — id, project_id (FK projects), operation, full_doc_tokens, loaded_tokens, created_at. Tracks context savings per read operation.
-- **project_chats** — id, project_id (unique FK projects), created_at, updated_at. One chat thread per project.
-- **chat_messages** — id, chat_id (FK project_chats), role ('user'|'assistant'|'system'|'tool' CHECK), content, metadata (JSONB), created_at.
+- **section_comments** — id, section_id, anchor_text, anchor_prefix, anchor_suffix, body, resolved, created_by, created_at, updated_at
+- **comment_replies** — id, comment_id (FK section_comments), author ('user'|'claude' CHECK), body, created_at
+- **project_settings** — project_id (PK, FK projects), settings (JSONB, merged with defaults at read time), updated_at
+- **token_estimates** — id, project_id (FK projects), operation, full_doc_tokens, loaded_tokens, created_at
+- **project_chats** — id, project_id, chat_type ('main'|section), section_id, created_by, created_at, updated_at. Multi-thread support.
+- **chat_messages** — id, chat_id (FK project_chats), role, content, metadata (JSONB), created_by, created_at
+- **mcp_activity** — id, project_id, tool_name, detail (JSONB), user_id, created_at. 12 mutating tools.
+- **project_members** — id, project_id, user_id, role (owner/admin/editor/commenter/viewer), created_at, updated_at
+- **audit_events** — id, project_id, user_id, action, resource, detail (JSONB), created_at
+- **password_reset_tokens** — id, user_id, token, expires_at, used, created_by, created_at
+- **prdforge_bootstrap** — id, setup_type (unique), completed, created_at
+- Better Auth tables: user, session, account, verification, organization, member, invitation (managed by Prisma)
- **section_tree** (view) — sections + project_slug, parent_slug, parent_title, revision_count, dep_out_count, dep_in_count
- **project_changelog** (view) — revisions joined with section and project slugs
@@ -112,8 +125,8 @@ Three Docker Compose services:
3. Update `db/02_seed.sql` if the seed data format changed
4. Update AGENTS.md schema reference
-**Adding a UI endpoint:**
-1. Add the route to `ui/app.py`
+**Adding an API endpoint:**
+1. Add the route to `api/app.py`
2. Query the pool directly
3. Add a test in `test_ui_api.py`
@@ -158,20 +171,13 @@ python -m venv .venv && .venv/bin/pip install -r tests/requirements.txt
- **Chat is experimental** — disabled by default, gated behind `chat_enabled` project setting. All 4 chat endpoints return 403 when disabled. Enable in Settings → Experimental Features.
- **Chat model selector** — `chat_model` setting (`sonnet`/`opus`/`haiku`) per-project, stored in `project_settings` JSONB. Passed to CLI as `--model` flag. For API provider, mapped via `API_MODEL_MAP` dict.
- **Section status editor** — `PATCH /api/projects/{slug}/sections/{section}` supports updating status, tags, title, summary. Valid statuses: `draft`, `in_progress`, `review`, `approved`, `outdated`.
-- Web UI Claude chat supports two auth methods: Claude CLI OAuth login (credentials file) or Anthropic API key
+- Web UI Claude chat uses Anthropic API key for authentication
- Chat tool execution uses an allowlist of MCP tool functions with project slug enforced server-side
- Web UI chat can attach selected section text as context; backend stores this in `chat_messages.metadata.selection_context` and rehydrates it into future model history turns
- Web UI chat can attach local files (text payloads); backend stores them in `chat_messages.metadata.attachments` and injects their content into future model history turns
-- Web UI chat provider defaults to `CHAT_PROVIDER` (`claude_cli` or `anthropic_api`) and can be overridden per project via settings (`chat_provider`). In Docker CLI mode, UI container needs `claude` binary plus mounted auth dir (`${HOME}/.claude` → `/root/.claude`)
+- Web UI chat provider can be overridden per project via settings (`chat_provider`)
- Web UI chat renders selected context inline inside user message bubbles and triggers best-effort live refresh of project/section views after each completed assistant turn
- Chat attachment limits are controlled via env vars: `CHAT_MAX_ATTACHMENTS`, `CHAT_ATTACHMENT_MAX_BYTES`, `CHAT_ATTACHMENT_MAX_CHARS`, `CHAT_ATTACHMENTS_MAX_TOTAL_CHARS`
-- **Claude CLI auth in Docker:** The CLI reads credentials from `/root/.claude/.credentials.json` (written by the OAuth login flow). Do NOT pass `ANTHROPIC_AUTH_TOKEN` as env var to the CLI subprocess — it causes 401 "OAuth authentication is currently not supported" because the CLI tries to use the token as a Bearer header against the Messages API, which rejects OAuth tokens. The credentials file approach works because the CLI uses its own internal auth flow.
-- **OAuth token format:** The callback page returns `AUTH_CODE#STATE` — split on `#` to get the code and state separately.
-- **OAuth tokens vs API keys:** OAuth tokens (`sk-ant-oat01-*`) do NOT work with the Anthropic Messages API. They only work through the Claude CLI which routes via a different backend. For direct API calls, a real API key (`sk-ant-api03-*`) is required.
-- **CLI default model:** The CLI's built-in default model may be deprecated. Always pass `--model sonnet` (or user-selected model) explicitly. Never rely on the CLI default.
-- **CLI `--allowedTools` required:** In non-interactive mode (`-p` flag), the CLI cannot prompt for tool approval. MCP tools will silently fail unless `--allowedTools` is passed with the explicit list of allowed tool names.
-- In `claude_cli` mode with manual permission settings (e.g. `acceptEdits`), permission requests are surfaced as dedicated `approval` chat events and persisted in `chat_messages.metadata.approval_requests`
-- Approval cards in Web UI chat support **Approve and continue** via `/api/projects/{slug}/chat/approve`, which replays the blocked user turn with `CLAUDE_CLI_APPROVAL_PERMISSION_MODE` (default `acceptEdits`; legacy `dontAsk` is normalized), passes a strict PRD-tool allowlist to Claude CLI, and marks the original approval message as resolved in metadata
- `GET /api/projects/{slug}` now backfills missing initial revisions for sections; if a project has chat activity and zero dependencies, it backfills a linear references chain so Dependencies/Changelog tabs are populated for chat-generated projects
- `GET /api/projects/{slug}/token-stats` now includes `project_stats` (`sections`, `dependencies`, `revisions`) in addition to token-savings metrics
- `install.sh` now auto-selects a free host PostgreSQL port (`5432`, else first free in `5433-5500`) and exports `POSTGRES_PORT` so Docker + Claude Desktop config stay in sync
diff --git a/README.md b/README.md
index 004dca1..eb58370 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,14 @@
# PRD Forge
-
-
**Stop feeding your entire spec to Claude every time you change one paragraph.**
+
+
PRD Forge splits your product requirements into independently addressable sections stored in PostgreSQL, then gives Claude surgical read/write access through 31 MCP tools. The result: edits that used to burn ~15,000 tokens now cost 500-2,000 — an **85-95% reduction** in context per operation.
## The Problem
-Every AI-assisted PRD workflow today has the same bottleneck: Claude needs the full document loaded into context to make a single edit. A 20-page spec means ~15K tokens of context consumed on every interaction — even if you're only changing one section. That context cost adds up fast, limits how much Claude can reason about, and makes large specs unwieldy.
+Every AI-assisted PRD workflow today has the same bottleneck: Claude needs the full document loaded into context to make a single edit. A 20-page spec means ~15K tokens of context consumed on every interaction — even if you're only changing one section.
## How PRD Forge Solves It
@@ -20,16 +20,20 @@ Each section stores both its full **content** and a short **summary** (1-3 sente
**Real example:** Reading `data-model` (820 words, ~1,200 tokens) loads summaries of `tech-stack` (~60 tokens) and `pipeline` (~60 tokens). Total: **~1,320 tokens** instead of ~15,000.
-Claude always has enough context to make informed edits without paying for the entire document.
-
-## What You Get
-
-- **31 MCP tools** — read, write, search, import/export, manage dependencies, track revisions, resolve comments. Claude operates on your spec like a database, not a blob of text.
-- **Dependency-aware context** — sections know what they depend on. When Claude reads one, it automatically gets summaries of upstream sections for context.
-- **Full revision history** — every content change creates a revision. Roll back any section to any point. No content is ever lost.
-- **Google Docs-style comments** — leave inline comments anchored to specific text, Claude reads them, implements changes, resolves them. Threaded replies included.
-- **Web UI** — browse specs, leave comments, create new projects, view dependency graph, toggle dark/light theme. Experimental: always-visible project Claude chat with selection context, file attachments, and model selector.
-- **One command to install** — `./install.sh` handles Docker, MCP config, and validation in ~15 seconds.
+## Features
+
+- **31 MCP tools** — read, write, search, import/export, manage dependencies, track revisions, resolve comments
+- **Multi-user auth** — Better Auth (email/password + Google OAuth), 5 roles (owner/admin/editor/commenter/viewer), org-scoped access control
+- **Real-time collaboration** — WebSocket presence, live section updates across clients
+- **Project templates** — start with Blank, SaaS MVP, Mobile App, or API Design — pre-built section structures with starter content
+- **Dependency-aware context** — sections know what they depend on; Claude automatically gets upstream summaries
+- **Full revision history** — every content change creates a revision, roll back to any point
+- **Google Docs-style comments** — inline comments anchored to specific text, threaded replies
+- **AI chat** — streaming chat panel with Claude (Anthropic API or CLI), tool-calling into your PRD
+- **Dependency graph** — interactive SVG visualization of section relationships
+- **Token stats** — dashboard showing per-section token usage
+- **Next.js frontend** — React 19, Tailwind v4, shadcn/ui, dark/light theme
+- **One command install** — `./install.sh` handles Docker, MCP config, validation
## Architecture
@@ -37,14 +41,21 @@ Claude always has enough context to make informed edits without paying for the e
graph LR
A[Claude.ai / Claude Code / Claude Desktop] <-->|MCP Protocol| B[MCP Server
FastMCP/Python
:8080]
B <-->|asyncpg| C[(PostgreSQL 16
sections, revisions
dependencies, comments)]
- D[Web UI
FastAPI
:8088] <-->|read + comments + chat memory| C
+ D[Python API
FastAPI
:8088] <-->|read + write + chat| C
+ E[Frontend
Next.js 15
:3000] <-->|REST proxy| D
+ F[Redis 7] <-->|pub/sub, jti| D
A -.->|reads comments| D
```
-Three Docker services, all localhost-only:
-- **PostgreSQL 16** — source of truth (10 tables, 2 views)
-- **MCP Server** — 31 tools for Claude integration (stdio + HTTP transports)
-- **Web UI** — browser interface with project switching/creation, inline comments, dependency graph, dark/light theme. Experimental chat with model selector and MCP tool access
+Five Docker services:
+
+| Service | Stack | Port | Purpose |
+|---------|-------|------|---------|
+| **PostgreSQL 16** | 15+ tables, 2 views | 5432 | Source of truth |
+| **MCP Server** | FastMCP / Python | 8080 | 31 tools for Claude |
+| **Python API** | FastAPI | 8088 | REST backend (projects, sections, chat, auth, audit) |
+| **Frontend** | Next.js 15, React 19, Tailwind v4, shadcn/ui, Better Auth | 3000 | Web UI |
+| **Redis 7** | — | 6379 | WebSocket token uniqueness, real-time pub/sub |
## Quick Start
@@ -55,7 +66,7 @@ cd PRDforge
This single command:
1. Pulls pre-built images from ghcr.io (or builds locally if unavailable)
-2. Starts Docker services (PostgreSQL, MCP server, Web UI)
+2. Starts Docker services (PostgreSQL, MCP server, API, Frontend, Redis)
3. Configures your Claude client (Code or Desktop)
4. Validates everything works
@@ -68,17 +79,15 @@ This single command:
POSTGRES_PORT=5433 ./install.sh # Override host PostgreSQL port
```
-If `5432` is already in use, `install.sh` automatically picks the first free port in `5433-5500` and configures it for Docker + Claude Desktop.
+If `5432` is already in use, `install.sh` automatically picks the first free port in `5433-5500`.
-For Claude Desktop setup, `install.sh` now auto-selects a compatible Python interpreter (`3.10-3.13`) for `mcp_server/.venv` and recreates that venv if it was previously created with an unsupported Python (for example, `3.14`).
+The stack starts in ~15 seconds. PostgreSQL seeds a sample "SnapHabit" project (12 sections, 12 dependencies) on first boot.
-The stack starts in ~15 seconds. Chat is disabled by default — enable it per-project in **Settings → Experimental Features**. PostgreSQL seeds a sample "SnapHabit" project (12 sections, 12 dependencies) on first boot — a mobile habit-tracking app with AWS serverless backend. Edit or delete the seed data to start your own PRD.
+After install, restart your Claude client. Web UI: http://localhost:3000
-After install, restart your Claude client. Web UI: http://localhost:8088
+## Configuration
-## MCP Configuration (Manual)
-
-If you prefer to configure manually instead of using `install.sh`:
+### MCP Configuration (Manual)
Claude Code (HTTP — recommended with Docker)
@@ -126,7 +135,6 @@ Start services: `docker compose up -d`
4. Restart Claude Desktop (Cmd+Q, reopen)
> **Note:** Claude Desktop does not support HTTP transport. Use stdio (spawns server as subprocess).
-> If PostgreSQL is published on a non-default host port, replace `5432` in `DATABASE_URL` with your chosen port.
@@ -144,7 +152,18 @@ Start services: `docker compose up -d`
```
-## Tool Reference
+### Chat Configuration
+
+Chat is an experimental feature, disabled by default. Enable per-project in **Settings → Experimental Features**.
+
+| Variable | Default | Description |
+|----------|---------|-------------|
+| `ANTHROPIC_API_KEY` | — | Anthropic API key for chat |
+| `ANTHROPIC_MODEL` | `claude-haiku-4-5-20251001` | Model for chat responses |
+| `CHAT_MAX_ATTACHMENTS` | `5` | Max files per chat turn |
+| `CHAT_ATTACHMENT_MAX_BYTES` | `200000` | Max size per file payload |
+
+## MCP Tools Reference
31 MCP tools across 10 groups: project management, section CRUD, dependencies, comments, context/search, revisions, import/export, batch operations, token stats, and settings.
@@ -154,58 +173,65 @@ See **[docs/tool-reference.md](docs/tool-reference.md)** for the full tool table
Google Docs-style comments anchored to specific text in any section:
-1. **In the UI** — select text in a section → click "+ Comment" → write your note → Save
-2. **Via MCP** — `prd_add_comment(project, section, anchor_text, body)` with optional `anchor_prefix`/`anchor_suffix` for disambiguation
-3. **Claude scans comments** — `prd_list_comments` returns all open comments with section pointers (~100 tokens), then read only the sections that have feedback
-4. **Claude reads comments** — `prd_read_section` includes all comments with their anchor text and body
-5. **Resolve after implementing** — use `prd_resolve_comment` or click "Resolve" in the UI
-
-Workflow: leave comments → ask Claude to check feedback → Claude calls `prd_list_comments` to see which sections have comments → reads only those sections → implements changes → resolves comments.
-
-## Web UI Claude Chat (Experimental)
+1. **In the UI** — select text → click "+ Comment" → write your note → Save
+2. **Via MCP** — `prd_add_comment(project, section, anchor_text, body)`
+3. **Claude scans comments** — `prd_list_comments` returns all open comments
+4. **Resolve after implementing** — `prd_resolve_comment` or click "Resolve" in the UI
-Chat is an **experimental feature**, disabled by default. Enable it per-project in **Settings → Experimental Features → Chat Integration**.
+## Development
-### Authentication
+```bash
+# Run backend tests (requires postgres running)
+docker compose up -d postgres
+pip install -r tests/requirements.txt
+pytest tests/ -x -v
-Chat requires an Anthropic API key. Paste your `sk-ant-api03-...` key in **Settings → Experimental Features → Anthropic API Key** and set provider to "Anthropic API".
+# Frontend type checking and lint
+cd frontend && yarn typecheck && yarn lint && yarn test --run
-### Features
+# Smoke tests (requires full stack)
+docker compose up -d
+pytest tests/test_smoke.py -v
-- One persistent thread per project, stored in PostgreSQL (`project_chats`, `chat_messages`)
-- Streaming responses in the browser (`text/event-stream`)
-- **Model selector** — choose between Sonnet 4.6, Opus 4.6, and Haiku 4.5 per-project
-- **Selection context** — highlight text in a section and your next chat message includes that exact snippet
-- **File attachments** in chat composer (name/type/size + text content)
-- After each assistant turn, the UI live-refreshes project/section data to reflect agent-applied updates
-- Chat has access to PRDforge MCP tools — it can read, search, and edit your PRD sections directly
-- In Claude CLI mode, approval-required tool requests are shown inline with an **Approve and continue** action
-- Default provider uses local `claude` command in the UI container (`CHAT_PROVIDER=claude_cli`)
-- API-key fallback available (`CHAT_PROVIDER=anthropic_api` + `ANTHROPIC_API_KEY`)
-- Provider and model can be overridden per project in **Settings → Experimental Features**
+# Record demo video
+pip install -r scripts/requirements.txt
+playwright install chromium
+python scripts/record_demo.py
+```
-### Chat Env Variables
+**Project structure:**
+```
+PRDforge/
+├── docker-compose.yml
+├── frontend/ # Next.js 15 app (React 19, Tailwind v4, shadcn/ui)
+├── api/ # FastAPI backend (REST, chat, auth, WebSocket)
+├── mcp_server/ # FastMCP server (31 tools, stdio + HTTP)
+├── shared/ # Shared Python modules (settings, constants, templates)
+├── db/ # PostgreSQL schema migrations (13 files)
+├── tests/ # pytest test suite
+├── scripts/ # Demo recording, utilities
+└── docs/ # Tool reference, data model, scaling guide
+```
-- `CHAT_PROVIDER=claude_cli` — run chat via terminal command `claude` (default)
-- `CHAT_PROVIDER=anthropic_api` — use direct Anthropic API (`ANTHROPIC_API_KEY` required)
-- `CLAUDE_CLI_PATH` — command path override (default `claude`)
-- `CLAUDE_CLI_MODEL` — default model (default `sonnet`; overridden by per-project setting)
-- `CLAUDE_CLI_APPROVAL_PERMISSION_MODE` — permission mode for **Approve and continue** (default `acceptEdits`)
-- `CLAUDE_CLI_ARGS` — optional extra CLI args
-- `CHAT_MAX_ATTACHMENTS` — max files per chat turn (default `5`)
-- `CHAT_ATTACHMENT_MAX_BYTES` — max size per file payload (default `200000`)
-- `CHAT_ATTACHMENT_MAX_CHARS` — max extracted text per file (default `12000`)
-- `CHAT_ATTACHMENTS_MAX_TOTAL_CHARS` — max combined attachment text per turn (default `40000`)
+## Security & Deployment
-## Data Model & Reference
+PRD Forge ships with **Better Auth** (email/password + Google OAuth) and role-based access control. Sign-up is closed after the first user is created — new users are invited via organization member management.
-10 tables, 2 views. See **[docs/data-model.md](docs/data-model.md)** for the full ER diagram, dependency types, tags, statuses, and the SnapHabit example dependency graph.
+**Localhost-only by default:**
+- All ports bound to `127.0.0.1` — not accessible from LAN
+- No TLS — acceptable only for localhost
+- Database credentials are defaults (`prdforge`/`prdforge`)
-## Seed Data
+**For production deployment:**
+- Put behind a reverse proxy with TLS (nginx, Caddy, Traefik)
+- Change database credentials in `.env`
+- Set `BETTER_AUTH_SECRET` to a strong random value
+- See [docs/scaling.md](docs/scaling.md) for detailed guidance
+- **Do NOT** bind ports to `0.0.0.0` or expose via tunnels without auth
-The default seed (`db/02_seed.sql`) creates a "SnapHabit" project — a mobile habit-tracking app with AWS serverless backend. It has 12 sections (overview, user research, tech stack, data model, API spec, mobile app, push notifications, auth, deployment, analytics, testing strategy, timeline) and 12 dependencies.
+## Data Model
-Edit or delete these to start your own PRD. To start fresh, simply clear the seed and add your own sections.
+15+ tables, 2 views. See **[docs/data-model.md](docs/data-model.md)** for the full ER diagram, dependency types, tags, statuses, and the SnapHabit example.
## Backup & Restore
@@ -217,87 +243,7 @@ curl http://localhost:8088/api/projects/snaphabit/export > backup.md
docker exec prdforge-postgres-1 pg_dump -U prdforge prdforge > backup.sql
# Full reset (destroys all data)
-docker compose down -v
-docker compose up -d
-```
-
-## Security Notes
-
-> **WARNING: PRD Forge is a single-user local-only tool.** It has no authentication, no authorization, and no rate limiting. It is NOT suitable for team use, shared access, or deployment on a network.
-
-- All ports bound to `127.0.0.1` — not accessible from LAN by default
-- **Do NOT** bind ports to `0.0.0.0`, expose them via tunnels (ngrok, Cloudflare Tunnel), or open firewall rules. Anyone with network access to port 8080 gets full read/write access to all your data with zero authentication.
-- Database credentials are defaults (`prdforge`/`prdforge`) — acceptable only for localhost
-- If you must expose PRD Forge beyond localhost, put it behind a reverse proxy with TLS and authentication. See [docs/scaling.md](docs/scaling.md) for guidance.
-
-## Known Limitations
-
-- No latency/error-rate metrics beyond structured logging, `/health`, and `prd_token_stats`
-- No reverse proxy hardening — localhost-only binding prevents accidental exposure
-
-## Development
-
-```bash
-# Run unit tests (requires postgres running)
-docker compose up -d postgres
-pip install -r tests/requirements.txt
-pytest tests/test_mcp_tools.py tests/test_ui_api.py -v
-
-# Smoke tests (requires full stack)
-docker compose up -d
-pip install httpx pytest
-pytest tests/test_smoke.py -v
-```
-
-**Project structure:**
-```
-PRDforge/
-├── docker-compose.yml
-├── docker-compose.prod.yml
-├── .env.example
-├── .gitignore
-├── .github/workflows/build-and-push.yml
-├── claude_mcp_config.json
-├── README.md
-├── AGENTS.md
-├── prd.md
-├── docs/
-│ ├── tool-reference.md
-│ ├── data-model.md
-│ └── scaling.md
-├── db/
-│ ├── 01_init.sql
-│ ├── 02_seed.sql
-│ ├── 03_comments.sql
-│ ├── 04_replies_and_settings.sql
-│ ├── 05_token_stats.sql
-│ └── 06_chat.sql
-├── shared/
-│ ├── __init__.py
-│ └── settings.py
-├── mcp_server/
-│ ├── Dockerfile
-│ ├── requirements.txt
-│ └── server.py
-├── ui/
-│ ├── Dockerfile
-│ ├── requirements.txt
-│ ├── app.py
-│ └── static/
-│ ├── marked.min.js
-│ ├── highlight.min.js
-│ ├── github-dark.min.css
-│ ├── fonts.css
-│ ├── fonts/
-│ │ ├── inter-*.woff2
-│ │ └── jetbrains-mono-*.woff2
-│ └── MARKED_VERSION
-└── tests/
- ├── requirements.txt
- ├── conftest.py
- ├── test_mcp_tools.py
- ├── test_ui_api.py
- └── test_smoke.py
+docker compose down -v && docker compose up -d
```
## License
diff --git a/TODO.md b/TODO.md
index 5ee5ba4..c0983a6 100644
--- a/TODO.md
+++ b/TODO.md
@@ -2,43 +2,42 @@
## High Impact, Moderate Effort – Do Next
-- [x] Demo GIF/video in README — Playwright-based recording script (`scripts/record_demo.py`), GIF above the fold
-- [ ] Token savings dashboard in Web UI — chart showing cumulative tokens saved over time, savings per section read, comparison bar ("full doc: 15,000 tokens vs loaded: 1,320 tokens"). Proof-of-value screen users will screenshot and share
-- [ ] `prd_import_url` tool — fetch a Google Doc, Notion page, or raw URL and import as sections. Support public Google Docs and raw GitHub markdown files to reduce onboarding friction
-- [ ] Section templates — offer project templates beyond blank/SnapHabit: "SaaS MVP", "API Design", "Mobile App", "Infrastructure Migration". Each is a seed SQL or importable markdown showcasing different dependency patterns
-- [ ] move to github projects
-- [ ] add playwrite preview autoupdate (ci for pr + agents.md for agents instaction which sections observe)
+- [ ] Agent personas for chat — per-project `system_prompt` in settings + per-section `agent_prompt` override. Ship 5-6 presets (PRD Architect, Technical Reviewer, UX/Design, QA Strategist, Executive Summary). Users pick preset or write custom. Passed as system message to the chat provider. Section-level prompt overrides project-level when chatting in that section context.
+- [ ] Section templates — offer project templates beyond blank/SnapHabit: "SaaS MVP", "API Design", "Mobile App", "Infrastructure Migration". Each is a seed SQL or importable markdown showcasing different dependency patterns.
+- [ ] add notes (accordion) to section. Here, I would like the option to add a note to the entire section.
+- [ ] We need to update the readme relative to all our recent changes, create a preview as we did through the playwrite, and make it as commercially product-successful as possible to attract potential users' attention.
## Medium Impact, Lower Effort – Quick Wins
-- [ ] Health check in docker-compose — add `healthcheck` directives for MCP server and UI containers (UI already has `/health`). Fixes startup ordering, makes `docker compose up` more reliable
- [ ] CONTRIBUTING.md — how to run tests locally, code style expectations, PR process
- [ ] GitHub repo metadata — description, topics/tags (`mcp`, `claude`, `prd`, `product-requirements`, `ai-tools`, `developer-tools`, `mcp-server`), website URL
-- [ ] Multi-arch Docker builds — add `linux/amd64,linux/arm64` to GH Actions build for Apple Silicon support
- [ ] `prd_diff_sections` tool — unified diff between two revisions of a section, avoids loading both and diffing manually
-- [ ] ui playwrite tests
+- [ ] ui playwrite tests
+- [ ] add playwrite preview autoupdate (ci for pr + agents.md for agents instaction which sections observe)
## Medium Impact, Higher Effort – Plan For These
- [ ] Webhooks / notifications — POST to a configured URL on section update for Slack/Discord/pipeline integration
- [ ] Export to Google Docs / Notion — push assembled PRD back to where stakeholders read it (Notion API is more reasonable than Google Docs)
-- [ ] Section-level permissions / locking — advisory lock with timestamp and owner field so two Claude sessions don't clobber each other
- [ ] Embeddings-based dependency suggestions — store embeddings in pgvector, compute cosine similarity to catch semantic relationships that FTS keyword overlap misses
- [ ] Version tagging / snapshots — `prd_tag_version` tool that snapshots all current section revision numbers under a named tag for milestone tracking
+- [ ] Google OAuth provider — Better Auth config ready, needs Google Cloud Console credentials
## Lower Priority – Worth Tracking
-- [ ] Conflict detection — optimistic concurrency with revision check on write (warn/fail if section was edited since last read)
+- [ ] `prd_import_url` tool — fetch public Google Docs, GitHub markdown, or raw URLs and import as sections. Private docs deferred (each provider needs its own OAuth — not worth the complexity for an import tool). Public-only version is ~2h of work.
- [ ] Section ordering visualization — Gantt-style view based on `blocks` dependency type for timeline sections
- [ ] Prometheus `/metrics` endpoint — request counts, latency histograms, DB connection pool stats
- [ ] claude.ai MCP marketplace listing — be ready when Anthropic opens MCP server discovery
- [ ] Replace heuristic markdown import parser with `markdown-it-py` AST parser
-- [ ] Add WebSocket push to UI for real-time updates when sections change
- [ ] Support `### ` (h3) splitting in import for nested section hierarchies
- [ ] Add `prd_merge_sections` tool (combine two sections into one)
- [ ] Add `prd_reorder_sections` tool (bulk sort_order update)
- [ ] Export as PDF via headless browser
- [ ] UI: keyboard navigation (j/k to move through sections, Enter to select)
+- [ ] MCP auth for remote Claude clients (SSH tunnel or authenticated ingress)
+- [ ] Redis jti uniqueness for WS tokens (SET NX EX — currently TODO in code)
+- [ ] move to tasks github projects
## Done
@@ -68,3 +67,24 @@
- [x] Google Fonts vendored locally (Inter, JetBrains Mono in ui/static/fonts/)
- [x] Light theme / dark-light toggle in UI nav rail
- [x] Docker build pipeline (GitHub Actions → ghcr.io) + `docker-compose.prod.yml` + install.sh pull support
+- [x] Token savings dashboard — Grafana-style with recharts, area/bar/pie/gauge, session-based honest savings math, section heatmap
+- [x] Health checks in docker-compose — all services (postgres, mcp-server, redis) have healthchecks with depends_on conditions
+- [x] Multi-arch Docker builds — `linux/amd64,linux/arm64` in GH Actions
+- [x] Multi-user auth — Better Auth (email/password), closed sign-up, first-user bootstrap
+- [x] RBAC — project_members with 5 roles (owner/admin/editor/commenter/viewer), permission middleware
+- [x] Next.js frontend — React 19, Tailwind v4, shadcn/ui, replaces server-rendered HTML
+- [x] Real-time WebSocket — presence tracking, event broadcasting via Redis pub/sub
+- [x] Optimistic locking — expected_revision on section PATCH, 409 Conflict with details
+- [x] MCP activity tracking — 12 mutating tools logged to mcp_activity table
+- [x] Chat with streaming — SSE, tool calls display, selection context, file attachments, stop button
+- [x] Audit events table — project + user indexed
+- [x] Password reset flow — admin-generated tokens, no email
+- [x] Member management — add/remove/change role via API + UI
+- [x] Dependency graph — dual view (force-directed SVG graph + list with type badges), click popup, drag nodes, curved colored arrows
+- [x] Structured error handling — 9 error codes, frontend error boundaries
+- [x] Comments — text selection anchoring, resolve/reopen toggle, edit/delete, existing comment detection
+- [x] Section status management — clickable dropdown to change status
+- [x] Multi-user chat threads — per-project + per-section, chat_type column
+- [x] Org-level encrypted API key — Fernet/AES-256
+- [x] Wider chat section — 40% viewport width, min 480px, max 700px
+- [x] Honest token savings math — section_access_log with session-based dedup, coverage fractions (full/summary/snippet), 30-min session windowing
diff --git a/ui/Dockerfile b/api/Dockerfile
similarity index 62%
rename from ui/Dockerfile
rename to api/Dockerfile
index 621698b..838e400 100644
--- a/ui/Dockerfile
+++ b/api/Dockerfile
@@ -5,11 +5,12 @@ RUN apt-get update \
&& npm install -g @anthropic-ai/claude-code \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
-COPY ui/requirements.txt /app/ui/
-RUN pip install --no-cache-dir -r /app/ui/requirements.txt
+COPY api/requirements.txt /app/api/
+RUN pip install --no-cache-dir -r /app/api/requirements.txt
COPY shared/ /app/shared/
COPY mcp_server/ /app/mcp_server/
-COPY ui/app.py /app/ui/
-COPY ui/static/ /app/ui/static/
-WORKDIR /app/ui
+COPY api/app.py api/auth.py api/errors.py api/ws.py /app/api/
+COPY api/auth_contract.py /app/api/
+COPY api/static/ /app/api/static/
+WORKDIR /app/api
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8088"]
diff --git a/ui/app.py b/api/app.py
similarity index 73%
rename from ui/app.py
rename to api/app.py
index 3bf45c5..40ddb16 100644
--- a/ui/app.py
+++ b/api/app.py
@@ -17,13 +17,14 @@
import asyncpg
import httpx
-from fastapi import FastAPI, Request
-from fastapi.responses import HTMLResponse, JSONResponse, PlainTextResponse, StreamingResponse
-from fastapi.staticfiles import StaticFiles
+from fastapi import FastAPI, Request, WebSocket, WebSocketDisconnect
+from fastapi.responses import JSONResponse, PlainTextResponse, StreamingResponse
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "mcp_server"))
from shared.settings import CHAT_PROVIDER_VALUES, DEFAULT_PROJECT_SETTINGS, validate_settings
+from shared.project_factory import create_project_with_template
+from shared.templates import list_templates
pool: asyncpg.Pool | None = None
logger = logging.getLogger("prd_forge_ui")
@@ -73,17 +74,31 @@ def _valid_project_slug(slug: str) -> bool:
return bool(slug and len(slug) <= 100 and PROJECT_SLUG_RE.match(slug))
+redis_client = None
+
+
@asynccontextmanager
async def lifespan(app: FastAPI):
- global pool
+ global pool, redis_client
pool = await asyncpg.create_pool(os.environ["DATABASE_URL"])
+ redis_url = os.environ.get("REDIS_URL", "")
+ if redis_url:
+ try:
+ import redis.asyncio as aioredis
+ redis_client = aioredis.from_url(redis_url, decode_responses=True)
+ await redis_client.ping()
+ logger.info("Redis connected: %s", redis_url)
+ except Exception as e:
+ logger.warning("Redis not available (real-time features disabled): %s", e)
+ redis_client = None
yield
+ if redis_client:
+ await redis_client.aclose()
if pool:
await pool.close()
-app = FastAPI(title="PRD Forge UI", lifespan=lifespan)
-app.mount("/static", StaticFiles(directory=os.path.join(os.path.dirname(__file__), "static")), name="static")
+app = FastAPI(title="PRD Forge API", lifespan=lifespan)
def dt(v):
@@ -108,9 +123,6 @@ def row_dict(r):
return d
-_static_dir = os.path.join(os.path.dirname(__file__), "static")
-with open(os.path.join(_static_dir, "index.html")) as _f:
- HTML = _f.read()
CHAT_ALLOWED_MCP_TOOLS: dict[str, dict[str, Any]] = {
@@ -228,6 +240,237 @@ def row_dict(r):
},
"arg_names": ["section", "comment_id", "body"],
},
+ "prd_add_comment": {
+ "description": "Add inline comment anchored to text in a section.",
+ "input_schema": {
+ "type": "object",
+ "properties": {
+ "section": {"type": "string"},
+ "anchor_text": {"type": "string"},
+ "body": {"type": "string"},
+ "anchor_prefix": {"type": "string"},
+ "anchor_suffix": {"type": "string"},
+ },
+ "required": ["section", "anchor_text", "body"],
+ "additionalProperties": False,
+ },
+ "arg_names": ["section", "anchor_text", "body", "anchor_prefix", "anchor_suffix"],
+ },
+ "prd_delete_comment": {
+ "description": "Delete an inline comment.",
+ "input_schema": {
+ "type": "object",
+ "properties": {
+ "section": {"type": "string"},
+ "comment_id": {"type": "string"},
+ },
+ "required": ["section", "comment_id"],
+ "additionalProperties": False,
+ },
+ "arg_names": ["section", "comment_id"],
+ },
+ "prd_create_section": {
+ "description": "Create a new section in the project.",
+ "input_schema": {
+ "type": "object",
+ "properties": {
+ "slug": {"type": "string"},
+ "title": {"type": "string"},
+ "section_type": {"type": "string"},
+ "content": {"type": "string"},
+ "summary": {"type": "string"},
+ "tags": {"type": "array", "items": {"type": "string"}},
+ "notes": {"type": "string"},
+ "sort_order": {"type": "integer"},
+ },
+ "required": ["slug", "title"],
+ "additionalProperties": False,
+ },
+ "arg_names": ["slug", "title", "section_type", "content", "summary", "tags", "notes", "sort_order"],
+ },
+ "prd_delete_section": {
+ "description": "Delete a section (warns about dependent sections).",
+ "input_schema": {
+ "type": "object",
+ "properties": {
+ "section": {"type": "string"},
+ },
+ "required": ["section"],
+ "additionalProperties": False,
+ },
+ "arg_names": ["section"],
+ },
+ "prd_add_dependency": {
+ "description": "Add dependency between two sections (idempotent).",
+ "input_schema": {
+ "type": "object",
+ "properties": {
+ "section": {"type": "string"},
+ "depends_on": {"type": "string"},
+ "dependency_type": {"type": "string"},
+ "description": {"type": "string"},
+ },
+ "required": ["section", "depends_on"],
+ "additionalProperties": False,
+ },
+ "arg_names": ["section", "depends_on", "dependency_type", "description"],
+ },
+ "prd_remove_dependency": {
+ "description": "Remove dependency between two sections.",
+ "input_schema": {
+ "type": "object",
+ "properties": {
+ "section": {"type": "string"},
+ "depends_on": {"type": "string"},
+ },
+ "required": ["section", "depends_on"],
+ "additionalProperties": False,
+ },
+ "arg_names": ["section", "depends_on"],
+ },
+ "prd_suggest_dependencies": {
+ "description": "Suggest dependencies for a section using content similarity.",
+ "input_schema": {
+ "type": "object",
+ "properties": {
+ "section": {"type": "string"},
+ },
+ "required": ["section"],
+ "additionalProperties": False,
+ },
+ "arg_names": ["section"],
+ },
+ "prd_get_changelog": {
+ "description": "Get recent revision history across all sections.",
+ "input_schema": {
+ "type": "object",
+ "properties": {
+ "limit": {"type": "integer"},
+ },
+ "additionalProperties": False,
+ },
+ "arg_names": ["limit"],
+ },
+ "prd_get_revisions": {
+ "description": "List revisions for a section.",
+ "input_schema": {
+ "type": "object",
+ "properties": {
+ "section": {"type": "string"},
+ },
+ "required": ["section"],
+ "additionalProperties": False,
+ },
+ "arg_names": ["section"],
+ },
+ "prd_rollback_section": {
+ "description": "Rollback section to a previous revision (saves backup first).",
+ "input_schema": {
+ "type": "object",
+ "properties": {
+ "section": {"type": "string"},
+ "revision": {"type": "integer"},
+ },
+ "required": ["section", "revision"],
+ "additionalProperties": False,
+ },
+ "arg_names": ["section", "revision"],
+ },
+ "prd_move_section": {
+ "description": "Move section (change sort order or parent).",
+ "input_schema": {
+ "type": "object",
+ "properties": {
+ "section": {"type": "string"},
+ "sort_order": {"type": "integer"},
+ "parent_section": {"type": "string"},
+ },
+ "required": ["section"],
+ "additionalProperties": False,
+ },
+ "arg_names": ["section", "sort_order", "parent_section"],
+ },
+ "prd_duplicate_section": {
+ "description": "Duplicate a section with a new slug.",
+ "input_schema": {
+ "type": "object",
+ "properties": {
+ "section": {"type": "string"},
+ "new_slug": {"type": "string"},
+ "new_title": {"type": "string"},
+ },
+ "required": ["section", "new_slug"],
+ "additionalProperties": False,
+ },
+ "arg_names": ["section", "new_slug", "new_title"],
+ },
+ "prd_bulk_status": {
+ "description": "Bulk update status for multiple sections.",
+ "input_schema": {
+ "type": "object",
+ "properties": {
+ "sections": {"type": "array", "items": {"type": "string"}},
+ "status": {"type": "string"},
+ },
+ "required": ["sections", "status"],
+ "additionalProperties": False,
+ },
+ "arg_names": ["sections", "status"],
+ },
+ "prd_export_markdown": {
+ "description": "Export entire project as markdown (large output).",
+ "input_schema": {
+ "type": "object",
+ "properties": {},
+ "additionalProperties": False,
+ },
+ "arg_names": [],
+ },
+ "prd_import_markdown": {
+ "description": "Import markdown document into the project.",
+ "input_schema": {
+ "type": "object",
+ "properties": {
+ "markdown": {"type": "string"},
+ "replace_existing": {"type": "boolean"},
+ "heading_level": {"type": "integer"},
+ "manual_delimiter": {"type": "string"},
+ },
+ "required": ["markdown"],
+ "additionalProperties": False,
+ },
+ "arg_names": ["markdown", "replace_existing", "heading_level", "manual_delimiter"],
+ },
+ "prd_token_stats": {
+ "description": "Get token savings statistics for the project.",
+ "input_schema": {
+ "type": "object",
+ "properties": {},
+ "additionalProperties": False,
+ },
+ "arg_names": [],
+ },
+ "prd_get_settings": {
+ "description": "Get project settings.",
+ "input_schema": {
+ "type": "object",
+ "properties": {},
+ "additionalProperties": False,
+ },
+ "arg_names": [],
+ },
+ "prd_update_settings": {
+ "description": "Update project settings.",
+ "input_schema": {
+ "type": "object",
+ "properties": {
+ "settings": {"type": "object"},
+ },
+ "required": ["settings"],
+ "additionalProperties": False,
+ },
+ "arg_names": ["settings"],
+ },
}
APPROVAL_ALLOWED_TOOLS = {f"mcp__prd-forge__{k}" for k in CHAT_ALLOWED_MCP_TOOLS}
@@ -860,16 +1103,27 @@ async def _resolve_project_id_or_none(slug: str):
return await pool.fetchval("SELECT id FROM projects WHERE slug = $1", slug)
-async def _get_or_create_project_chat(project_id):
+async def _get_or_create_project_chat(project_id, chat_type="main", section_id=None):
+ if section_id:
+ return await pool.fetchval(
+ """
+ INSERT INTO project_chats (project_id, chat_type, section_id)
+ VALUES ($1, $2, $3)
+ ON CONFLICT (project_id, chat_type, COALESCE(section_id, '00000000-0000-0000-0000-000000000000'))
+ DO UPDATE SET updated_at = now()
+ RETURNING id
+ """,
+ project_id, chat_type, section_id,
+ )
return await pool.fetchval(
"""
- INSERT INTO project_chats (project_id)
- VALUES ($1)
- ON CONFLICT (project_id)
+ INSERT INTO project_chats (project_id, chat_type)
+ VALUES ($1, $2)
+ ON CONFLICT (project_id, chat_type, COALESCE(section_id, '00000000-0000-0000-0000-000000000000'))
DO UPDATE SET updated_at = now()
RETURNING id
""",
- project_id,
+ project_id, chat_type,
)
@@ -1116,11 +1370,6 @@ async def _ensure_chat_generated_project_graph_data(project_id) -> None:
-@app.get("/", response_class=HTMLResponse)
-async def index():
- return HTML
-
-
@app.get("/api/projects")
async def list_projects():
rows = await pool.fetch("""
@@ -1134,8 +1383,19 @@ async def list_projects():
return [row_dict(r) for r in rows]
+@app.get("/api/templates")
+async def get_templates():
+ return list_templates()
+
+
@app.post("/api/projects")
async def create_project(request: Request):
+ from auth import require_authenticated_user
+
+ user = await require_authenticated_user(request, pool)
+ if isinstance(user, JSONResponse):
+ return user
+
try:
body = await request.json()
except Exception:
@@ -1154,22 +1414,25 @@ async def create_project(request: Request):
)
description = str(body.get("description") or "").strip()
+ template_id = str(body.get("template_id") or "").strip() or None
try:
- row = await pool.fetchrow(
- """
- INSERT INTO projects (name, slug, description)
- VALUES ($1, $2, $3)
- RETURNING id, slug, name, description, version, created_at, updated_at
- """,
+ result = await create_project_with_template(
+ pool,
name,
slug,
description,
+ template_id=template_id,
+ user_id=user.get("user_id"),
)
+ return result
+ except ValueError as e:
+ return JSONResponse({"error": str(e)}, 400)
except asyncpg.UniqueViolationError:
return JSONResponse({"error": f"project slug '{slug}' already exists"}, 409)
-
- return row_dict(row)
+ except Exception as e:
+ logger.error("create_project: %s", e)
+ return JSONResponse({"error": "internal error"}, 500)
@app.get("/api/projects/{slug}")
@@ -1307,6 +1570,27 @@ async def patch_section(slug: str, section: str, request: Request):
return JSONResponse({"error": f"section '{section}' not found"}, 404)
body = await request.json()
+
+ # Optimistic locking: if client sends expected_revision, verify it matches
+ expected_rev = body.get("expected_revision")
+ if expected_rev is not None:
+ current_rev = await pool.fetchval(
+ "SELECT COALESCE(MAX(revision_number), 0) FROM section_revisions WHERE section_id = $1",
+ sec["id"],
+ )
+ if current_rev != expected_rev:
+ return JSONResponse({
+ "error": {
+ "code": "CONFLICT",
+ "message": f"Section was updated (revision {expected_rev} → {current_rev}). Reload and retry.",
+ "status": 409,
+ "details": {
+ "current_revision": current_rev,
+ "expected_revision": expected_rev,
+ },
+ }
+ }, 409)
+
allowed = {"status", "tags", "title", "summary"}
updates = {k: v for k, v in body.items() if k in allowed and v is not None}
if not updates:
@@ -1327,11 +1611,19 @@ async def patch_section(slug: str, section: str, request: Request):
await pool.execute(
f"UPDATE sections SET {', '.join(set_parts)} WHERE id = $1", *params
)
+ await broadcast_project_event(slug, "section_updated", {"section": section, "fields": list(updates.keys())})
return {"ok": True, "updated": list(updates.keys())}
@app.post("/api/projects/{slug}/sections/{section}/notes")
async def update_notes(slug: str, section: str, request: Request):
+ from auth import require_project_access
+
+ access = await require_project_access(request, pool, slug, min_role="editor")
+ user, role = access
+ if isinstance(user, JSONResponse):
+ return user
+
body = await request.json()
notes = body.get("notes", "")
proj = await pool.fetchrow("SELECT id FROM projects WHERE slug = $1", slug)
@@ -1362,6 +1654,7 @@ async def create_comment(slug: str, section: str, request: Request):
VALUES ($1, $2, $3, $4, $5) RETURNING *
""", sec_id, body["anchor_text"], body.get("anchor_prefix", ""),
body.get("anchor_suffix", ""), body["body"])
+ await broadcast_project_event(slug, "comment_added", {"section": section, "comment_id": str(row["id"])})
return row_dict(row)
@@ -1499,56 +1792,144 @@ async def get_token_stats(slug: str):
await _backfill_missing_initial_revisions(pid)
- totals = await pool.fetchrow("""
- SELECT COUNT(*) AS operations,
- COALESCE(SUM(full_doc_tokens), 0) AS total_full,
- COALESCE(SUM(loaded_tokens), 0) AS total_loaded
- FROM token_estimates WHERE project_id = $1
+ # Full document size (current)
+ full_doc = await pool.fetchrow("""
+ SELECT COALESCE(SUM(word_count), 0) AS total_words, COUNT(*) AS section_count
+ FROM sections WHERE project_id = $1
""", pid)
+ full_doc_words = full_doc["total_words"]
+ full_doc_tokens = int(full_doc_words * 1.3)
+ # Check if new access log has data
+ has_access_log = await pool.fetchval(
+ "SELECT EXISTS(SELECT 1 FROM section_access_log WHERE project_id = $1)", pid
+ )
+
+ if has_access_log:
+ # --- Honest session-based calculation ---
+ sessions = await pool.fetch("""
+ WITH numbered AS (
+ SELECT *,
+ CASE WHEN created_at - LAG(created_at) OVER (ORDER BY created_at)
+ > interval '30 minutes'
+ OR LAG(created_at) OVER (ORDER BY created_at) IS NULL
+ THEN 1 ELSE 0 END AS new_session
+ FROM section_access_log WHERE project_id = $1
+ ),
+ sessioned AS (
+ SELECT *, SUM(new_session) OVER (ORDER BY created_at) AS session_id
+ FROM numbered
+ ),
+ session_coverage AS (
+ SELECT session_id, section_id,
+ MAX(CASE access_level
+ WHEN 'full' THEN 1.0 WHEN 'summary' THEN 0.10 WHEN 'snippet' THEN 0.15
+ END) AS coverage
+ FROM sessioned GROUP BY session_id, section_id
+ ),
+ session_stats AS (
+ SELECT sc.session_id,
+ $2::int AS full_doc_words,
+ SUM(COALESCE(s.word_count, 0) * sc.coverage)::int AS unique_loaded_words,
+ COUNT(DISTINCT sc.section_id) AS sections_touched
+ FROM session_coverage sc
+ LEFT JOIN sections s ON s.id = sc.section_id
+ GROUP BY sc.session_id
+ )
+ SELECT
+ session_id,
+ full_doc_words,
+ unique_loaded_words,
+ sections_touched,
+ CASE WHEN full_doc_words > 0
+ THEN ROUND((1.0 - unique_loaded_words::numeric / full_doc_words) * 100, 1)
+ ELSE 0 END AS savings_pct
+ FROM session_stats ORDER BY session_id
+ """, pid, full_doc_words)
+
+ total_ops = await pool.fetchval(
+ "SELECT COUNT(*) FROM section_access_log WHERE project_id = $1", pid
+ )
+ session_count = len(sessions)
+ avg_savings = round(sum(s["savings_pct"] for s in sessions) / session_count, 1) if session_count > 0 else 0
+ best_session = max((s["savings_pct"] for s in sessions), default=0)
+ avg_sections_per_session = round(sum(s["sections_touched"] for s in sessions) / session_count, 1) if session_count > 0 else 0
+ total_unique_loaded = sum(s["unique_loaded_words"] for s in sessions)
+ total_loaded_tokens = int(total_unique_loaded * 1.3)
+ total_saved_tokens = max(0, full_doc_tokens * session_count - total_loaded_tokens)
+
+ # Section heatmap — how often each section is accessed
+ heatmap = await pool.fetch("""
+ SELECT s.slug, s.title, COUNT(*) AS access_count,
+ MAX(CASE access_level WHEN 'full' THEN 1 WHEN 'summary' THEN 0 WHEN 'snippet' THEN 0 END) AS has_full_read
+ FROM section_access_log sal
+ JOIN sections s ON s.id = sal.section_id
+ WHERE sal.project_id = $1
+ GROUP BY s.slug, s.title
+ ORDER BY access_count DESC
+ """, pid)
+ else:
+ # --- Fallback to legacy token_estimates ---
+ totals = await pool.fetchrow("""
+ SELECT COUNT(*) AS operations,
+ COALESCE(SUM(full_doc_tokens), 0) AS total_full,
+ COALESCE(SUM(loaded_tokens), 0) AS total_loaded
+ FROM token_estimates WHERE project_id = $1
+ """, pid)
+ total_full_legacy = totals["total_full"]
+ total_loaded_legacy = totals["total_loaded"]
+ saved_legacy = total_full_legacy - total_loaded_legacy
+ avg_savings = round(saved_legacy / total_full_legacy * 100, 1) if total_full_legacy > 0 else 0
+ total_ops = totals["operations"]
+ session_count = 0
+ best_session = avg_savings
+ avg_sections_per_session = 0
+ total_loaded_tokens = total_loaded_legacy
+ total_saved_tokens = saved_legacy
+ heatmap = []
+
+ # By operation (from legacy table — still populated)
by_op = await pool.fetch("""
- SELECT operation,
- COUNT(*) AS count,
+ SELECT operation, COUNT(*) AS count,
SUM(full_doc_tokens) AS full_tokens,
SUM(loaded_tokens) AS loaded_tokens
FROM token_estimates WHERE project_id = $1
GROUP BY operation ORDER BY count DESC
""", pid)
+ # Daily trend
daily = await pool.fetch("""
SELECT d.day::date AS day,
COALESCE(COUNT(t.id), 0) AS operations,
COALESCE(SUM(t.full_doc_tokens - t.loaded_tokens), 0) AS tokens_saved
FROM generate_series(current_date - 6, current_date, '1 day') AS d(day)
- LEFT JOIN (
- SELECT * FROM token_estimates WHERE project_id = $1
- ) t ON t.created_at::date = d.day
+ LEFT JOIN (SELECT * FROM token_estimates WHERE project_id = $1) t
+ ON t.created_at::date = d.day
GROUP BY d.day ORDER BY d.day ASC
""", pid)
- total_full = totals["total_full"]
- total_loaded = totals["total_loaded"]
- saved = total_full - total_loaded
- pct = round(saved / total_full * 100, 1) if total_full > 0 else 0
-
- project_stats = await pool.fetchrow(
- """
+ project_stats = await pool.fetchrow("""
SELECT
(SELECT COUNT(*) FROM sections WHERE project_id = $1) AS section_count,
(SELECT COUNT(*) FROM section_dependencies WHERE project_id = $1) AS dependency_count,
(SELECT COUNT(*) FROM section_revisions r
- JOIN sections s ON s.id = r.section_id
- WHERE s.project_id = $1) AS revision_count
- """,
- pid,
- )
+ JOIN sections s ON s.id = r.section_id WHERE s.project_id = $1) AS revision_count
+ """, pid)
+
+ activity_rows = await pool.fetch("""
+ SELECT tool_name, detail, created_at FROM mcp_activity
+ WHERE project_id = $1 ORDER BY created_at DESC LIMIT 50
+ """, pid)
return {
- "operations": totals["operations"],
- "total_full_doc_tokens": total_full,
- "total_loaded_tokens": total_loaded,
- "total_saved_tokens": saved,
- "savings_percent": pct,
+ "operations": total_ops,
+ "total_full_doc_tokens": full_doc_tokens,
+ "total_loaded_tokens": total_loaded_tokens,
+ "total_saved_tokens": total_saved_tokens,
+ "savings_percent": float(avg_savings),
+ "sessions": session_count,
+ "best_session_savings": float(best_session),
+ "avg_sections_per_session": float(avg_sections_per_session),
"by_operation": [row_dict(r) for r in by_op],
"daily_trend": [{"day": str(r["day"]), "operations": r["operations"],
"tokens_saved": r["tokens_saved"]} for r in daily],
@@ -1557,6 +1938,8 @@ async def get_token_stats(slug: str):
"dependencies": project_stats["dependency_count"],
"revisions": project_stats["revision_count"],
},
+ "activity": [row_dict(r) for r in activity_rows],
+ "section_heatmap": [row_dict(r) for r in heatmap] if heatmap else [],
}
@@ -1583,21 +1966,6 @@ async def chat_provider_status():
}
-@app.put("/api/chat/api-key")
-async def set_chat_api_key(request: Request):
- """Set Anthropic API key at runtime (not persisted to disk)."""
- global _runtime_anthropic_api_key
- try:
- body = await request.json()
- except Exception:
- return JSONResponse({"error": "invalid JSON body"}, 400)
- key = str(body.get("api_key") or "").strip()
- if key and not key.startswith("sk-ant-"):
- return JSONResponse({"error": "Invalid API key format (expected sk-ant-...)"}, 400)
- _runtime_anthropic_api_key = key
- return {"ok": True, "configured": bool(key), "key_hint": f"...{key[-4:]}" if len(key) >= 4 else ""}
-
-
@app.post("/api/chat/cli-login")
async def cli_login():
"""Generate PKCE OAuth URL for Claude CLI authentication."""
@@ -2041,6 +2409,259 @@ async def export_project(slug: str):
return PlainTextResponse("\n".join(lines), media_type="text/plain")
+# --- Member management ---
+
+@app.get("/api/projects/{slug}/members")
+async def list_project_members(slug: str, request: Request):
+ """List all members of a project."""
+ from auth import require_project_access
+
+ access = await require_project_access(request, pool, slug, min_role="viewer")
+ user, role = access
+ if isinstance(user, JSONResponse):
+ return user
+
+ proj = await pool.fetchrow("SELECT id FROM projects WHERE slug = $1", slug)
+ if not proj:
+ return JSONResponse({"error": f"project '{slug}' not found"}, 404)
+ rows = await pool.fetch("""
+ SELECT pm.id, pm.user_id, pm.role, pm.created_at, pm.updated_at
+ FROM project_members pm
+ WHERE pm.project_id = $1
+ ORDER BY pm.created_at
+ """, proj["id"])
+ return [row_dict(r) for r in rows]
+
+
+@app.post("/api/projects/{slug}/members")
+async def add_project_member(slug: str, request: Request):
+ """Add a member to a project."""
+ from auth import require_project_access
+
+ access = await require_project_access(request, pool, slug, min_role="admin")
+ user, role = access
+ if isinstance(user, JSONResponse):
+ return user
+
+ proj = await pool.fetchrow("SELECT id FROM projects WHERE slug = $1", slug)
+ if not proj:
+ return JSONResponse({"error": f"project '{slug}' not found"}, 404)
+ try:
+ body = await request.json()
+ except Exception:
+ return JSONResponse({"error": "invalid JSON body"}, 400)
+ user_id = body.get("user_id")
+ role = body.get("role", "viewer")
+ if not user_id:
+ return JSONResponse({"error": "user_id is required"}, 400)
+ valid_roles = {"owner", "admin", "editor", "commenter", "viewer"}
+ if role not in valid_roles:
+ return JSONResponse({"error": f"invalid role, must be one of {sorted(valid_roles)}"}, 400)
+ try:
+ row = await pool.fetchrow("""
+ INSERT INTO project_members (project_id, user_id, role)
+ VALUES ($1, $2, $3)
+ ON CONFLICT (project_id, user_id) DO UPDATE SET role = EXCLUDED.role
+ RETURNING id, user_id, role, created_at
+ """, proj["id"], _uuid.UUID(user_id), role)
+ return row_dict(row)
+ except Exception:
+ return JSONResponse({"error": "internal error"}, 500)
+
+
+@app.delete("/api/projects/{slug}/members/{user_id}")
+async def remove_project_member(slug: str, user_id: str, request: Request):
+ """Remove a member from a project."""
+ from auth import require_project_access
+
+ access = await require_project_access(request, pool, slug, min_role="admin")
+ user, role = access
+ if isinstance(user, JSONResponse):
+ return user
+
+ proj = await pool.fetchrow("SELECT id FROM projects WHERE slug = $1", slug)
+ if not proj:
+ return JSONResponse({"error": f"project '{slug}' not found"}, 404)
+ result = await pool.execute(
+ "DELETE FROM project_members WHERE project_id = $1 AND user_id = $2",
+ proj["id"], _uuid.UUID(user_id),
+ )
+ removed = result.split()[-1] != "0"
+ return {"removed": removed}
+
+
+# --- Audit events ---
+
+@app.get("/api/projects/{slug}/audit")
+async def list_audit_events(slug: str, limit: int = 50):
+ """List recent audit events for a project."""
+ proj = await pool.fetchrow("SELECT id FROM projects WHERE slug = $1", slug)
+ if not proj:
+ return JSONResponse({"error": f"project '{slug}' not found"}, 404)
+ rows = await pool.fetch("""
+ SELECT id, user_id, action, resource, detail, created_at
+ FROM audit_events
+ WHERE project_id = $1
+ ORDER BY created_at DESC
+ LIMIT $2
+ """, proj["id"], limit)
+ return [row_dict(r) for r in rows]
+
+
+# --- WebSocket token ---
+
+@app.post("/api/ws-token")
+async def create_ws_token(request: Request):
+ """Mint a short-lived HMAC token for WebSocket authentication."""
+ from auth import require_project_access
+ from ws import mint_ws_token
+
+ try:
+ body = await request.json()
+ except Exception:
+ return JSONResponse({"error": "invalid JSON body"}, 400)
+
+ project_slug = body.get("project_slug")
+ if not project_slug:
+ return JSONResponse({"error": "project_slug required"}, 400)
+
+ # Verify project exists
+ proj = await pool.fetchrow("SELECT id FROM projects WHERE slug = $1", project_slug)
+ if not proj:
+ return JSONResponse({"error": f"project '{project_slug}' not found"}, 404)
+
+ access = await require_project_access(request, pool, project_slug, min_role="viewer")
+ user, role = access
+ if isinstance(user, JSONResponse):
+ return user
+
+ # user_id is None in pre-setup mode (anonymous), str otherwise
+ user_id = user.get("user_id") or "anonymous"
+ token = mint_ws_token(str(user_id), project_slug)
+ return {"token": token}
+
+
+# --- WebSocket handler ---
+
+# Connected clients: {project_slug: {user_id: WebSocket}}
+_ws_connections: dict[str, dict[str, WebSocket]] = {}
+_ws_redis_warned = [False] # mutable holder — warn once, no global needed
+
+
+@app.websocket("/ws/projects/{slug}")
+async def websocket_project(websocket: WebSocket, slug: str):
+ """WebSocket endpoint for real-time project updates and presence."""
+ from auth import _is_auth_enforced, get_user_project_role
+ from ws import verify_ws_token
+
+ token = websocket.query_params.get("token")
+ if not token:
+ await websocket.close(code=4001, reason="Missing token")
+ return
+
+ payload = verify_ws_token(token)
+ if not payload:
+ await websocket.close(code=4001, reason="Invalid or expired token")
+ return
+
+ if payload.get("project") != slug:
+ await websocket.close(code=4003, reason="Token project mismatch")
+ return
+
+ user_id = payload["sub"]
+ jti = payload.get("jti", "")
+
+ # jti uniqueness: Redis SET NX EX — reject replayed tokens
+ if redis_client and jti:
+ was_set = await redis_client.set(f"ws:jti:{jti}", "1", nx=True, ex=120)
+ if not was_set:
+ await websocket.close(code=4002, reason="Token already used")
+ return
+ elif not redis_client and jti:
+ if not _ws_redis_warned[0]:
+ logger.warning("Redis unavailable — WS token replay protection disabled")
+ _ws_redis_warned[0] = True
+
+ # Membership re-check: user may have been removed since token was minted
+ if await _is_auth_enforced(pool):
+ ws_role = await get_user_project_role(pool, user_id, slug)
+ if not ws_role:
+ await websocket.close(code=4003, reason="No project access")
+ return
+
+ await websocket.accept()
+
+ # Register connection
+ if slug not in _ws_connections:
+ _ws_connections[slug] = {}
+ _ws_connections[slug][user_id] = websocket
+
+ # Broadcast presence update
+ await _broadcast_presence(slug)
+
+ try:
+ while True:
+ data = await websocket.receive_text()
+ # Handle incoming messages (e.g., cursor position, typing indicator)
+ try:
+ msg = json.loads(data)
+ if msg.get("type") == "presence_update":
+ # Update user's active section and re-broadcast
+ await _broadcast_presence(slug)
+ except json.JSONDecodeError:
+ pass
+ except WebSocketDisconnect:
+ pass
+ finally:
+ # Unregister
+ if slug in _ws_connections:
+ _ws_connections[slug].pop(user_id, None)
+ if not _ws_connections[slug]:
+ del _ws_connections[slug]
+ else:
+ await _broadcast_presence(slug)
+
+
+async def _broadcast_presence(slug: str):
+ """Send presence list to all connected clients for a project."""
+ conns = _ws_connections.get(slug, {})
+ users = [{"id": uid, "name": uid} for uid in conns]
+ message = json.dumps({"type": "presence_update", "data": {"users": users}})
+ disconnected = []
+ for uid, ws in conns.items():
+ try:
+ await ws.send_text(message)
+ except Exception:
+ disconnected.append(uid)
+ for uid in disconnected:
+ conns.pop(uid, None)
+
+
+async def broadcast_project_event(slug: str, event_type: str, data: dict):
+ """Broadcast a real-time event to all connected project clients.
+
+ Sends via local WS connections AND Redis pub/sub for multi-process.
+ """
+ message = json.dumps({"type": event_type, "data": data})
+ # Local broadcast
+ conns = _ws_connections.get(slug, {})
+ if conns:
+ disconnected = []
+ for uid, ws in conns.items():
+ try:
+ await ws.send_text(message)
+ except Exception:
+ disconnected.append(uid)
+ for uid in disconnected:
+ conns.pop(uid, None)
+ # Redis pub/sub for multi-process
+ if redis_client:
+ try:
+ await redis_client.publish(f"project:{slug}", message)
+ except Exception as e:
+ logger.warning("Redis publish failed: %s", e)
+
+
@app.get("/health")
async def health():
try:
diff --git a/api/auth.py b/api/auth.py
new file mode 100644
index 0000000..f5bb050
--- /dev/null
+++ b/api/auth.py
@@ -0,0 +1,181 @@
+"""Python-side auth: read-only consumer of Better Auth tables.
+
+All auth write operations happen in Next.js. Python API validates
+sessions and resolves roles by querying the auth tables directly.
+"""
+
+import logging
+from datetime import datetime, timezone
+from functools import wraps
+
+from fastapi import Request
+from fastapi.responses import JSONResponse
+
+logger = logging.getLogger("prd_forge_auth")
+
+# Actual Better Auth table/column names (verified by contract test)
+AUTH_TABLES = {
+ "user": "user",
+ "session": "session",
+ "account": "account",
+ "organization": "organization",
+ "member": "member",
+ "invitation": "invitation",
+ "verification": "verification",
+}
+
+
+async def get_session_user(request: Request, pool):
+ """Extract user from session token in cookie or Authorization header.
+
+ Returns dict with user info or None if not authenticated.
+ """
+ # Try cookie first (browser), then Authorization header (API)
+ token = None
+ cookie = request.cookies.get("better-auth.session_token")
+ if cookie:
+ # Cookie value may have .signature suffix
+ token = cookie.split(".")[0] if "." in cookie else cookie
+ else:
+ auth_header = request.headers.get("authorization", "")
+ if auth_header.startswith("Bearer "):
+ token = auth_header[7:]
+
+ if not token:
+ return None
+
+ row = await pool.fetchrow(
+ f"""
+ SELECT s.id AS session_id, s."userId" AS user_id, s."expiresAt",
+ u.name, u.email, u.image
+ FROM "{AUTH_TABLES['session']}" s
+ JOIN "{AUTH_TABLES['user']}" u ON u.id = s."userId"
+ WHERE s.token = $1
+ """,
+ token,
+ )
+
+ if not row:
+ return None
+
+ # Check expiry
+ expires = row["expiresAt"]
+ if expires and expires.replace(tzinfo=timezone.utc) < datetime.now(timezone.utc):
+ return None
+
+ return {
+ "session_id": row["session_id"],
+ "user_id": row["user_id"],
+ "name": row["name"],
+ "email": row["email"],
+ "image": row["image"],
+ }
+
+
+async def get_user_project_role(pool, user_id: str, project_slug: str) -> str | None:
+ """Get user's role for a project.
+
+ Checks project_members first, then falls back to org membership.
+ Returns role string or None if no access.
+ """
+ # Direct project membership
+ role = await pool.fetchval(
+ """
+ SELECT pm.role FROM project_members pm
+ JOIN projects p ON p.id = pm.project_id
+ WHERE pm.user_id = $1 AND p.slug = $2
+ """,
+ user_id,
+ project_slug,
+ )
+ if role:
+ return role
+
+ # Org membership fallback: org owner/admin → project admin
+ org_role = await pool.fetchval(
+ f"""
+ SELECT m.role FROM "{AUTH_TABLES['member']}" m
+ JOIN "{AUTH_TABLES['organization']}" o ON o.id = m."organizationId"
+ JOIN projects p ON p.organization_id = o.id::uuid
+ WHERE m."userId" = $1 AND p.slug = $2
+ """,
+ user_id,
+ project_slug,
+ )
+ if org_role in ("owner", "admin"):
+ return "admin"
+ if org_role == "member":
+ return "editor"
+
+ return None
+
+
+# Role hierarchy for permission checks
+ROLE_HIERARCHY = {
+ "owner": 5,
+ "admin": 4,
+ "editor": 3,
+ "commenter": 2,
+ "viewer": 1,
+}
+
+
+def has_min_role(user_role: str, min_role: str) -> bool:
+ """Check if user_role meets the minimum required role."""
+ return ROLE_HIERARCHY.get(user_role, 0) >= ROLE_HIERARCHY.get(min_role, 0)
+
+
+async def require_authenticated_user(request: Request, pool):
+ """Check user is authenticated. Returns user dict or JSONResponse error.
+
+ Does NOT check project role — use for endpoints where the project doesn't exist yet.
+ During migration / pre-setup: if auth not bootstrapped, returns a local-mode user.
+ """
+ from errors import unauthorized
+
+ if not await _is_auth_enforced(pool):
+ return {"user_id": None, "name": "local", "email": ""}
+
+ user = await get_session_user(request, pool)
+ if not user:
+ return unauthorized()
+
+ return user
+
+
+async def _is_auth_enforced(pool) -> bool:
+ """Return True if auth should be enforced (tables exist AND setup completed)."""
+ tbl = AUTH_TABLES["session"]
+ auth_exists = await pool.fetchval(f"""SELECT to_regclass('public."{tbl}"')""")
+ if not auth_exists:
+ return False
+ bootstrap_exists = await pool.fetchval("SELECT to_regclass('public.prdforge_bootstrap')")
+ if bootstrap_exists:
+ has_bootstrap = await pool.fetchval("SELECT 1 FROM prdforge_bootstrap LIMIT 1")
+ if not has_bootstrap:
+ return False
+ return True
+
+
+async def require_project_access(request: Request, pool, slug: str, min_role: str = "viewer"):
+ """Check user has required role for project. Returns (user, role) or JSONResponse error.
+
+ During migration / pre-setup: allow all access (single-user mode).
+ """
+ from errors import unauthorized, permission_denied, not_found
+
+ if not await _is_auth_enforced(pool):
+ return {"user_id": None, "name": "local", "email": ""}, "owner"
+
+ user = await get_session_user(request, pool)
+ if not user:
+ return unauthorized(), None
+
+ role = await get_user_project_role(pool, user["user_id"], slug)
+ if not role:
+ return not_found("project", slug), None
+
+ if not has_min_role(role, min_role):
+ return permission_denied(f"Requires {min_role} role, you have {role}"), None
+
+ return user, role
diff --git a/api/auth_contract.py b/api/auth_contract.py
new file mode 100644
index 0000000..0ac531a
--- /dev/null
+++ b/api/auth_contract.py
@@ -0,0 +1,50 @@
+"""Contract test: verify Better Auth table names and columns exist.
+
+Better Auth uses Prisma model names which may differ from DB table names.
+This contract verifies the ACTUAL tables created by `prisma migrate deploy`.
+Pin: better-auth@1.4.7
+"""
+
+# Expected tables and their required columns (from Prisma schema @@map)
+EXPECTED_TABLES = {
+ "user": ["id", "name", "email", "emailVerified", "createdAt", "updatedAt"],
+ "session": ["id", "token", "userId", "expiresAt", "createdAt"],
+ "account": ["id", "accountId", "providerId", "userId", "createdAt"],
+ "verification": ["id", "identifier", "value", "expiresAt"],
+ "organization": ["id", "name", "slug", "createdAt", "updatedAt"],
+ "member": ["id", "organizationId", "userId", "role", "createdAt"],
+ "invitation": ["id", "organizationId", "email", "role", "status", "expiresAt"],
+}
+
+
+async def verify_auth_contract(pool) -> list[str]:
+ """Verify Better Auth tables exist with expected columns.
+
+ Returns list of errors (empty = all good).
+ """
+ errors = []
+
+ for table, expected_cols in EXPECTED_TABLES.items():
+ # Check table exists
+ exists = await pool.fetchval(
+ "SELECT to_regclass($1)", table
+ )
+ if not exists:
+ errors.append(f"Table '{table}' does not exist")
+ continue
+
+ # Check columns
+ actual_cols = await pool.fetch(
+ """
+ SELECT column_name FROM information_schema.columns
+ WHERE table_name = $1 AND table_schema = 'public'
+ """,
+ table,
+ )
+ actual_col_names = {r["column_name"] for r in actual_cols}
+
+ for col in expected_cols:
+ if col not in actual_col_names:
+ errors.append(f"Table '{table}' missing column '{col}'")
+
+ return errors
diff --git a/api/errors.py b/api/errors.py
new file mode 100644
index 0000000..091e928
--- /dev/null
+++ b/api/errors.py
@@ -0,0 +1,68 @@
+"""Structured error responses for the Python API.
+
+Format: {"error": {"code": "...", "message": "...", "status": N, "details": {}}}
+
+9 standard error codes matching the PRD spec.
+"""
+
+from fastapi.responses import JSONResponse
+
+
+# Standard error codes
+UNAUTHORIZED = "UNAUTHORIZED"
+PERMISSION_DENIED = "PERMISSION_DENIED"
+NOT_FOUND = "NOT_FOUND"
+VALIDATION_ERROR = "VALIDATION_ERROR"
+CONFLICT = "CONFLICT"
+RATE_LIMITED = "RATE_LIMITED"
+INTERNAL_ERROR = "INTERNAL_ERROR"
+CHAT_DISABLED = "CHAT_DISABLED"
+NO_API_KEY = "NO_API_KEY"
+
+
+def error_response(
+ code: str,
+ message: str,
+ status: int,
+ details: dict | None = None,
+) -> JSONResponse:
+ """Create a structured error response."""
+ return JSONResponse(
+ {
+ "error": {
+ "code": code,
+ "message": message,
+ "status": status,
+ "details": details or {},
+ }
+ },
+ status_code=status,
+ )
+
+
+def not_found(resource: str, identifier: str) -> JSONResponse:
+ return error_response(
+ NOT_FOUND,
+ f"{resource} '{identifier}' not found",
+ 404,
+ )
+
+
+def validation_error(message: str, details: dict | None = None) -> JSONResponse:
+ return error_response(VALIDATION_ERROR, message, 400, details)
+
+
+def unauthorized(message: str = "Authentication required") -> JSONResponse:
+ return error_response(UNAUTHORIZED, message, 401)
+
+
+def permission_denied(message: str = "Insufficient permissions") -> JSONResponse:
+ return error_response(PERMISSION_DENIED, message, 403)
+
+
+def conflict(message: str, details: dict | None = None) -> JSONResponse:
+ return error_response(CONFLICT, message, 409, details)
+
+
+def internal_error(message: str = "Internal server error") -> JSONResponse:
+ return error_response(INTERNAL_ERROR, message, 500)
diff --git a/ui/requirements.txt b/api/requirements.txt
similarity index 65%
rename from ui/requirements.txt
rename to api/requirements.txt
index 85650cf..c3cce95 100644
--- a/ui/requirements.txt
+++ b/api/requirements.txt
@@ -2,4 +2,6 @@ fastapi>=0.115
uvicorn>=0.34
asyncpg>=0.29
httpx>=0.28
+redis[hiredis]>=5.0
+websockets>=14.0
mcp[cli]>=1.9
diff --git a/ui/static/MARKED_VERSION b/api/static/MARKED_VERSION
similarity index 100%
rename from ui/static/MARKED_VERSION
rename to api/static/MARKED_VERSION
diff --git a/ui/static/fonts.css b/api/static/fonts.css
similarity index 100%
rename from ui/static/fonts.css
rename to api/static/fonts.css
diff --git a/ui/static/fonts/inter-cyrillic-ext.woff2 b/api/static/fonts/inter-cyrillic-ext.woff2
similarity index 100%
rename from ui/static/fonts/inter-cyrillic-ext.woff2
rename to api/static/fonts/inter-cyrillic-ext.woff2
diff --git a/ui/static/fonts/inter-cyrillic.woff2 b/api/static/fonts/inter-cyrillic.woff2
similarity index 100%
rename from ui/static/fonts/inter-cyrillic.woff2
rename to api/static/fonts/inter-cyrillic.woff2
diff --git a/ui/static/fonts/inter-greek-ext.woff2 b/api/static/fonts/inter-greek-ext.woff2
similarity index 100%
rename from ui/static/fonts/inter-greek-ext.woff2
rename to api/static/fonts/inter-greek-ext.woff2
diff --git a/ui/static/fonts/inter-greek.woff2 b/api/static/fonts/inter-greek.woff2
similarity index 100%
rename from ui/static/fonts/inter-greek.woff2
rename to api/static/fonts/inter-greek.woff2
diff --git a/ui/static/fonts/inter-latin-ext.woff2 b/api/static/fonts/inter-latin-ext.woff2
similarity index 100%
rename from ui/static/fonts/inter-latin-ext.woff2
rename to api/static/fonts/inter-latin-ext.woff2
diff --git a/ui/static/fonts/inter-latin.woff2 b/api/static/fonts/inter-latin.woff2
similarity index 100%
rename from ui/static/fonts/inter-latin.woff2
rename to api/static/fonts/inter-latin.woff2
diff --git a/ui/static/fonts/inter-vietnamese.woff2 b/api/static/fonts/inter-vietnamese.woff2
similarity index 100%
rename from ui/static/fonts/inter-vietnamese.woff2
rename to api/static/fonts/inter-vietnamese.woff2
diff --git a/ui/static/fonts/jetbrains-mono-cyrillic-ext.woff2 b/api/static/fonts/jetbrains-mono-cyrillic-ext.woff2
similarity index 100%
rename from ui/static/fonts/jetbrains-mono-cyrillic-ext.woff2
rename to api/static/fonts/jetbrains-mono-cyrillic-ext.woff2
diff --git a/ui/static/fonts/jetbrains-mono-cyrillic.woff2 b/api/static/fonts/jetbrains-mono-cyrillic.woff2
similarity index 100%
rename from ui/static/fonts/jetbrains-mono-cyrillic.woff2
rename to api/static/fonts/jetbrains-mono-cyrillic.woff2
diff --git a/ui/static/fonts/jetbrains-mono-greek.woff2 b/api/static/fonts/jetbrains-mono-greek.woff2
similarity index 100%
rename from ui/static/fonts/jetbrains-mono-greek.woff2
rename to api/static/fonts/jetbrains-mono-greek.woff2
diff --git a/ui/static/fonts/jetbrains-mono-latin-ext.woff2 b/api/static/fonts/jetbrains-mono-latin-ext.woff2
similarity index 100%
rename from ui/static/fonts/jetbrains-mono-latin-ext.woff2
rename to api/static/fonts/jetbrains-mono-latin-ext.woff2
diff --git a/ui/static/fonts/jetbrains-mono-latin.woff2 b/api/static/fonts/jetbrains-mono-latin.woff2
similarity index 100%
rename from ui/static/fonts/jetbrains-mono-latin.woff2
rename to api/static/fonts/jetbrains-mono-latin.woff2
diff --git a/ui/static/fonts/jetbrains-mono-vietnamese.woff2 b/api/static/fonts/jetbrains-mono-vietnamese.woff2
similarity index 100%
rename from ui/static/fonts/jetbrains-mono-vietnamese.woff2
rename to api/static/fonts/jetbrains-mono-vietnamese.woff2
diff --git a/ui/static/github-dark.min.css b/api/static/github-dark.min.css
similarity index 100%
rename from ui/static/github-dark.min.css
rename to api/static/github-dark.min.css
diff --git a/ui/static/highlight.min.js b/api/static/highlight.min.js
similarity index 100%
rename from ui/static/highlight.min.js
rename to api/static/highlight.min.js
diff --git a/ui/static/index.html b/api/static/index.html
similarity index 99%
rename from ui/static/index.html
rename to api/static/index.html
index ea6d5e6..f59b21e 100644
--- a/ui/static/index.html
+++ b/api/static/index.html
@@ -487,7 +487,7 @@
Project Chat
-
+
Thinking...
diff --git a/ui/static/marked.min.js b/api/static/marked.min.js
similarity index 100%
rename from ui/static/marked.min.js
rename to api/static/marked.min.js
diff --git a/api/ws.py b/api/ws.py
new file mode 100644
index 0000000..2e5772f
--- /dev/null
+++ b/api/ws.py
@@ -0,0 +1,80 @@
+"""WebSocket token minting and real-time event handling.
+
+Token: HMAC-SHA256({jti, sub, aud, project, exp})
+jti uniqueness: Redis SET NX EX (one-time use)
+Revocation: publish ws_revoke:{user_id} to Redis → handlers force-disconnect
+"""
+
+import hashlib
+import hmac
+import json
+import logging
+import os
+import time
+import uuid
+
+logger = logging.getLogger("prd_forge_ws")
+
+_DEFAULT_WS_SECRET = "dev-ws-secret-change-in-production-0000000000000000"
+WS_TOKEN_SECRET = os.environ.get("WS_TOKEN_SECRET", _DEFAULT_WS_SECRET)
+WS_TOKEN_TTL = int(os.environ.get("WS_TOKEN_TTL_SECONDS", "120"))
+
+if WS_TOKEN_SECRET == _DEFAULT_WS_SECRET:
+ import sys
+ print(
+ "WARNING: WS_TOKEN_SECRET is using the default dev value — "
+ "set WS_TOKEN_SECRET env var in production",
+ file=sys.stderr,
+ )
+
+
+def mint_ws_token(user_id: str, project_slug: str) -> str:
+ """Create a short-lived HMAC token for WebSocket authentication."""
+ payload = {
+ "jti": str(uuid.uuid4()),
+ "sub": user_id,
+ "aud": "ws",
+ "project": project_slug,
+ "exp": int(time.time()) + WS_TOKEN_TTL,
+ }
+ payload_json = json.dumps(payload, separators=(",", ":"), sort_keys=True)
+ sig = hmac.new(
+ WS_TOKEN_SECRET.encode(), payload_json.encode(), hashlib.sha256
+ ).hexdigest()
+ return f"{payload_json}.{sig}"
+
+
+def verify_ws_token(token: str) -> dict | None:
+ """Verify HMAC signature and TTL. Returns payload or None."""
+ try:
+ payload_json, sig = token.rsplit(".", 1)
+ except ValueError:
+ return None
+
+ expected_sig = hmac.new(
+ WS_TOKEN_SECRET.encode(), payload_json.encode(), hashlib.sha256
+ ).hexdigest()
+
+ if not hmac.compare_digest(sig, expected_sig):
+ logger.warning("WS token signature mismatch")
+ return None
+
+ payload = json.loads(payload_json)
+
+ if payload.get("aud") != "ws":
+ return None
+ if payload.get("exp", 0) < time.time():
+ logger.warning("WS token expired")
+ return None
+
+ return payload
+
+
+# Event types for real-time updates
+EVENT_TYPES = {
+ "section_updated",
+ "section_created",
+ "section_deleted",
+ "comment_added",
+ "presence_update",
+}
diff --git a/db/07_multi_user.sql b/db/07_multi_user.sql
new file mode 100644
index 0000000..ff3ac96
--- /dev/null
+++ b/db/07_multi_user.sql
@@ -0,0 +1,99 @@
+-- Multi-user schema: bridge columns, project_members, bootstrap flag
+-- All statements idempotent (IF NOT EXISTS / DO $$ BEGIN ... END $$)
+
+-- Bridge columns on existing tables (nullable for backward compat)
+DO $$ BEGIN
+ IF NOT EXISTS (
+ SELECT 1 FROM information_schema.columns
+ WHERE table_name = 'projects' AND column_name = 'organization_id'
+ ) THEN
+ ALTER TABLE projects ADD COLUMN organization_id UUID;
+ END IF;
+END $$;
+
+DO $$ BEGIN
+ IF NOT EXISTS (
+ SELECT 1 FROM information_schema.columns
+ WHERE table_name = 'projects' AND column_name = 'created_by'
+ ) THEN
+ ALTER TABLE projects ADD COLUMN created_by UUID;
+ END IF;
+END $$;
+
+DO $$ BEGIN
+ IF NOT EXISTS (
+ SELECT 1 FROM information_schema.columns
+ WHERE table_name = 'sections' AND column_name = 'updated_by'
+ ) THEN
+ ALTER TABLE sections ADD COLUMN updated_by UUID;
+ END IF;
+END $$;
+
+DO $$ BEGIN
+ IF NOT EXISTS (
+ SELECT 1 FROM information_schema.columns
+ WHERE table_name = 'section_revisions' AND column_name = 'created_by'
+ ) THEN
+ ALTER TABLE section_revisions ADD COLUMN created_by UUID;
+ END IF;
+END $$;
+
+DO $$ BEGIN
+ IF NOT EXISTS (
+ SELECT 1 FROM information_schema.columns
+ WHERE table_name = 'section_comments' AND column_name = 'created_by'
+ ) THEN
+ ALTER TABLE section_comments ADD COLUMN created_by UUID;
+ END IF;
+END $$;
+
+DO $$ BEGIN
+ IF NOT EXISTS (
+ SELECT 1 FROM information_schema.columns
+ WHERE table_name = 'chat_messages' AND column_name = 'created_by'
+ ) THEN
+ ALTER TABLE chat_messages ADD COLUMN created_by UUID;
+ END IF;
+END $$;
+
+DO $$ BEGIN
+ IF NOT EXISTS (
+ SELECT 1 FROM information_schema.columns
+ WHERE table_name = 'mcp_activity' AND column_name = 'user_id'
+ ) THEN
+ ALTER TABLE mcp_activity ADD COLUMN user_id UUID;
+ END IF;
+END $$;
+
+-- Project members (5 roles)
+CREATE TABLE IF NOT EXISTS project_members (
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+ project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
+ user_id UUID NOT NULL,
+ role TEXT NOT NULL CHECK (role IN ('owner', 'admin', 'editor', 'commenter', 'viewer')),
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
+ UNIQUE(project_id, user_id)
+);
+
+CREATE INDEX IF NOT EXISTS idx_project_members_user
+ ON project_members(user_id);
+
+-- Trigger for updated_at on project_members
+DO $$ BEGIN
+ IF NOT EXISTS (
+ SELECT 1 FROM pg_trigger WHERE tgname = 'trg_project_members_updated'
+ ) THEN
+ CREATE TRIGGER trg_project_members_updated
+ BEFORE UPDATE ON project_members
+ FOR EACH ROW EXECUTE FUNCTION update_timestamp();
+ END IF;
+END $$;
+
+-- Bootstrap flag table (ensures first-user setup runs once)
+CREATE TABLE IF NOT EXISTS prdforge_bootstrap (
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+ setup_type TEXT NOT NULL UNIQUE,
+ completed BOOLEAN NOT NULL DEFAULT false,
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now()
+);
diff --git a/db/08_mcp_activity.sql b/db/08_mcp_activity.sql
new file mode 100644
index 0000000..35fea6c
--- /dev/null
+++ b/db/08_mcp_activity.sql
@@ -0,0 +1,11 @@
+-- MCP activity tracking (write operations only)
+CREATE TABLE IF NOT EXISTS mcp_activity (
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+ project_id UUID REFERENCES projects(id) ON DELETE CASCADE,
+ tool_name TEXT NOT NULL,
+ detail JSONB DEFAULT '{}',
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now()
+);
+
+CREATE INDEX IF NOT EXISTS idx_mcp_activity_project
+ ON mcp_activity(project_id, created_at DESC);
diff --git a/db/09_audit.sql b/db/09_audit.sql
new file mode 100644
index 0000000..4e7dcf2
--- /dev/null
+++ b/db/09_audit.sql
@@ -0,0 +1,16 @@
+-- Audit events table
+CREATE TABLE IF NOT EXISTS audit_events (
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+ project_id UUID REFERENCES projects(id) ON DELETE CASCADE,
+ user_id UUID,
+ action TEXT NOT NULL,
+ resource TEXT NOT NULL,
+ detail JSONB DEFAULT '{}',
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now()
+);
+
+CREATE INDEX IF NOT EXISTS idx_audit_events_project
+ ON audit_events(project_id, created_at DESC);
+
+CREATE INDEX IF NOT EXISTS idx_audit_events_user
+ ON audit_events(user_id, created_at DESC);
diff --git a/db/10_password_reset.sql b/db/10_password_reset.sql
new file mode 100644
index 0000000..5bba079
--- /dev/null
+++ b/db/10_password_reset.sql
@@ -0,0 +1,13 @@
+-- Password reset tokens (admin-generated, no email)
+CREATE TABLE IF NOT EXISTS password_reset_tokens (
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+ user_id UUID NOT NULL,
+ token TEXT NOT NULL UNIQUE,
+ expires_at TIMESTAMPTZ NOT NULL,
+ used BOOLEAN NOT NULL DEFAULT false,
+ created_by UUID,
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now()
+);
+
+CREATE INDEX IF NOT EXISTS idx_password_reset_token
+ ON password_reset_tokens(token) WHERE NOT used;
diff --git a/db/11_chat_multiuser.sql b/db/11_chat_multiuser.sql
new file mode 100644
index 0000000..e403f78
--- /dev/null
+++ b/db/11_chat_multiuser.sql
@@ -0,0 +1,50 @@
+-- Multi-user chat: thread types, user attribution, org API key
+-- All statements idempotent
+
+-- Add chat_type to project_chats (main thread vs per-section)
+DO $$ BEGIN
+ IF NOT EXISTS (
+ SELECT 1 FROM information_schema.columns
+ WHERE table_name = 'project_chats' AND column_name = 'chat_type'
+ ) THEN
+ ALTER TABLE project_chats ADD COLUMN chat_type TEXT NOT NULL DEFAULT 'main';
+ -- Drop unique constraint on project_id to allow multiple threads
+ ALTER TABLE project_chats DROP CONSTRAINT IF EXISTS project_chats_project_id_key;
+ END IF;
+END $$;
+
+-- Add section_id for per-section threads
+DO $$ BEGIN
+ IF NOT EXISTS (
+ SELECT 1 FROM information_schema.columns
+ WHERE table_name = 'project_chats' AND column_name = 'section_id'
+ ) THEN
+ ALTER TABLE project_chats ADD COLUMN section_id UUID REFERENCES sections(id) ON DELETE CASCADE;
+ END IF;
+END $$;
+
+-- Add created_by for user attribution on chats
+DO $$ BEGIN
+ IF NOT EXISTS (
+ SELECT 1 FROM information_schema.columns
+ WHERE table_name = 'project_chats' AND column_name = 'created_by'
+ ) THEN
+ ALTER TABLE project_chats ADD COLUMN created_by UUID;
+ END IF;
+END $$;
+
+-- Unique constraint: one thread per type per project (per section if section thread)
+CREATE UNIQUE INDEX IF NOT EXISTS idx_project_chats_type_section
+ ON project_chats(project_id, chat_type, COALESCE(section_id, '00000000-0000-0000-0000-000000000000'));
+
+-- Add encrypted API key to organization table (if it exists from Better Auth)
+DO $$ BEGIN
+ IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'organization') THEN
+ IF NOT EXISTS (
+ SELECT 1 FROM information_schema.columns
+ WHERE table_name = 'organization' AND column_name = 'anthropic_api_key_encrypted'
+ ) THEN
+ ALTER TABLE organization ADD COLUMN anthropic_api_key_encrypted TEXT;
+ END IF;
+ END IF;
+END $$;
diff --git a/db/12_better_auth.sql b/db/12_better_auth.sql
new file mode 100644
index 0000000..2f8dc33
--- /dev/null
+++ b/db/12_better_auth.sql
@@ -0,0 +1,78 @@
+-- Better Auth tables (matches Prisma schema with @@map names)
+-- These are normally created by `prisma db push` but we create via SQL
+-- for Docker init compatibility. All statements idempotent.
+
+CREATE TABLE IF NOT EXISTS "user" (
+ id TEXT PRIMARY KEY,
+ name TEXT NOT NULL,
+ email TEXT NOT NULL UNIQUE,
+ "emailVerified" BOOLEAN NOT NULL DEFAULT false,
+ image TEXT,
+ "createdAt" TIMESTAMPTZ NOT NULL DEFAULT now(),
+ "updatedAt" TIMESTAMPTZ NOT NULL DEFAULT now()
+);
+
+CREATE TABLE IF NOT EXISTS session (
+ id TEXT PRIMARY KEY,
+ "expiresAt" TIMESTAMPTZ NOT NULL,
+ token TEXT NOT NULL UNIQUE,
+ "createdAt" TIMESTAMPTZ NOT NULL DEFAULT now(),
+ "updatedAt" TIMESTAMPTZ NOT NULL DEFAULT now(),
+ "ipAddress" TEXT,
+ "userAgent" TEXT,
+ "userId" TEXT NOT NULL REFERENCES "user"(id) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS account (
+ id TEXT PRIMARY KEY,
+ "accountId" TEXT NOT NULL,
+ "providerId" TEXT NOT NULL,
+ "userId" TEXT NOT NULL REFERENCES "user"(id) ON DELETE CASCADE,
+ "accessToken" TEXT,
+ "refreshToken" TEXT,
+ "idToken" TEXT,
+ "accessTokenExpiresAt" TIMESTAMPTZ,
+ "refreshTokenExpiresAt" TIMESTAMPTZ,
+ scope TEXT,
+ password TEXT,
+ "createdAt" TIMESTAMPTZ NOT NULL DEFAULT now(),
+ "updatedAt" TIMESTAMPTZ NOT NULL DEFAULT now()
+);
+
+CREATE TABLE IF NOT EXISTS verification (
+ id TEXT PRIMARY KEY,
+ identifier TEXT NOT NULL,
+ value TEXT NOT NULL,
+ "expiresAt" TIMESTAMPTZ NOT NULL,
+ "createdAt" TIMESTAMPTZ DEFAULT now(),
+ "updatedAt" TIMESTAMPTZ DEFAULT now()
+);
+
+CREATE TABLE IF NOT EXISTS organization (
+ id TEXT PRIMARY KEY,
+ name TEXT NOT NULL,
+ slug TEXT UNIQUE,
+ logo TEXT,
+ "createdAt" TIMESTAMPTZ NOT NULL DEFAULT now(),
+ "updatedAt" TIMESTAMPTZ NOT NULL DEFAULT now(),
+ metadata TEXT,
+ anthropic_api_key_encrypted TEXT
+);
+
+CREATE TABLE IF NOT EXISTS member (
+ id TEXT PRIMARY KEY,
+ "organizationId" TEXT NOT NULL REFERENCES organization(id) ON DELETE CASCADE,
+ "userId" TEXT NOT NULL REFERENCES "user"(id) ON DELETE CASCADE,
+ role TEXT NOT NULL,
+ "createdAt" TIMESTAMPTZ NOT NULL DEFAULT now()
+);
+
+CREATE TABLE IF NOT EXISTS invitation (
+ id TEXT PRIMARY KEY,
+ "organizationId" TEXT NOT NULL REFERENCES organization(id) ON DELETE CASCADE,
+ email TEXT NOT NULL,
+ role TEXT,
+ status TEXT NOT NULL,
+ "expiresAt" TIMESTAMPTZ NOT NULL,
+ "inviterId" TEXT NOT NULL
+);
diff --git a/db/13_section_access_log.sql b/db/13_section_access_log.sql
new file mode 100644
index 0000000..296f580
--- /dev/null
+++ b/db/13_section_access_log.sql
@@ -0,0 +1,15 @@
+-- Honest token savings: track section-level access for deduplication
+-- Replaces the old token_estimates approach which inflated savings
+
+CREATE TABLE IF NOT EXISTS section_access_log (
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+ project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
+ operation TEXT NOT NULL,
+ section_id UUID REFERENCES sections(id) ON DELETE SET NULL,
+ access_level TEXT NOT NULL CHECK (access_level IN ('full', 'summary', 'snippet')),
+ loaded_words INT NOT NULL DEFAULT 0,
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now()
+);
+
+CREATE INDEX IF NOT EXISTS idx_sal_project_time
+ ON section_access_log(project_id, created_at);
diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml
index c647e7f..b3a6dbf 100644
--- a/docker-compose.prod.yml
+++ b/docker-compose.prod.yml
@@ -18,6 +18,13 @@ services:
- ./db/04_replies_and_settings.sql:/docker-entrypoint-initdb.d/04_replies_and_settings.sql:ro
- ./db/05_token_stats.sql:/docker-entrypoint-initdb.d/05_token_stats.sql:ro
- ./db/06_chat.sql:/docker-entrypoint-initdb.d/06_chat.sql:ro
+ - ./db/07_multi_user.sql:/docker-entrypoint-initdb.d/07_multi_user.sql:ro
+ - ./db/08_mcp_activity.sql:/docker-entrypoint-initdb.d/08_mcp_activity.sql:ro
+ - ./db/09_audit.sql:/docker-entrypoint-initdb.d/09_audit.sql:ro
+ - ./db/10_password_reset.sql:/docker-entrypoint-initdb.d/10_password_reset.sql:ro
+ - ./db/11_chat_multiuser.sql:/docker-entrypoint-initdb.d/11_chat_multiuser.sql:ro
+ - ./db/12_better_auth.sql:/docker-entrypoint-initdb.d/12_better_auth.sql:ro
+ - ./db/13_section_access_log.sql:/docker-entrypoint-initdb.d/13_section_access_log.sql:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-prdforge}"]
interval: 3s
@@ -43,8 +50,8 @@ services:
start_period: 10s
restart: unless-stopped
- ui:
- image: ghcr.io/tommass/prdforge-ui:${PRDFORGE_VERSION:-latest}
+ python-api:
+ image: ghcr.io/tommass/prdforge-api:${PRDFORGE_VERSION:-latest}
environment:
DATABASE_URL: postgresql://${POSTGRES_USER:-prdforge}:${POSTGRES_PASSWORD:-prdforge}@postgres:5432/${POSTGRES_DB:-prdforge}
CHAT_PROVIDER: ${CHAT_PROVIDER:-claude_cli}
@@ -65,5 +72,24 @@ services:
condition: service_healthy
restart: unless-stopped
+ redis:
+ image: redis:7-alpine
+ healthcheck:
+ test: ["CMD", "redis-cli", "ping"]
+ interval: 3s
+ timeout: 2s
+ retries: 5
+ restart: unless-stopped
+
+ frontend:
+ image: ghcr.io/tommass/prdforge-frontend:${PRDFORGE_VERSION:-latest}
+ ports:
+ - "3000:3000"
+ environment:
+ NEXT_PUBLIC_API_URL: ""
+ depends_on:
+ - python-api
+ restart: unless-stopped
+
volumes:
pgdata:
diff --git a/docker-compose.yml b/docker-compose.yml
index 5e59dd4..b0d060a 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -16,6 +16,13 @@ services:
- ./db/04_replies_and_settings.sql:/docker-entrypoint-initdb.d/04_replies_and_settings.sql:ro
- ./db/05_token_stats.sql:/docker-entrypoint-initdb.d/05_token_stats.sql:ro
- ./db/06_chat.sql:/docker-entrypoint-initdb.d/06_chat.sql:ro
+ - ./db/07_multi_user.sql:/docker-entrypoint-initdb.d/07_multi_user.sql:ro
+ - ./db/08_mcp_activity.sql:/docker-entrypoint-initdb.d/08_mcp_activity.sql:ro
+ - ./db/09_audit.sql:/docker-entrypoint-initdb.d/09_audit.sql:ro
+ - ./db/10_password_reset.sql:/docker-entrypoint-initdb.d/10_password_reset.sql:ro
+ - ./db/11_chat_multiuser.sql:/docker-entrypoint-initdb.d/11_chat_multiuser.sql:ro
+ - ./db/12_better_auth.sql:/docker-entrypoint-initdb.d/12_better_auth.sql:ro
+ - ./db/13_section_access_log.sql:/docker-entrypoint-initdb.d/13_section_access_log.sql:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-prdforge}"]
interval: 3s
@@ -43,10 +50,10 @@ services:
start_period: 10s
restart: unless-stopped
- ui:
+ python-api:
build:
context: .
- dockerfile: ui/Dockerfile
+ dockerfile: api/Dockerfile
environment:
DATABASE_URL: postgresql://${POSTGRES_USER:-prdforge}:${POSTGRES_PASSWORD:-prdforge}@postgres:5432/${POSTGRES_DB:-prdforge}
CHAT_PROVIDER: ${CHAT_PROVIDER:-claude_cli}
@@ -58,6 +65,9 @@ services:
CLAUDE_CLI_PATH: ${CLAUDE_CLI_PATH:-claude}
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-}
ANTHROPIC_MODEL: ${ANTHROPIC_MODEL:-claude-3-7-sonnet-latest}
+ REDIS_URL: ${REDIS_URL:-redis://redis:6379}
+ WS_TOKEN_SECRET: ${WS_TOKEN_SECRET:-dev-ws-secret-change-in-production-0000000000000000}
+ WS_TOKEN_TTL_SECONDS: ${WS_TOKEN_TTL_SECONDS:-120}
volumes:
- ${HOME}/.claude:/root/.claude
ports:
@@ -65,6 +75,36 @@ services:
depends_on:
postgres:
condition: service_healthy
+ redis:
+ condition: service_healthy
+ restart: unless-stopped
+
+ redis:
+ image: redis:7-alpine
+ ports:
+ - "127.0.0.1:6379:6379"
+ healthcheck:
+ test: ["CMD", "redis-cli", "ping"]
+ interval: 3s
+ timeout: 2s
+ retries: 5
+ restart: unless-stopped
+
+ frontend:
+ build:
+ context: .
+ dockerfile: frontend/Dockerfile
+ ports:
+ - "3000:3000"
+ environment:
+ DATABASE_URL: postgresql://${POSTGRES_USER:-prdforge}:${POSTGRES_PASSWORD:-prdforge}@postgres:5432/${POSTGRES_DB:-prdforge}
+ BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET:-dev-better-auth-secret-change-in-production}
+ PRISMA_QUERY_ENGINE_LIBRARY: /app/node_modules/.prisma/client/libquery_engine-linux-musl-arm64-openssl-3.0.x.so.node
+ depends_on:
+ postgres:
+ condition: service_healthy
+ python-api:
+ condition: service_started
restart: unless-stopped
volumes:
diff --git a/frontend/.gitignore b/frontend/.gitignore
new file mode 100644
index 0000000..d1b8113
--- /dev/null
+++ b/frontend/.gitignore
@@ -0,0 +1,5 @@
+node_modules/
+.next/
+out/
+.yarn/cache
+.yarn/install-state.gz
diff --git a/frontend/.yarnrc.yml b/frontend/.yarnrc.yml
new file mode 100644
index 0000000..3186f3f
--- /dev/null
+++ b/frontend/.yarnrc.yml
@@ -0,0 +1 @@
+nodeLinker: node-modules
diff --git a/frontend/Dockerfile b/frontend/Dockerfile
new file mode 100644
index 0000000..a7bea19
--- /dev/null
+++ b/frontend/Dockerfile
@@ -0,0 +1,25 @@
+FROM node:22-alpine AS base
+RUN corepack enable
+
+FROM base AS deps
+WORKDIR /app
+COPY frontend/package.json frontend/yarn.lock frontend/.yarnrc.yml ./
+COPY frontend/prisma ./prisma
+RUN yarn install --immutable
+RUN npx prisma generate
+
+FROM base AS builder
+WORKDIR /app
+COPY --from=deps /app/node_modules ./node_modules
+COPY --from=deps /app/.yarnrc.yml ./
+COPY frontend/ .
+RUN yarn build
+
+FROM base AS runner
+WORKDIR /app
+ENV NODE_ENV=production
+COPY --from=builder /app/.next/standalone ./
+COPY --from=builder /app/.next/static ./.next/static
+COPY --from=builder /app/public ./public
+EXPOSE 3000
+CMD ["node", "server.js"]
diff --git a/frontend/eslint.config.mjs b/frontend/eslint.config.mjs
new file mode 100644
index 0000000..348c45a
--- /dev/null
+++ b/frontend/eslint.config.mjs
@@ -0,0 +1,14 @@
+import { dirname } from "path";
+import { fileURLToPath } from "url";
+import { FlatCompat } from "@eslint/eslintrc";
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = dirname(__filename);
+
+const compat = new FlatCompat({
+ baseDirectory: __dirname,
+});
+
+const eslintConfig = [...compat.extends("next/core-web-vitals")];
+
+export default eslintConfig;
diff --git a/frontend/next-env.d.ts b/frontend/next-env.d.ts
new file mode 100644
index 0000000..830fb59
--- /dev/null
+++ b/frontend/next-env.d.ts
@@ -0,0 +1,6 @@
+///
+///
+///
+
+// NOTE: This file should not be edited
+// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
diff --git a/frontend/next.config.ts b/frontend/next.config.ts
new file mode 100644
index 0000000..854daa2
--- /dev/null
+++ b/frontend/next.config.ts
@@ -0,0 +1,10 @@
+import type { NextConfig } from "next";
+
+const nextConfig: NextConfig = {
+ output: "standalone",
+ outputFileTracingIncludes: {
+ "/api/**": ["./node_modules/.prisma/**", "./node_modules/@prisma/client/**"],
+ },
+};
+
+export default nextConfig;
diff --git a/frontend/package.json b/frontend/package.json
new file mode 100644
index 0000000..143b24b
--- /dev/null
+++ b/frontend/package.json
@@ -0,0 +1,55 @@
+{
+ "name": "prdforge-frontend",
+ "version": "0.1.0",
+ "private": true,
+ "packageManager": "yarn@4.6.0",
+ "scripts": {
+ "dev": "next dev",
+ "build": "next build",
+ "start": "next start",
+ "lint": "next lint",
+ "typecheck": "tsc --noEmit",
+ "test": "vitest"
+ },
+ "dependencies": {
+ "@prisma/client": "5.22.0",
+ "@radix-ui/react-avatar": "^1.1.11",
+ "@radix-ui/react-dialog": "^1.1.15",
+ "@radix-ui/react-dropdown-menu": "^2.1.16",
+ "@radix-ui/react-select": "^2.2.6",
+ "@radix-ui/react-slot": "^1.2.4",
+ "@radix-ui/react-tabs": "^1.1.13",
+ "@radix-ui/react-tooltip": "^1.2.8",
+ "bcryptjs": "^3.0.3",
+ "better-auth": "1.4.7",
+ "class-variance-authority": "^0.7.1",
+ "clsx": "^2.1.1",
+ "http-proxy": "^1.18.1",
+ "lucide-react": "^0.475.0",
+ "next": "^15.3.1",
+ "prisma": "5.22.0",
+ "react": "^19.1.0",
+ "react-dom": "^19.1.0",
+ "react-markdown": "^10.1.0",
+ "recharts": "^3.8.0",
+ "rehype-highlight": "^7.0.2",
+ "remark-gfm": "^4.0.1",
+ "sonner": "^2.0.7",
+ "tailwind-merge": "^3.0.2"
+ },
+ "devDependencies": {
+ "@eslint/eslintrc": "^3.3.5",
+ "@tailwindcss/postcss": "^4.1.3",
+ "@types/bcryptjs": "^3.0.0",
+ "@types/http-proxy": "^1.17.17",
+ "@types/node": "^22.13.10",
+ "@types/react": "^19.1.0",
+ "@types/react-dom": "^19.1.0",
+ "@vitejs/plugin-react": "^4.3.4",
+ "eslint": "^9.0.0",
+ "eslint-config-next": "^15.3.1",
+ "tailwindcss": "^4.1.3",
+ "typescript": "^5.8.2",
+ "vitest": "^3.1.1"
+ }
+}
diff --git a/frontend/postcss.config.mjs b/frontend/postcss.config.mjs
new file mode 100644
index 0000000..c2ddf74
--- /dev/null
+++ b/frontend/postcss.config.mjs
@@ -0,0 +1,5 @@
+export default {
+ plugins: {
+ "@tailwindcss/postcss": {},
+ },
+};
diff --git a/frontend/prisma/schema.prisma b/frontend/prisma/schema.prisma
new file mode 100644
index 0000000..38cdc56
--- /dev/null
+++ b/frontend/prisma/schema.prisma
@@ -0,0 +1,116 @@
+generator client {
+ provider = "prisma-client-js"
+ binaryTargets = ["native", "linux-musl-openssl-3.0.x", "linux-musl-arm64-openssl-3.0.x"]
+}
+
+datasource db {
+ provider = "postgresql"
+ url = env("DATABASE_URL")
+}
+
+// Better Auth tables — 7 tables for auth management
+// These are managed by Better Auth, not PRDforge
+
+model User {
+ id String @id
+ name String
+ email String @unique
+ emailVerified Boolean @default(false)
+ image String?
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+
+ sessions Session[]
+ accounts Account[]
+ members Member[]
+
+ @@map("user")
+}
+
+model Session {
+ id String @id
+ expiresAt DateTime
+ token String @unique
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ ipAddress String?
+ userAgent String?
+ userId String
+
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
+
+ @@map("session")
+}
+
+model Account {
+ id String @id
+ accountId String
+ providerId String
+ userId String
+ accessToken String?
+ refreshToken String?
+ idToken String?
+ accessTokenExpiresAt DateTime?
+ refreshTokenExpiresAt DateTime?
+ scope String?
+ password String?
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
+
+ @@map("account")
+}
+
+model Verification {
+ id String @id
+ identifier String
+ value String
+ expiresAt DateTime
+ createdAt DateTime? @default(now())
+ updatedAt DateTime? @updatedAt
+
+ @@map("verification")
+}
+
+model Organization {
+ id String @id
+ name String
+ slug String? @unique
+ logo String?
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ metadata String?
+
+ members Member[]
+ invitations Invitation[]
+
+ @@map("organization")
+}
+
+model Member {
+ id String @id
+ organizationId String
+ userId String
+ role String
+ createdAt DateTime @default(now())
+
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
+
+ @@map("member")
+}
+
+model Invitation {
+ id String @id
+ organizationId String
+ email String
+ role String?
+ status String
+ expiresAt DateTime
+ inviterId String
+
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
+
+ @@map("invitation")
+}
diff --git a/frontend/server.ts b/frontend/server.ts
new file mode 100644
index 0000000..8df62d9
--- /dev/null
+++ b/frontend/server.ts
@@ -0,0 +1,48 @@
+/**
+ * Custom Next.js server with WebSocket proxy.
+ *
+ * Proxies /ws/** upgrade requests to python-api:8088/ws/**
+ * Same code path for dev and prod — no env-specific routing.
+ */
+
+import { createServer } from "http";
+import { parse } from "url";
+import next from "next";
+import httpProxy from "http-proxy";
+
+const dev = process.env.NODE_ENV !== "production";
+const app = next({ dev });
+const handle = app.getRequestHandler();
+
+const PYTHON_API = process.env.PYTHON_API_URL || "http://python-api:8088";
+
+const proxy = httpProxy.createProxyServer({
+ target: PYTHON_API,
+ ws: true,
+});
+
+proxy.on("error", (err) => {
+ console.error("[ws-proxy] error:", err.message);
+});
+
+app.prepare().then(() => {
+ const server = createServer((req, res) => {
+ const parsedUrl = parse(req.url!, true);
+ handle(req, res, parsedUrl);
+ });
+
+ // Handle WebSocket upgrades
+ server.on("upgrade", (req, socket, head) => {
+ const { pathname } = parse(req.url!, true);
+ if (pathname?.startsWith("/ws/")) {
+ proxy.ws(req, socket, head);
+ } else {
+ socket.destroy();
+ }
+ });
+
+ const port = parseInt(process.env.PORT || "3000", 10);
+ server.listen(port, () => {
+ console.log(`> Ready on http://localhost:${port}`);
+ });
+});
diff --git a/frontend/src/__tests__/utils.test.ts b/frontend/src/__tests__/utils.test.ts
new file mode 100644
index 0000000..7970217
--- /dev/null
+++ b/frontend/src/__tests__/utils.test.ts
@@ -0,0 +1,16 @@
+import { describe, it, expect } from "vitest";
+import { cn } from "@/lib/utils";
+
+describe("cn", () => {
+ it("merges class names", () => {
+ expect(cn("foo", "bar")).toBe("foo bar");
+ });
+
+ it("resolves tailwind conflicts", () => {
+ expect(cn("p-4", "p-2")).toBe("p-2");
+ });
+
+ it("handles conditional classes", () => {
+ expect(cn("base", false && "hidden", "visible")).toBe("base visible");
+ });
+});
diff --git a/frontend/src/app/(auth)/reset/page.tsx b/frontend/src/app/(auth)/reset/page.tsx
new file mode 100644
index 0000000..f2a4703
--- /dev/null
+++ b/frontend/src/app/(auth)/reset/page.tsx
@@ -0,0 +1,132 @@
+"use client";
+
+import { useState } from "react";
+import { useRouter, useSearchParams } from "next/navigation";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+
+export default function ResetPasswordPage() {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+ const token = searchParams.get("token");
+
+ const [password, setPassword] = useState("");
+ const [confirm, setConfirm] = useState("");
+ const [error, setError] = useState("");
+ const [success, setSuccess] = useState(false);
+ const [loading, setLoading] = useState(false);
+
+ if (!token) {
+ return (
+
+
+
+
+ Invalid reset link. Please contact your administrator.
+
+
+
+
+ );
+ }
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+ setError("");
+
+ if (password.length < 8) {
+ setError("Password must be at least 8 characters");
+ return;
+ }
+ if (password !== confirm) {
+ setError("Passwords do not match");
+ return;
+ }
+
+ setLoading(true);
+ try {
+ const res = await fetch("/api/auth/reset-password", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ token, password }),
+ });
+ if (!res.ok) {
+ const data = await res.json();
+ throw new Error(data.error || "Reset failed");
+ }
+ setSuccess(true);
+ setTimeout(() => router.push("/signin"), 2000);
+ } catch (err) {
+ setError(err instanceof Error ? err.message : "Reset failed");
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ if (success) {
+ return (
+
+
+
+
+ Password reset successfully. Redirecting to sign in...
+
+
+
+
+ );
+ }
+
+ return (
+
+
+
+ Reset Password
+
+ Enter your new password
+
+
+
+
+
+
+
+ );
+}
diff --git a/frontend/src/app/(auth)/signin/page.tsx b/frontend/src/app/(auth)/signin/page.tsx
new file mode 100644
index 0000000..f726498
--- /dev/null
+++ b/frontend/src/app/(auth)/signin/page.tsx
@@ -0,0 +1,87 @@
+"use client";
+
+import { useState } from "react";
+import { useRouter } from "next/navigation";
+import { signIn } from "@/lib/auth-client";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+
+export default function SignInPage() {
+ const router = useRouter();
+ const [email, setEmail] = useState("");
+ const [password, setPassword] = useState("");
+ const [error, setError] = useState("");
+ const [loading, setLoading] = useState(false);
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+ setError("");
+ setLoading(true);
+
+ try {
+ const result = await signIn.email({ email, password });
+ if (result.error) {
+ setError(result.error.message || "Invalid email or password");
+ } else {
+ router.push("/projects");
+ }
+ } catch {
+ setError("Unable to connect to server");
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return (
+
+
+
+ PRDforge
+
+ Sign in to your account
+
+
+
+
+
+
+
+ );
+}
diff --git a/frontend/src/app/api/auth/[...all]/route.ts b/frontend/src/app/api/auth/[...all]/route.ts
new file mode 100644
index 0000000..5b67b06
--- /dev/null
+++ b/frontend/src/app/api/auth/[...all]/route.ts
@@ -0,0 +1,4 @@
+import { auth } from "@/lib/auth";
+import { toNextJsHandler } from "better-auth/next-js";
+
+export const { GET, POST } = toNextJsHandler(auth);
diff --git a/frontend/src/app/api/auth/reset-password/route.ts b/frontend/src/app/api/auth/reset-password/route.ts
new file mode 100644
index 0000000..29cd2f3
--- /dev/null
+++ b/frontend/src/app/api/auth/reset-password/route.ts
@@ -0,0 +1,75 @@
+import { NextRequest, NextResponse } from "next/server";
+import { prisma } from "@/lib/db";
+import { auth } from "@/lib/auth";
+
+export async function POST(req: NextRequest) {
+ const body = await req.json();
+ const { token, password } = body;
+
+ if (!token || !password) {
+ return NextResponse.json(
+ { error: "token and password are required" },
+ { status: 400 }
+ );
+ }
+
+ if (password.length < 8) {
+ return NextResponse.json(
+ { error: "Password must be at least 8 characters" },
+ { status: 400 }
+ );
+ }
+
+ try {
+ // Find valid, unused token
+ const rows = await prisma.$queryRawUnsafe<
+ { id: string; user_id: string; expires_at: Date }[]
+ >(
+ `SELECT id, user_id, expires_at FROM password_reset_tokens
+ WHERE token = $1 AND NOT used AND expires_at > now()
+ LIMIT 1`,
+ token
+ );
+
+ if (!rows || rows.length === 0) {
+ return NextResponse.json(
+ { error: "Invalid or expired reset token" },
+ { status: 400 }
+ );
+ }
+
+ const resetToken = rows[0];
+
+ // Mark token as used
+ await prisma.$executeRawUnsafe(
+ `UPDATE password_reset_tokens SET used = true WHERE id = $1::uuid`,
+ resetToken.id
+ );
+
+ // Update password via Better Auth API
+ // Better Auth doesn't expose a direct password update API publicly,
+ // so we update the account table directly
+ const bcrypt = await import("bcryptjs");
+ const hashedPassword = await bcrypt.hash(password, 10);
+
+ await prisma.$executeRawUnsafe(
+ `UPDATE account SET password = $1, "updatedAt" = now()
+ WHERE "userId" = $2 AND "providerId" = 'credential'`,
+ hashedPassword,
+ resetToken.user_id
+ );
+
+ // Revoke all sessions for this user
+ await prisma.$executeRawUnsafe(
+ `DELETE FROM session WHERE "userId" = $1`,
+ resetToken.user_id
+ );
+
+ return NextResponse.json({ success: true });
+ } catch (err) {
+ return NextResponse.json(
+ { error: err instanceof Error ? err.message : "Password reset failed" },
+ { status: 500 }
+ );
+ }
+}
diff --git a/frontend/src/app/api/auth/setup/route.ts b/frontend/src/app/api/auth/setup/route.ts
new file mode 100644
index 0000000..6ca5c5d
--- /dev/null
+++ b/frontend/src/app/api/auth/setup/route.ts
@@ -0,0 +1,80 @@
+import { NextRequest, NextResponse } from "next/server";
+import { auth } from "@/lib/auth";
+import { prisma } from "@/lib/db";
+
+export async function POST(req: NextRequest) {
+ const body = await req.json();
+ const { name, email, password } = body;
+
+ if (!name || !email || !password) {
+ return NextResponse.json(
+ { error: "name, email, and password are required" },
+ { status: 400 }
+ );
+ }
+
+ // Race-safe bootstrap check via INSERT ON CONFLICT
+ try {
+ const result = await prisma.$queryRawUnsafe<{ id: string }[]>(
+ `INSERT INTO prdforge_bootstrap (setup_type, completed)
+ VALUES ('first_user', true)
+ ON CONFLICT (setup_type) DO NOTHING
+ RETURNING id`
+ );
+
+ if (!result || result.length === 0) {
+ return NextResponse.json(
+ { error: "Setup already completed" },
+ { status: 409 }
+ );
+ }
+
+ const bootstrapId = result[0].id;
+
+ // Create first user via Better Auth API
+ try {
+ const ctx = await auth.api.signUpEmail({
+ body: { name, email, password },
+ });
+
+ // Create default organization
+ // Note: org creation via Better Auth API requires auth context
+ // For bootstrap, we create directly
+ const orgId = crypto.randomUUID();
+ await prisma.$executeRawUnsafe(
+ `INSERT INTO organization (id, name, slug, "createdAt", "updatedAt")
+ VALUES ($1, 'Default', 'default', now(), now())`,
+ orgId
+ );
+
+ await prisma.$executeRawUnsafe(
+ `INSERT INTO member (id, "organizationId", "userId", role, "createdAt")
+ VALUES ($1, $2, $3, 'owner', now())`,
+ crypto.randomUUID(),
+ orgId,
+ ctx.user.id
+ );
+
+ return NextResponse.json({
+ success: true,
+ user: { id: ctx.user.id, email: ctx.user.email, name: ctx.user.name },
+ });
+ } catch (err) {
+ // Compensation: remove bootstrap flag on failure
+ await prisma.$executeRawUnsafe(
+ `DELETE FROM prdforge_bootstrap WHERE id = $1`,
+ bootstrapId
+ );
+ throw err;
+ }
+ } catch (err) {
+ if (err instanceof Error && err.message === "Setup already completed") {
+ throw err;
+ }
+ console.error("Setup failed:", err);
+ return NextResponse.json(
+ { error: err instanceof Error ? err.message : "Setup failed" },
+ { status: 500 }
+ );
+ }
+}
diff --git a/frontend/src/app/api/orgs/[slug]/api-key/route.ts b/frontend/src/app/api/orgs/[slug]/api-key/route.ts
new file mode 100644
index 0000000..ba5a741
--- /dev/null
+++ b/frontend/src/app/api/orgs/[slug]/api-key/route.ts
@@ -0,0 +1,54 @@
+import { NextRequest, NextResponse } from "next/server";
+import { prisma } from "@/lib/db";
+import crypto from "crypto";
+
+const ENCRYPTION_SECRET = process.env.API_KEY_ENCRYPTION_SECRET || "dev-encryption-key-change-in-prod";
+
+function encrypt(text: string): string {
+ const key = crypto.scryptSync(ENCRYPTION_SECRET, "salt", 32);
+ const iv = crypto.randomBytes(16);
+ const cipher = crypto.createCipheriv("aes-256-cbc", key, iv);
+ let encrypted = cipher.update(text, "utf8", "hex");
+ encrypted += cipher.final("hex");
+ return iv.toString("hex") + ":" + encrypted;
+}
+
+export async function PUT(
+ req: NextRequest,
+ { params }: { params: Promise<{ slug: string }> }
+) {
+ const { slug } = await params;
+ const body = await req.json();
+ const apiKey = body.api_key?.trim();
+
+ if (!apiKey) {
+ return NextResponse.json({ error: "api_key required" }, { status: 400 });
+ }
+
+ if (!apiKey.startsWith("sk-ant-")) {
+ return NextResponse.json(
+ { error: "Invalid API key format (expected sk-ant-...)" },
+ { status: 400 }
+ );
+ }
+
+ const encrypted = encrypt(apiKey);
+
+ try {
+ await prisma.$executeRawUnsafe(
+ `UPDATE organization SET anthropic_api_key_encrypted = $1, "updatedAt" = now() WHERE slug = $2`,
+ encrypted,
+ slug
+ );
+
+ return NextResponse.json({
+ ok: true,
+ key_hint: `...${apiKey.slice(-4)}`,
+ });
+ } catch (err) {
+ return NextResponse.json(
+ { error: err instanceof Error ? err.message : "Failed to save key" },
+ { status: 500 }
+ );
+ }
+}
diff --git a/frontend/src/app/api/orgs/[slug]/members/[id]/reset-password/route.ts b/frontend/src/app/api/orgs/[slug]/members/[id]/reset-password/route.ts
new file mode 100644
index 0000000..0b76639
--- /dev/null
+++ b/frontend/src/app/api/orgs/[slug]/members/[id]/reset-password/route.ts
@@ -0,0 +1,37 @@
+import { NextRequest, NextResponse } from "next/server";
+import { prisma } from "@/lib/db";
+import crypto from "crypto";
+
+export async function POST(
+ req: NextRequest,
+ { params }: { params: Promise<{ slug: string; id: string }> }
+) {
+ const { id: userId } = await params;
+
+ // Generate a secure reset token
+ const token = crypto.randomBytes(32).toString("hex");
+ const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24h
+
+ try {
+ await prisma.$executeRawUnsafe(
+ `INSERT INTO password_reset_tokens (user_id, token, expires_at)
+ VALUES ($1::uuid, $2, $3)`,
+ userId,
+ token,
+ expiresAt
+ );
+
+ // Return the reset URL — admin shares it manually (no email)
+ const resetUrl = `/reset?token=${token}`;
+
+ return NextResponse.json({
+ reset_url: resetUrl,
+ expires_at: expiresAt.toISOString(),
+ });
+ } catch (err) {
+ return NextResponse.json(
+ { error: err instanceof Error ? err.message : "Failed to create reset token" },
+ { status: 500 }
+ );
+ }
+}
diff --git a/frontend/src/app/api/orgs/[slug]/members/create/route.ts b/frontend/src/app/api/orgs/[slug]/members/create/route.ts
new file mode 100644
index 0000000..a554c4a
--- /dev/null
+++ b/frontend/src/app/api/orgs/[slug]/members/create/route.ts
@@ -0,0 +1,36 @@
+import { NextRequest, NextResponse } from "next/server";
+import { auth } from "@/lib/auth";
+
+export async function POST(
+ req: NextRequest,
+ { params }: { params: Promise<{ slug: string }> }
+) {
+ const { slug } = await params;
+ const body = await req.json();
+ const { name, email, password, role } = body;
+
+ if (!name || !email || !password) {
+ return NextResponse.json(
+ { error: "name, email, and password are required" },
+ { status: 400 }
+ );
+ }
+
+ try {
+ // Create user via Better Auth API (Next.js only — Python never writes auth)
+ const ctx = await auth.api.signUpEmail({
+ body: { name, email, password },
+ });
+
+ return NextResponse.json({
+ user: { id: ctx.user.id, email: ctx.user.email, name: ctx.user.name },
+ org: slug,
+ role: role || "member",
+ });
+ } catch (err) {
+ return NextResponse.json(
+ { error: err instanceof Error ? err.message : "Failed to create user" },
+ { status: 500 }
+ );
+ }
+}
diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css
new file mode 100644
index 0000000..96b9d54
--- /dev/null
+++ b/frontend/src/app/globals.css
@@ -0,0 +1,133 @@
+@import "tailwindcss";
+
+@theme inline {
+ --color-background: var(--bg);
+ --color-foreground: var(--fg);
+ --color-card: var(--card-bg);
+ --color-card-foreground: var(--fg);
+ --color-popover: var(--card-bg);
+ --color-popover-foreground: var(--fg);
+ --color-primary: var(--accent);
+ --color-primary-foreground: #ffffff;
+ --color-secondary: var(--surface);
+ --color-secondary-foreground: var(--fg);
+ --color-muted: var(--surface);
+ --color-muted-foreground: var(--fg-muted);
+ --color-accent: var(--surface);
+ --color-accent-foreground: var(--fg);
+ --color-destructive: #ef4444;
+ --color-destructive-foreground: #ffffff;
+ --color-border: var(--border-color);
+ --color-input: var(--border-color);
+ --color-ring: var(--accent);
+ --radius-sm: 4px;
+ --radius-md: 6px;
+ --radius-lg: 8px;
+ --radius-xl: 12px;
+}
+
+/* Light theme */
+:root {
+ --bg: #f5f5f7;
+ --fg: #1a1a2e;
+ --fg-muted: #6b6b80;
+ --card-bg: #ffffff;
+ --surface: #e8e8ec;
+ --border-color: #d1d1d9;
+ --accent: #6366f1;
+ --accent-hover: #5558e6;
+ --notes-bg: #fef9e7;
+ --notes-border: #e6d88a;
+}
+
+/* Dark theme */
+.dark {
+ --bg: #2b2d35;
+ --fg: #e2e4ea;
+ --fg-muted: #9496ad;
+ --card-bg: #33353f;
+ --surface: #3d3f4a;
+ --border-color: #44465a;
+ --accent: #6366f1;
+ --accent-hover: #5558e6;
+ --notes-bg: #3a3520;
+ --notes-border: #665e3a;
+}
+
+* {
+ border-color: var(--border-color);
+}
+
+body {
+ background-color: var(--bg);
+ color: var(--fg);
+}
+
+/* Markdown styles */
+.markdown-body {
+ color: var(--fg);
+ line-height: 1.7;
+}
+.markdown-body h1 { font-size: 1.5rem; font-weight: 700; margin: 1.5rem 0 0.75rem; }
+.markdown-body h2 { font-size: 1.25rem; font-weight: 600; margin: 1.25rem 0 0.5rem; }
+.markdown-body h3 { font-size: 1.1rem; font-weight: 600; margin: 1rem 0 0.5rem; }
+.markdown-body p { margin: 0.5rem 0; }
+.markdown-body ul { list-style: disc; padding-left: 1.5rem; margin: 0.5rem 0; }
+.markdown-body ol { list-style: decimal; padding-left: 1.5rem; margin: 0.5rem 0; }
+.markdown-body li { margin: 0.25rem 0; }
+.markdown-body strong { font-weight: 600; }
+.markdown-body em { font-style: italic; }
+.markdown-body a { color: var(--accent); text-decoration: underline; }
+.markdown-body blockquote {
+ border-left: 3px solid var(--border-color);
+ padding-left: 1rem;
+ margin: 0.75rem 0;
+ color: var(--fg-muted);
+ font-style: italic;
+}
+.markdown-body code {
+ background: var(--surface);
+ padding: 0.15em 0.4em;
+ border-radius: 4px;
+ font-size: 0.875em;
+ font-family: 'JetBrains Mono', ui-monospace, monospace;
+}
+.markdown-body pre {
+ background: var(--surface);
+ border-radius: 8px;
+ padding: 1rem;
+ overflow-x: auto;
+ margin: 0.75rem 0;
+}
+.markdown-body pre code {
+ background: transparent;
+ padding: 0;
+ font-size: 0.85em;
+ line-height: 1.5;
+}
+.markdown-body table {
+ width: 100%;
+ border-collapse: collapse;
+ margin: 0.75rem 0;
+ font-size: 0.875rem;
+}
+.markdown-body th {
+ border: 1px solid var(--border-color);
+ padding: 0.5rem 0.75rem;
+ text-align: left;
+ font-weight: 600;
+ background: var(--surface);
+}
+.markdown-body td {
+ border: 1px solid var(--border-color);
+ padding: 0.5rem 0.75rem;
+}
+.markdown-body hr {
+ border: none;
+ border-top: 1px solid var(--border-color);
+ margin: 1.5rem 0;
+}
+.markdown-body img {
+ max-width: 100%;
+ border-radius: 8px;
+}
diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx
new file mode 100644
index 0000000..bc47751
--- /dev/null
+++ b/frontend/src/app/layout.tsx
@@ -0,0 +1,42 @@
+import type { Metadata } from "next";
+import { Inter } from "next/font/google";
+import { Toaster } from "sonner";
+import { AuthGuard } from "@/components/auth-guard";
+import "./globals.css";
+
+const inter = Inter({
+ subsets: ["latin"],
+ variable: "--font-inter",
+});
+
+export const metadata: Metadata = {
+ title: "PRDforge",
+ description: "Product Requirements Document management tool",
+};
+
+export default function RootLayout({
+ children,
+}: Readonly<{
+ children: React.ReactNode;
+}>) {
+ // Inline script to prevent flash — reads localStorage before paint
+ const themeScript = `
+ (function() {
+ var t = localStorage.getItem('prdforge-theme');
+ if (t === 'light') return;
+ document.documentElement.classList.add('dark');
+ })();
+ `;
+
+ return (
+
+
+
+
+
+
{children}
+
+
+
+ );
+}
diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx
new file mode 100644
index 0000000..10f2e4e
--- /dev/null
+++ b/frontend/src/app/page.tsx
@@ -0,0 +1,5 @@
+import { redirect } from "next/navigation";
+
+export default function Home() {
+ redirect("/projects");
+}
diff --git a/frontend/src/app/projects/[slug]/page.tsx b/frontend/src/app/projects/[slug]/page.tsx
new file mode 100644
index 0000000..980397a
--- /dev/null
+++ b/frontend/src/app/projects/[slug]/page.tsx
@@ -0,0 +1,683 @@
+"use client";
+
+import { useEffect, useState, useCallback, useRef } from "react";
+import { useParams, useRouter } from "next/navigation";
+import {
+ Settings,
+ FileText,
+ GitBranch,
+ Clock,
+ BarChart3,
+ MessageSquare,
+} from "lucide-react";
+import { TopBar } from "@/components/top-bar";
+import { SectionSidebar } from "@/components/section-sidebar";
+import { SectionViewer } from "@/components/section-viewer";
+import { ChatPanel } from "@/components/chat-panel";
+import { DependencyGraph } from "@/components/dependency-graph";
+import { TokenStatsDashboard } from "@/components/token-stats-dashboard";
+import { EmptyState } from "@/components/empty-state";
+import { LoadingOverlay } from "@/components/loading-overlay";
+import { Badge } from "@/components/ui/badge";
+import { Button } from "@/components/ui/button";
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
+import { fetchProject, fetchSection, fetchTokenStats } from "@/lib/api";
+import type {
+ ProjectDetailResponse,
+ SectionDetailResponse,
+ TokenStats,
+ ProjectSettings,
+} from "@/lib/types";
+
+interface AllComment {
+ id: string;
+ anchor_text: string;
+ body: string;
+ resolved: boolean;
+ created_at: string;
+ section_slug: string;
+ section_title: string;
+}
+
+export default function ProjectDetailPage() {
+ const params = useParams<{ slug: string }>();
+ const router = useRouter();
+ const slug = params.slug;
+
+ const [project, setProject] = useState
(null);
+ const [activeSection, setActiveSection] =
+ useState(null);
+ const [tokenStats, setTokenStats] = useState(null);
+ const [settings, setSettings] = useState(null);
+ const [allComments, setAllComments] = useState([]);
+ const [chatMessages, setChatMessages] = useState<
+ { id: string; role: "user" | "assistant"; content: string; created_at: string; context?: string; tools?: string[] }[]
+ >([]);
+ const [isStreaming, setIsStreaming] = useState(false);
+ const [streamStatus, setStreamStatus] = useState("");
+ const [streamTools, setStreamTools] = useState([]);
+ const [pendingApproval, setPendingApproval] = useState<{ messageId: string; tools: string[] } | null>(null);
+ const streamStatusRef = useRef("");
+ const abortRef = useRef(null);
+ const [selectionContext, setSelectionContext] = useState<{
+ selected_text: string;
+ section_slug: string;
+ section_title: string;
+ } | null>(null);
+ const [loading, setLoading] = useState(true);
+ const [sectionLoading, setSectionLoading] = useState(false);
+ const [activeTab, setActiveTab] = useState("sections");
+
+ const loadComments = useCallback(async () => {
+ try {
+ const res = await fetch(`/api/projects/${slug}/comments`);
+ if (res.ok) {
+ const data = await res.json();
+ setAllComments(data);
+ }
+ } catch {
+ /* ignore */
+ }
+ }, [slug]);
+
+ useEffect(() => {
+ Promise.all([
+ fetchProject(slug),
+ fetch(`/api/projects/${slug}/settings`).then((r) => r.json()),
+ ])
+ .then(([p, s]) => {
+ setProject(p);
+ setSettings(s);
+ if (p.sections.length > 0) {
+ handleSectionSelect(p.sections[0].slug);
+ }
+ })
+ .catch(console.error)
+ .finally(() => setLoading(false));
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [slug]);
+
+ const handleSectionSelect = useCallback(
+ async (sectionSlug: string) => {
+ setSectionLoading(true);
+ try {
+ const data = await fetchSection(slug, sectionSlug);
+ setActiveSection(data);
+ } catch (err) {
+ console.error("Failed to load section:", err);
+ } finally {
+ setSectionLoading(false);
+ }
+ },
+ [slug]
+ );
+
+ const handleTabChange = useCallback(
+ async (tab: string) => {
+ setActiveTab(tab);
+ if (tab === "stats" && !tokenStats) {
+ try {
+ const stats = await fetchTokenStats(slug);
+ setTokenStats(stats);
+ } catch (err) {
+ console.error("Failed to load token stats:", err);
+ }
+ }
+ if (tab === "comments") {
+ loadComments();
+ }
+ },
+ [slug, tokenStats, loadComments]
+ );
+
+ // Load chat messages
+ useEffect(() => {
+ if (!settings?.chat_enabled) return;
+ fetch(`/api/projects/${slug}/chat/messages`)
+ .then((r) => r.json())
+ .then((data) => {
+ // API returns {messages: [...]} not a plain array
+ const msgs = Array.isArray(data) ? data : data.messages || [];
+ setChatMessages(
+ msgs.map((m: Record) => {
+ const meta = (m.metadata || {}) as Record;
+ const sc = meta.selection_context as Record | undefined;
+ const toolEvts = (meta.tool_events || []) as { name: string }[];
+ return {
+ id: m.id as string,
+ role: m.role as "user" | "assistant",
+ content: m.content as string,
+ created_at: m.created_at as string,
+ context: sc?.selected_text || undefined,
+ tools: toolEvts.length > 0 ? toolEvts.map((t) => t.name) : undefined,
+ };
+ })
+ );
+ })
+ .catch(() => {});
+ }, [slug, settings?.chat_enabled]);
+
+ const handleChatSend = useCallback(
+ async (content: string, attachments?: { name: string; type: string; text_content: string }[]) => {
+ // Add user message optimistically, include selection context
+ const userMsg = {
+ id: crypto.randomUUID(),
+ role: "user" as const,
+ content,
+ created_at: new Date().toISOString(),
+ context: selectionContext?.selected_text || undefined,
+ };
+ setChatMessages((prev) => [...prev, userMsg]);
+ setIsStreaming(true);
+ setStreamStatus("thinking");
+ streamStatusRef.current = "thinking";
+ setStreamTools([]);
+
+ const abort = new AbortController();
+ abortRef.current = abort;
+
+ try {
+ const body: Record = { message: content };
+ if (selectionContext) {
+ body.selection_context = {
+ selected_text: selectionContext.selected_text,
+ section_slug: selectionContext.section_slug,
+ section_title: selectionContext.section_title,
+ };
+ }
+ if (attachments && attachments.length > 0) {
+ body.attachments = attachments;
+ }
+
+ const res = await fetch(`/api/projects/${slug}/chat/stream`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify(body),
+ signal: abort.signal,
+ });
+
+ if (!res.ok) {
+ const err = await res.json().catch(() => ({ error: "Chat failed" }));
+ setChatMessages((prev) => [
+ ...prev,
+ {
+ id: crypto.randomUUID(),
+ role: "assistant",
+ content: `Error: ${err.error || res.statusText}`,
+ created_at: new Date().toISOString(),
+ },
+ ]);
+ return;
+ }
+
+ // Read SSE stream
+ const reader = res.body?.getReader();
+ if (!reader) return;
+
+ const decoder = new TextDecoder();
+ let assistantContent = "";
+ const assistantId = crypto.randomUUID();
+ let buffer = "";
+
+ // Add empty assistant message
+ setChatMessages((prev) => [
+ ...prev,
+ { id: assistantId, role: "assistant", content: "", created_at: new Date().toISOString() },
+ ]);
+
+ while (true) {
+ const { done, value } = await reader.read();
+ if (done) break;
+
+ buffer += decoder.decode(value, { stream: true });
+
+ // Process complete SSE blocks (separated by \n\n or \r\n\r\n)
+ const blocks = buffer.split(/\r?\n\r?\n/);
+ buffer = blocks.pop() || ""; // Keep incomplete block in buffer
+
+ for (const block of blocks) {
+ if (!block.trim()) continue;
+ const lines = block.split(/\r?\n/);
+ let eventType = "";
+ let eventData = "";
+ for (const line of lines) {
+ if (line.startsWith("event:")) eventType = line.slice(6).trim();
+ if (line.startsWith("data:")) eventData = line.slice(5).trim();
+ }
+ if (!eventData) continue;
+
+ try {
+ const parsed = JSON.parse(eventData);
+ if (eventType === "status" && parsed.phase) {
+ setStreamStatus(parsed.phase);
+ streamStatusRef.current = parsed.phase;
+ } else if (eventType === "tool" && parsed.name) {
+ setStreamTools((prev) => [...prev, parsed.name]);
+ setStreamStatus(`Using: ${parsed.name.replace(/^mcp__prd-forge__/, "").replace(/_/g, " ")}`);
+ streamStatusRef.current = "tool_use";
+ } else if (eventType === "delta" && parsed.text) {
+ if (streamStatusRef.current !== "writing") {
+ setStreamStatus("writing");
+ streamStatusRef.current = "writing";
+ }
+ assistantContent += parsed.text;
+ setChatMessages((prev) =>
+ prev.map((m) =>
+ m.id === assistantId ? { ...m, content: assistantContent } : m
+ )
+ );
+ } else if (eventType === "approval") {
+ // Tool needs approval — show approval UI
+ const toolName = parsed.name || parsed.tool || "unknown tool";
+ setStreamStatus("approval");
+ streamStatusRef.current = "approval";
+ // Will be handled after stream ends via metadata
+ } else if (eventType === "done" && parsed.message) {
+ // Final message — use the server's complete content + tool events
+ assistantContent = parsed.message.content;
+ const meta = parsed.message.metadata || {};
+ const toolEvents = (meta.tool_events || []).map((t: { name: string }) => t.name);
+ const approvalReqs = meta.approval_requests || [];
+ const needsApproval = !meta.approval_resolved && approvalReqs.length > 0;
+ setChatMessages((prev) =>
+ prev.map((m) =>
+ m.id === assistantId
+ ? { ...m, id: parsed.message.id, content: assistantContent, tools: toolEvents.length > 0 ? toolEvents : undefined }
+ : m
+ )
+ );
+ if (needsApproval) {
+ setPendingApproval({
+ messageId: parsed.message.id,
+ tools: approvalReqs.map((a: { name?: string; tool?: string }) => a.name || a.tool || "tool"),
+ });
+ }
+ }
+ } catch {
+ // ignore unparseable events
+ }
+ }
+ }
+ } catch (err) {
+ setChatMessages((prev) => [
+ ...prev,
+ {
+ id: crypto.randomUUID(),
+ role: "assistant",
+ content: `Error: ${err instanceof Error ? err.message : "Connection failed"}`,
+ created_at: new Date().toISOString(),
+ },
+ ]);
+ } finally {
+ setIsStreaming(false);
+ setStreamStatus("");
+ setStreamTools([]);
+ setSelectionContext(null);
+ // Auto-refresh active section + project (Claude may have edited content)
+ if (activeSection) {
+ handleSectionSelect(activeSection.section.slug);
+ }
+ fetchProject(slug).then(setProject).catch(() => {});
+ }
+ },
+ [slug, selectionContext]
+ );
+
+ const handleChatStop = useCallback(() => {
+ abortRef.current?.abort();
+ }, []);
+
+ const handleApprove = useCallback(
+ async (messageId: string) => {
+ setPendingApproval(null);
+ setIsStreaming(true);
+ setStreamStatus("thinking");
+ streamStatusRef.current = "thinking";
+ setStreamTools([]);
+
+ const abort = new AbortController();
+ abortRef.current = abort;
+
+ try {
+ const res = await fetch(`/api/projects/${slug}/chat/approve`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ assistant_message_id: messageId }),
+ signal: abort.signal,
+ });
+
+ if (!res.ok) {
+ const err = await res.json().catch(() => ({ error: "Approve failed" }));
+ setChatMessages((prev) => [
+ ...prev,
+ { id: crypto.randomUUID(), role: "assistant", content: `Error: ${err.error || res.statusText}`, created_at: new Date().toISOString() },
+ ]);
+ return;
+ }
+
+ const reader = res.body?.getReader();
+ if (!reader) return;
+
+ const decoder = new TextDecoder();
+ let assistantContent = "";
+ const assistantId = crypto.randomUUID();
+ let buffer = "";
+
+ setChatMessages((prev) => [
+ ...prev,
+ { id: assistantId, role: "assistant", content: "", created_at: new Date().toISOString() },
+ ]);
+
+ while (true) {
+ const { done, value } = await reader.read();
+ if (done) break;
+ buffer += decoder.decode(value, { stream: true });
+ const blocks = buffer.split(/\r?\n\r?\n/);
+ buffer = blocks.pop() || "";
+ for (const block of blocks) {
+ if (!block.trim()) continue;
+ const lines = block.split(/\r?\n/);
+ let eventType = "";
+ let eventData = "";
+ for (const line of lines) {
+ if (line.startsWith("event:")) eventType = line.slice(6).trim();
+ if (line.startsWith("data:")) eventData = line.slice(5).trim();
+ }
+ if (!eventData) continue;
+ try {
+ const parsed = JSON.parse(eventData);
+ if (eventType === "delta" && parsed.text) {
+ assistantContent += parsed.text;
+ setChatMessages((prev) =>
+ prev.map((m) => (m.id === assistantId ? { ...m, content: assistantContent } : m))
+ );
+ } else if (eventType === "tool" && parsed.name) {
+ setStreamTools((prev) => [...prev, parsed.name]);
+ } else if (eventType === "done" && parsed.message) {
+ assistantContent = parsed.message.content;
+ const meta = parsed.message.metadata || {};
+ const toolEvents = (meta.tool_events || []).map((t: { name: string }) => t.name);
+ setChatMessages((prev) =>
+ prev.map((m) =>
+ m.id === assistantId
+ ? { ...m, id: parsed.message.id, content: assistantContent, tools: toolEvents.length > 0 ? toolEvents : undefined }
+ : m
+ )
+ );
+ }
+ } catch { /* ignore */ }
+ }
+ }
+ } catch { /* aborted or error */ } finally {
+ setIsStreaming(false);
+ setStreamStatus("");
+ setStreamTools([]);
+ if (activeSection) handleSectionSelect(activeSection.section.slug);
+ fetchProject(slug).then(setProject).catch(() => {});
+ }
+ },
+ [slug, activeSection, handleSectionSelect]
+ );
+
+ // Called when text is selected in SectionViewer — injects into chat
+ const handleSelectionContext = useCallback(
+ (text: string) => {
+ if (activeSection) {
+ setSelectionContext({
+ selected_text: text,
+ section_slug: activeSection.section.slug,
+ section_title: activeSection.section.title,
+ });
+ }
+ },
+ [activeSection]
+ );
+
+ if (loading) {
+ return (
+
+
+
+
+ );
+ }
+
+ if (!project) {
+ return (
+
+
+ router.push("/projects"),
+ }}
+ />
+
+ );
+ }
+
+ return (
+
+
+
+
+
+
+
+
+
+
+ Sections
+
+
+
+ Comments
+
+
+
+ Dependencies
+
+
+
+ Changelog
+
+
+
+ Stats
+
+
+
+
+
+
+
+
+
+ {sectionLoading ? (
+
+ ) : activeSection ? (
+ {
+ if (activeSection)
+ handleSectionSelect(activeSection.section.slug);
+ }}
+ onTextSelected={handleSelectionContext}
+ />
+ ) : (
+
+ )}
+
+
+ {/* Comments tab — all comments across project */}
+
+ {allComments.length === 0 ? (
+
+ ) : (
+
+ {allComments.map((c) => (
+
+
+
+
+ {c.resolved && (
+
+ Resolved
+
+ )}
+
+ {new Date(c.created_at).toLocaleString()}
+
+
+
+
+ {c.anchor_text.length > 80
+ ? c.anchor_text.slice(0, 80) + "..."
+ : c.anchor_text}
+
+
{c.body}
+
+ ))}
+
+ )}
+
+
+
+ { handleSectionSelect(s); setActiveTab("sections"); }}
+ />
+
+
+
+ {project.changelog.length === 0 ? (
+
+ ) : (
+
+ {project.changelog.map((entry, i) => (
+
+
+
+
+ {entry.section_title}
+ {" "}
+
+ rev {entry.revision_number}
+
+
+ {entry.change_description && (
+
+ {entry.change_description}
+
+ )}
+
+
+ {new Date(entry.created_at).toLocaleString()}
+
+
+ ))}
+
+ )}
+
+
+
+ {tokenStats ? (
+
+
+
+ ) : (
+
+ )}
+
+
+
+
+ {/* Chat panel */}
+ {settings?.chat_enabled && (
+
setSelectionContext(null)}
+ />
+ )}
+
+
+ );
+}
diff --git a/frontend/src/app/projects/[slug]/settings/page.tsx b/frontend/src/app/projects/[slug]/settings/page.tsx
new file mode 100644
index 0000000..250e9af
--- /dev/null
+++ b/frontend/src/app/projects/[slug]/settings/page.tsx
@@ -0,0 +1,453 @@
+"use client";
+
+import { useEffect, useState } from "react";
+import { useParams, useRouter } from "next/navigation";
+import {
+ ArrowLeft,
+ Check,
+ CheckCircle2,
+ XCircle,
+ ExternalLink,
+} from "lucide-react";
+import { toast } from "sonner";
+import { TopBar } from "@/components/top-bar";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "@/components/ui/select";
+import { LoadingOverlay } from "@/components/loading-overlay";
+
+const PROVIDERS = ["claude_cli", "anthropic_api"] as const;
+const MODELS = ["sonnet", "opus", "haiku"] as const;
+
+interface Settings {
+ claude_comment_replies: boolean;
+ chat_enabled: boolean;
+ chat_provider: string;
+ chat_model: string;
+}
+
+interface ProviderStatus {
+ claude_cli: { installed: boolean; logged_in: boolean };
+ anthropic_api: { configured: boolean; key_hint: string };
+}
+
+export default function SettingsPage() {
+ const params = useParams<{ slug: string }>();
+ const router = useRouter();
+ const slug = params.slug;
+
+ const [settings, setSettings] = useState(null);
+ const [providerStatus, setProviderStatus] = useState(
+ null
+ );
+ const [loading, setLoading] = useState(true);
+ const [saving, setSaving] = useState(false);
+ const [apiKey, setApiKey] = useState("");
+ const [savingKey, setSavingKey] = useState(false);
+ const [loggingIn, setLoggingIn] = useState(false);
+ const [showCodeInput, setShowCodeInput] = useState(false);
+ const [loginCode, setLoginCode] = useState("");
+
+ useEffect(() => {
+ Promise.all([
+ fetch(`/api/projects/${slug}/settings`).then((r) => r.json()),
+ fetch("/api/chat/provider-status").then((r) => r.json()),
+ ])
+ .then(([s, p]) => {
+ setSettings(s);
+ setProviderStatus(p);
+ })
+ .catch(console.error)
+ .finally(() => setLoading(false));
+ }, [slug]);
+
+ const handleSave = async () => {
+ if (!settings) return;
+ setSaving(true);
+ try {
+ const res = await fetch(`/api/projects/${slug}/settings`, {
+ method: "PUT",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify(settings),
+ });
+ if (!res.ok) {
+ const data = await res.json();
+ toast.error(data.error || "Failed to save");
+ return;
+ }
+ const updated = await res.json();
+ setSettings(updated);
+ toast.success("Settings saved");
+ } catch {
+ toast.error("Failed to save settings");
+ } finally {
+ setSaving(false);
+ }
+ };
+
+ const update = (patch: Partial) => {
+ setSettings((prev) => (prev ? { ...prev, ...patch } : prev));
+ };
+
+ const handleCliLogin = async () => {
+ setLoggingIn(true);
+ try {
+ const res = await fetch("/api/chat/cli-login", { method: "POST" });
+ const data = await res.json();
+ const oauthUrl = data.oauth_url || data.url;
+ if (oauthUrl) {
+ window.open(oauthUrl, "_blank");
+ setShowCodeInput(true);
+ toast.info(
+ "Complete login in the browser tab. Then paste the code below."
+ );
+ } else {
+ toast.error("No OAuth URL returned");
+ }
+ } catch {
+ toast.error("Failed to start CLI login");
+ } finally {
+ setLoggingIn(false);
+ }
+ };
+
+ const handleCliLoginCode = async () => {
+ if (!loginCode.trim()) return;
+ try {
+ const res = await fetch("/api/chat/cli-login-code", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ code: loginCode.trim() }),
+ });
+ if (res.ok) {
+ toast.success("Claude CLI logged in");
+ setLoginCode("");
+ setShowCodeInput(false);
+ const status = await fetch("/api/chat/provider-status").then((r) =>
+ r.json()
+ );
+ setProviderStatus(status);
+ } else {
+ const data = await res.json();
+ toast.error(data.error || "Login failed");
+ }
+ } catch {
+ toast.error("Login code exchange failed");
+ }
+ };
+
+ const handleSaveApiKey = async () => {
+ if (!apiKey.trim()) return;
+ setSavingKey(true);
+ try {
+ const res = await fetch("/api/orgs/default/api-key", {
+ method: "PUT",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ api_key: apiKey.trim() }),
+ });
+ if (res.ok) {
+ toast.success("API key saved");
+ setApiKey("");
+ const status = await fetch("/api/chat/provider-status").then((r) =>
+ r.json()
+ );
+ setProviderStatus(status);
+ } else {
+ const data = await res.json();
+ toast.error(data.error || "Failed to save key");
+ }
+ } catch {
+ toast.error("Failed to save API key");
+ } finally {
+ setSavingKey(false);
+ }
+ };
+
+ if (loading) {
+ return (
+
+
+
+
+ );
+ }
+
+ if (!settings) {
+ return (
+
+
+
+ Failed to load settings.
+
+
+ );
+ }
+
+ return (
+
+
+
+
+
+
+
+
Project Settings
+
+ {/* Features */}
+
+
+ Features
+
+
+
+
+
Comment Auto-Replies
+
+ Claude auto-replies when resolving comments
+
+
+
+
+
+
+
+
Chat Panel
+
+ Enable AI chat for this project
+
+
+
+
+
+
+
+ {/* Chat Configuration */}
+
+
+ Chat Configuration
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Provider Authentication */}
+
+
+
+ Provider Authentication
+
+
+
+ {/* Claude CLI */}
+
+
Claude CLI
+
+ {providerStatus?.claude_cli.installed ? (
+
+ ) : (
+
+ )}
+
+ {providerStatus?.claude_cli.installed
+ ? "Installed"
+ : "Not installed"}
+
+
+
+ {providerStatus?.claude_cli.logged_in ? (
+
+ ) : (
+
+ )}
+
+ {providerStatus?.claude_cli.logged_in
+ ? "Logged in"
+ : "Not logged in"}
+
+
+ {providerStatus?.claude_cli.installed && (
+
+
+ {showCodeInput && (
+
+ setLoginCode(e.target.value)}
+ autoComplete="off"
+ className="text-sm h-9"
+ />
+
+
+ )}
+
+ )}
+
+
+ {/* Divider */}
+
+
+ {/* Anthropic API */}
+
+
Anthropic API Key
+
+ {providerStatus?.anthropic_api.configured ? (
+ <>
+
+
+ Configured (
+ {providerStatus.anthropic_api.key_hint})
+
+ >
+ ) : (
+ <>
+
+
+ Not configured
+
+ >
+ )}
+
+
+ setApiKey(e.target.value)}
+ type="password"
+ className="text-sm h-9"
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/frontend/src/app/projects/page.tsx b/frontend/src/app/projects/page.tsx
new file mode 100644
index 0000000..4489de6
--- /dev/null
+++ b/frontend/src/app/projects/page.tsx
@@ -0,0 +1,238 @@
+"use client";
+
+import { useEffect, useState } from "react";
+import { useRouter } from "next/navigation";
+import { FolderOpen, Plus, Check } from "lucide-react";
+import { TopBar } from "@/components/top-bar";
+import { Button } from "@/components/ui/button";
+import {
+ Card,
+ CardContent,
+ CardDescription,
+ CardHeader,
+ CardTitle,
+} from "@/components/ui/card";
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+ DialogTrigger,
+} from "@/components/ui/dialog";
+import { Input } from "@/components/ui/input";
+import { Textarea } from "@/components/ui/textarea";
+import { EmptyState } from "@/components/empty-state";
+import { LoadingOverlay } from "@/components/loading-overlay";
+import { fetchProjects, createProject, fetchTemplates } from "@/lib/api";
+import type { TemplateInfo } from "@/lib/api";
+import type { Project } from "@/lib/types";
+
+export default function ProjectsPage() {
+ const router = useRouter();
+ const [projects, setProjects] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [dialogOpen, setDialogOpen] = useState(false);
+ const [name, setName] = useState("");
+ const [description, setDescription] = useState("");
+ const [templateId, setTemplateId] = useState("blank");
+ const [templates, setTemplates] = useState([]);
+ const [creating, setCreating] = useState(false);
+
+ useEffect(() => {
+ fetchProjects()
+ .then(setProjects)
+ .catch(console.error)
+ .finally(() => setLoading(false));
+ fetchTemplates().then(setTemplates).catch(console.error);
+ }, []);
+
+ const handleCreate = async () => {
+ if (!name.trim()) return;
+ setCreating(true);
+ try {
+ const project = await createProject({
+ name: name.trim(),
+ description: description.trim(),
+ template_id: templateId,
+ });
+ setProjects((prev) => [...prev, project]);
+ setDialogOpen(false);
+ setName("");
+ setDescription("");
+ setTemplateId("blank");
+ router.push(`/projects/${project.slug}`);
+ } catch (err) {
+ console.error("Failed to create project:", err);
+ } finally {
+ setCreating(false);
+ }
+ };
+
+ return (
+
+
+
+
+
+
+
+
Projects
+
+ Manage your product requirement documents
+
+
+
+
+
+
+ {loading ? (
+
+ ) : projects.length === 0 ? (
+
setDialogOpen(true),
+ }}
+ />
+ ) : (
+
+ {projects.map((project) => (
+
+ router.push(`/projects/${project.slug}`)
+ }
+ >
+
+
+ {project.name}
+
+ {project.description && (
+
+ {project.description}
+
+ )}
+
+
+
+
+ {project.section_count}{" "}
+ {project.section_count === 1
+ ? "section"
+ : "sections"}
+
+
+ {project.total_words} words
+
+
+
+
+ ))}
+
+ )}
+
+
+
+ );
+}
diff --git a/frontend/src/components/auth-guard.tsx b/frontend/src/components/auth-guard.tsx
new file mode 100644
index 0000000..d151a91
--- /dev/null
+++ b/frontend/src/components/auth-guard.tsx
@@ -0,0 +1,32 @@
+"use client";
+
+import { useEffect } from "react";
+import { useRouter, usePathname } from "next/navigation";
+import { useSession } from "@/lib/auth-client";
+import { LoadingOverlay } from "@/components/loading-overlay";
+
+const PUBLIC_PATHS = ["/signin", "/reset"];
+
+export function AuthGuard({ children }: { children: React.ReactNode }) {
+ const { data: session, isPending } = useSession();
+ const router = useRouter();
+ const pathname = usePathname();
+
+ const isPublic = PUBLIC_PATHS.some((p) => pathname.startsWith(p));
+
+ useEffect(() => {
+ if (!isPending && !session && !isPublic) {
+ router.push("/signin");
+ }
+ }, [session, isPending, isPublic, router]);
+
+ if (isPending) {
+ return ;
+ }
+
+ if (!session && !isPublic) {
+ return ;
+ }
+
+ return <>{children}>;
+}
diff --git a/frontend/src/components/chat-panel.tsx b/frontend/src/components/chat-panel.tsx
new file mode 100644
index 0000000..4a68294
--- /dev/null
+++ b/frontend/src/components/chat-panel.tsx
@@ -0,0 +1,339 @@
+"use client";
+
+import { useEffect, useRef, useState } from "react";
+import { Send, Loader2, X, ChevronDown, ChevronRight, Wrench, Brain, PenLine, Paperclip, Square, ShieldCheck } from "lucide-react";
+import { Button } from "@/components/ui/button";
+import { Textarea } from "@/components/ui/textarea";
+import { MarkdownRenderer } from "@/components/markdown-renderer";
+import { cn } from "@/lib/utils";
+interface ChatMsg {
+ id: string;
+ role: "user" | "assistant" | "system" | "tool";
+ content: string;
+ created_at: string;
+ context?: string;
+ tools?: string[];
+}
+
+interface ChatAttachment {
+ name: string;
+ type: string;
+ text_content: string;
+}
+
+interface ChatPanelProps {
+ projectSlug: string;
+ messages: ChatMsg[];
+ onSend: (content: string, attachments?: ChatAttachment[]) => void;
+ onStop?: () => void;
+ onApprove?: (messageId: string) => void;
+ pendingApproval?: { messageId: string; tools: string[] } | null;
+ isStreaming?: boolean;
+ streamStatus?: string;
+ streamTools?: string[];
+ selectionContext?: { selected_text: string; section_slug: string; section_title: string } | null;
+ onClearSelection?: () => void;
+}
+
+export function ChatPanel({
+ messages,
+ onSend,
+ onStop,
+ onApprove,
+ pendingApproval,
+ isStreaming = false,
+ streamStatus = "",
+ streamTools = [],
+ selectionContext,
+ onClearSelection,
+}: ChatPanelProps) {
+ const [input, setInput] = useState("");
+ const [attachments, setAttachments] = useState([]);
+ const fileInputRef = useRef(null);
+ const messagesEndRef = useRef(null);
+
+ // Auto-scroll on new messages or streaming updates
+ useEffect(() => {
+ messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
+ }, [messages, isStreaming]);
+
+ const handleSubmit = () => {
+ const trimmed = input.trim();
+ if (!trimmed || isStreaming) return;
+ onSend(trimmed, attachments.length > 0 ? attachments : undefined);
+ setInput("");
+ setAttachments([]);
+ onClearSelection?.();
+ };
+
+ const handleFileSelect = async (e: React.ChangeEvent) => {
+ const files = e.target.files;
+ if (!files) return;
+ const newAttachments: ChatAttachment[] = [];
+ for (const file of Array.from(files)) {
+ if (file.size > 200_000) {
+ continue; // Skip files > 200KB
+ }
+ const text = await file.text();
+ newAttachments.push({
+ name: file.name,
+ type: file.type || "text/plain",
+ text_content: text.slice(0, 12_000),
+ });
+ }
+ setAttachments((prev) => [...prev, ...newAttachments]);
+ if (fileInputRef.current) fileInputRef.current.value = "";
+ };
+
+ const handleKeyDown = (e: React.KeyboardEvent) => {
+ if (e.key === "Enter" && !e.shiftKey) {
+ e.preventDefault();
+ handleSubmit();
+ }
+ };
+
+ return (
+
+
+
Chat
+
+
+ {/* Messages */}
+
+ {messages.length === 0 && (
+
+ Select text in a section to add context, then ask questions or request changes.
+
+ )}
+ {messages.map((msg) => (
+
+ {/* Selection context shown above user message */}
+ {msg.role === "user" && msg.context && (
+
+ “{msg.context.length > 100 ? msg.context.slice(0, 100) + "..." : msg.context}”
+
+ )}
+
+ {msg.role === "user" ? (
+ msg.content
+ ) : (
+ <>
+ {msg.tools && msg.tools.length > 0 && (
+
+ )}
+
+ >
+ )}
+
+
+ ))}
+ {isStreaming && (
+
+ )}
+ {pendingApproval && !isStreaming && (
+
+
+
+ Tool approval needed
+
+
+ The following tools need permission to run:
+
+
+ {pendingApproval.tools.map((tool, i) => (
+
+
+ {prettifyToolName(tool)}
+
+ ))}
+
+
+
+ )}
+
+
+
+ {/* Selection context */}
+ {selectionContext && (
+
+
+
+ Context from: {selectionContext.section_title}
+
+
+
+
+ “{selectionContext.selected_text}”
+
+
+ )}
+
+ {/* Attachments preview */}
+ {attachments.length > 0 && (
+
+ {attachments.map((att, i) => (
+
+
+
{att.name}
+
+
+ ))}
+
+ )}
+
+ {/* Input */}
+
+
+ );
+}
+
+function ToolCallsSummary({ tools }: { tools: string[] }) {
+ const [expanded, setExpanded] = useState(false);
+ return (
+
+
+ {expanded && (
+
+ {tools.map((tool, i) => (
+
+ {prettifyToolName(tool)}
+
+ ))}
+
+ )}
+
+ );
+}
+
+function prettifyToolName(name: string): string {
+ return name
+ .replace(/^mcp__prd-forge__/, "")
+ .replace(/^mcp__/, "")
+ .replace(/_/g, " ");
+}
+
+function StreamingIndicator({ status, tools }: { status: string; tools: string[] }) {
+ const [expanded, setExpanded] = useState(false);
+
+ const isToolUse = status.startsWith("Using:") || status === "tool_use";
+
+ const statusIcon =
+ status === "thinking" ? :
+ isToolUse ? :
+ status === "writing" ? :
+ status === "approval" ? :
+ ;
+
+ const statusText =
+ status === "thinking" ? "Thinking..." :
+ status.startsWith("Using:") ? status :
+ status === "tool_use" ? `Using: ${prettifyToolName(tools[tools.length - 1] || "")}` :
+ status === "writing" ? "Writing..." :
+ status === "approval" ? "Waiting for approval..." :
+ "Processing...";
+
+ return (
+
+
+ {statusIcon}
+ {statusText}
+
+
+ {tools.length > 0 && (
+
+
+ {expanded && (
+
+ {tools.map((tool, i) => (
+
+
+ {prettifyToolName(tool)}
+
+ ))}
+
+ )}
+
+ )}
+
+ );
+}
diff --git a/frontend/src/components/dependency-graph.tsx b/frontend/src/components/dependency-graph.tsx
new file mode 100644
index 0000000..faa5aad
--- /dev/null
+++ b/frontend/src/components/dependency-graph.tsx
@@ -0,0 +1,369 @@
+"use client";
+
+import { useEffect, useRef, useState, useCallback, useMemo } from "react";
+import { ArrowRight, LayoutGrid, Network, X } from "lucide-react";
+import { Badge } from "@/components/ui/badge";
+import { Button } from "@/components/ui/button";
+import { cn } from "@/lib/utils";
+
+interface Dependency {
+ from_slug: string;
+ to_slug: string;
+ type?: string;
+ dependency_type?: string;
+ description?: string;
+}
+
+interface Section {
+ slug: string;
+ title: string;
+ status: string;
+ summary?: string;
+ word_count?: number;
+}
+
+interface DependencyGraphProps {
+ dependencies?: Dependency[];
+ sections?: Section[];
+ className?: string;
+ onSectionClick?: (slug: string) => void;
+}
+
+const DEP_TYPE_COLORS: Record = {
+ references: "#6366f1",
+ implements: "#22c55e",
+ blocks: "#ef6b6b",
+ extends: "#38bdf8",
+};
+
+const STATUS_COLORS: Record = {
+ approved: "#22c55e",
+ in_progress: "#3b82f6",
+ review: "#f59e0b",
+ draft: "#9496ad",
+ outdated: "#ef4444",
+};
+
+// --- List View ---
+function ListView({ dependencies, sections, onSectionClick }: {
+ dependencies: Dependency[]; sections: Section[]; onSectionClick?: (slug: string) => void;
+}) {
+ const sectionMap = new Map(sections.map((s) => [s.slug, s]));
+ const grouped = new Map();
+ for (const dep of dependencies) {
+ if (!grouped.has(dep.from_slug)) grouped.set(dep.from_slug, []);
+ grouped.get(dep.from_slug)!.push(dep);
+ }
+ return (
+
+ {Array.from(grouped.entries()).map(([fromSlug, deps]) => (
+
+
+
+ {deps.map((dep, i) => {
+ const t = dep.dependency_type || dep.type || "references";
+ return (
+
+
+
{t}
+
+
+ );
+ })}
+
+
+ ))}
+
+ );
+}
+
+// --- Graph View ---
+interface GNode {
+ slug: string; title: string; status: string; summary: string; wordCount: number;
+ x: number; y: number; vx: number; vy: number; r: number;
+}
+
+function wrapText(text: string, maxCharsPerLine: number): string[] {
+ const words = text.split(" ");
+ const lines: string[] = [];
+ let current = "";
+ for (const word of words) {
+ if (current.length + word.length + 1 > maxCharsPerLine && current) {
+ lines.push(current);
+ current = word;
+ } else {
+ current = current ? current + " " + word : word;
+ }
+ }
+ if (current) lines.push(current);
+ // Max 3 lines, truncate last
+ if (lines.length > 3) {
+ lines.length = 3;
+ lines[2] = lines[2].slice(0, maxCharsPerLine - 3) + "...";
+ }
+ return lines;
+}
+
+function GraphView({ dependencies, sections, onSectionClick }: {
+ dependencies: Dependency[]; sections: Section[]; onSectionClick?: (slug: string) => void;
+}) {
+ const svgRef = useRef(null);
+ const [nodes, setNodes] = useState([]);
+ const [dragging, setDragging] = useState(null);
+ const [popup, setPopup] = useState(null);
+ const frameRef = useRef(0);
+ const iterRef = useRef(0);
+
+ const W = 1000, H = 700;
+ const NODE_R = 42;
+
+ useEffect(() => {
+ if (!sections.length) return;
+ const init: GNode[] = sections.map((s, i) => {
+ const angle = (2 * Math.PI * i) / sections.length;
+ const r = Math.min(W, H) * 0.3;
+ return {
+ slug: s.slug, title: s.title, status: s.status,
+ summary: s.summary || "", wordCount: s.word_count || 0,
+ x: W / 2 + r * Math.cos(angle), y: H / 2 + r * Math.sin(angle),
+ vx: 0, vy: 0, r: NODE_R,
+ };
+ });
+ iterRef.current = 0;
+ setNodes(init);
+ }, [sections]);
+
+ useEffect(() => {
+ if (!nodes.length) return;
+ const tick = () => {
+ if (iterRef.current > 350) return;
+ iterRef.current++;
+ setNodes((prev) => {
+ const ns = prev.map((n) => ({ ...n }));
+ // Repulsion
+ for (let i = 0; i < ns.length; i++) {
+ for (let j = i + 1; j < ns.length; j++) {
+ const dx = ns[j].x - ns[i].x, dy = ns[j].y - ns[i].y;
+ const d = Math.max(Math.sqrt(dx * dx + dy * dy), 10);
+ const f = 15000 / (d * d);
+ ns[i].vx -= (dx / d) * f; ns[i].vy -= (dy / d) * f;
+ ns[j].vx += (dx / d) * f; ns[j].vy += (dy / d) * f;
+ }
+ }
+ // Edge attraction
+ for (const dep of dependencies) {
+ const a = ns.find((n) => n.slug === dep.from_slug);
+ const b = ns.find((n) => n.slug === dep.to_slug);
+ if (!a || !b) continue;
+ const dx = b.x - a.x, dy = b.y - a.y;
+ const d = Math.max(Math.sqrt(dx * dx + dy * dy), 10);
+ const f = (d - 160) * 0.025;
+ a.vx += (dx / d) * f; a.vy += (dy / d) * f;
+ b.vx -= (dx / d) * f; b.vy -= (dy / d) * f;
+ }
+ // Center gravity
+ for (const n of ns) { n.vx += (W / 2 - n.x) * 0.006; n.vy += (H / 2 - n.y) * 0.006; }
+ // Apply
+ for (const n of ns) {
+ if (n.slug === dragging) continue;
+ n.vx *= 0.55; n.vy *= 0.55;
+ n.x = Math.max(NODE_R + 10, Math.min(W - NODE_R - 10, n.x + n.vx));
+ n.y = Math.max(NODE_R + 10, Math.min(H - NODE_R - 10, n.y + n.vy));
+ }
+ return ns;
+ });
+ if (iterRef.current <= 350) frameRef.current = requestAnimationFrame(tick);
+ };
+ frameRef.current = requestAnimationFrame(tick);
+ return () => cancelAnimationFrame(frameRef.current);
+ }, [nodes.length, dependencies, dragging]);
+
+ const handleMouseMove = useCallback((e: React.MouseEvent) => {
+ if (!dragging || !svgRef.current) return;
+ const rect = svgRef.current.getBoundingClientRect();
+ const x = (e.clientX - rect.left) * (W / rect.width);
+ const y = (e.clientY - rect.top) * (H / rect.height);
+ setNodes((prev) => prev.map((n) => n.slug === dragging ? { ...n, x, y, vx: 0, vy: 0 } : n));
+ }, [dragging]);
+
+ const nodeMap = new Map(nodes.map((n) => [n.slug, n]));
+
+ // Curved path between two nodes
+ const edgePath = (from: GNode, to: GNode): string => {
+ const dx = to.x - from.x, dy = to.y - from.y;
+ const d = Math.sqrt(dx * dx + dy * dy) || 1;
+ const nx = dx / d, ny = dy / d;
+ // Start/end at circle edge
+ const x1 = from.x + nx * from.r, y1 = from.y + ny * from.r;
+ const x2 = to.x - nx * to.r, y2 = to.y - ny * to.r;
+ // Control point offset perpendicular for curve
+ const cx = (x1 + x2) / 2 - ny * 25;
+ const cy = (y1 + y2) / 2 + nx * 25;
+ return `M${x1},${y1} Q${cx},${cy} ${x2},${y2}`;
+ };
+
+ return (
+
+
+
+ {/* Popup card */}
+ {popup && (
+
+
+
+
+
+
+
+
+ {popup.summary && (
+
{popup.summary}
+ )}
+
+ {popup.status}
+ {popup.wordCount > 0 && {popup.wordCount} words}
+
+
+ )}
+
+ );
+}
+
+// --- Main Component ---
+export function DependencyGraph({ dependencies = [], sections = [], className, onSectionClick }: DependencyGraphProps) {
+ const [view, setView] = useState<"graph" | "list">("graph");
+
+ if (!sections.length || !dependencies.length) {
+ return (
+
+
No Dependencies
+
Add dependencies between sections to see them here.
+
+ );
+ }
+
+ return (
+
+
+
+
Dependencies
+
+ {dependencies.length} edges · {sections.length} sections
+ {view === "graph" && " — click node for details, drag to rearrange"}
+
+
+
+
+
+
+
+
+ {view === "graph" && (
+
+
+ {Object.entries(DEP_TYPE_COLORS).map(([type, color]) => (
+
+ ))}
+
+
+
+ )}
+
+ {view === "list" &&
}
+
+ );
+}
diff --git a/frontend/src/components/empty-state.tsx b/frontend/src/components/empty-state.tsx
new file mode 100644
index 0000000..f0aa0eb
--- /dev/null
+++ b/frontend/src/components/empty-state.tsx
@@ -0,0 +1,42 @@
+import type { LucideIcon } from "lucide-react";
+import { Button } from "@/components/ui/button";
+import { cn } from "@/lib/utils";
+
+interface EmptyStateProps {
+ icon: LucideIcon;
+ title: string;
+ description: string;
+ action?: {
+ label: string;
+ onClick: () => void;
+ };
+ className?: string;
+}
+
+export function EmptyState({
+ icon: Icon,
+ title,
+ description,
+ action,
+ className,
+}: EmptyStateProps) {
+ return (
+
+
+
{title}
+
+ {description}
+
+ {action && (
+
+ )}
+
+ );
+}
diff --git a/frontend/src/components/error-boundary.tsx b/frontend/src/components/error-boundary.tsx
new file mode 100644
index 0000000..e8ac505
--- /dev/null
+++ b/frontend/src/components/error-boundary.tsx
@@ -0,0 +1,143 @@
+"use client";
+
+import { useEffect, useState } from "react";
+import { AlertTriangle, RefreshCw } from "lucide-react";
+import { Button } from "@/components/ui/button";
+
+interface ErrorBoundaryFallbackProps {
+ error: Error;
+ onRetry: () => void;
+}
+
+export function ErrorBoundaryFallback({
+ error,
+ onRetry,
+}: ErrorBoundaryFallbackProps) {
+ return (
+
+
+
+
Something went wrong
+
+ {error.message}
+
+
+
+
+ );
+}
+
+interface APIDownBannerProps {
+ onRetry: () => void;
+ retryIn?: number;
+}
+
+export function APIDownBanner({ onRetry, retryIn }: APIDownBannerProps) {
+ return (
+
+
+
+
+ Unable to reach the server. Your unsaved changes are preserved.
+
+
+
+ {retryIn !== undefined && (
+
+ Retrying in {retryIn}s...
+
+ )}
+
+
+
+ );
+}
+
+interface SessionExpiredDialogProps {
+ onSignIn: () => void;
+}
+
+export function SessionExpiredDialog({ onSignIn }: SessionExpiredDialogProps) {
+ return (
+
+
+
+
+
Session expired
+
+ Your session has ended. Sign in again to continue. Your work is
+ saved.
+
+
+
+
+
+ );
+}
+
+interface ConflictDialogProps {
+ theirVersion: string;
+ myVersion: string;
+ updatedBy: string;
+ onDiscard: () => void;
+ onOverwrite: () => void;
+ onCopyMine: () => void;
+}
+
+export function ConflictDialog({
+ theirVersion,
+ myVersion,
+ updatedBy,
+ onDiscard,
+ onOverwrite,
+ onCopyMine,
+}: ConflictDialogProps) {
+ return (
+
+
+
+
+ {updatedBy} updated this section while you were editing. Your changes
+ haven't been saved.
+
+
+
+
+ Their version (current):
+
+
{theirVersion}
+
+
+
+ Your version (unsaved):
+
+
{myVersion}
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/frontend/src/components/loading-overlay.tsx b/frontend/src/components/loading-overlay.tsx
new file mode 100644
index 0000000..13912b4
--- /dev/null
+++ b/frontend/src/components/loading-overlay.tsx
@@ -0,0 +1,26 @@
+import { Skeleton } from "@/components/ui/skeleton";
+import { cn } from "@/lib/utils";
+
+interface LoadingOverlayProps {
+ className?: string;
+}
+
+export function LoadingOverlay({ className }: LoadingOverlayProps) {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/frontend/src/components/markdown-renderer.tsx b/frontend/src/components/markdown-renderer.tsx
new file mode 100644
index 0000000..62509d3
--- /dev/null
+++ b/frontend/src/components/markdown-renderer.tsx
@@ -0,0 +1,24 @@
+"use client";
+
+import ReactMarkdown from "react-markdown";
+import rehypeHighlight from "rehype-highlight";
+import remarkGfm from "remark-gfm";
+import { cn } from "@/lib/utils";
+
+interface MarkdownRendererProps {
+ content: string;
+ className?: string;
+}
+
+export function MarkdownRenderer({ content, className }: MarkdownRendererProps) {
+ return (
+
+
+ {content}
+
+
+ );
+}
diff --git a/frontend/src/components/member-manager.tsx b/frontend/src/components/member-manager.tsx
new file mode 100644
index 0000000..8589ff5
--- /dev/null
+++ b/frontend/src/components/member-manager.tsx
@@ -0,0 +1,196 @@
+"use client";
+
+import { useState } from "react";
+import { UserPlus, Trash2 } from "lucide-react";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "@/components/ui/select";
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+ DialogTrigger,
+} from "@/components/ui/dialog";
+import { Badge } from "@/components/ui/badge";
+
+interface Member {
+ id: string;
+ user_id: string;
+ role: string;
+ name?: string;
+ email?: string;
+ created_at: string;
+}
+
+interface MemberManagerProps {
+ members: Member[];
+ projectSlug: string;
+ onAddMember: (userId: string, role: string) => Promise;
+ onRemoveMember: (userId: string) => Promise;
+ onChangeRole: (userId: string, role: string) => Promise;
+}
+
+const ROLES = ["owner", "admin", "editor", "commenter", "viewer"] as const;
+
+const ROLE_COLORS: Record = {
+ owner: "bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200",
+ admin: "bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200",
+ editor: "bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200",
+ commenter: "bg-amber-100 text-amber-800 dark:bg-amber-900 dark:text-amber-200",
+ viewer: "bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-200",
+};
+
+export function MemberManager({
+ members,
+ onAddMember,
+ onRemoveMember,
+ onChangeRole,
+}: MemberManagerProps) {
+ const [dialogOpen, setDialogOpen] = useState(false);
+ const [userId, setUserId] = useState("");
+ const [role, setRole] = useState("editor");
+ const [adding, setAdding] = useState(false);
+
+ const handleAdd = async () => {
+ if (!userId.trim()) return;
+ setAdding(true);
+ try {
+ await onAddMember(userId.trim(), role);
+ setDialogOpen(false);
+ setUserId("");
+ setRole("editor");
+ } finally {
+ setAdding(false);
+ }
+ };
+
+ return (
+
+
+
Members
+
+
+
+
+ {members.length === 0 ? (
+
+ No members yet
+
+ ) : (
+ members.map((member) => (
+
+
+
+
+ {member.name || member.email || member.user_id}
+
+ {member.email && (
+
+ {member.email}
+
+ )}
+
+
+
+
+
+
+
+ ))
+ )}
+
+
+ );
+}
diff --git a/frontend/src/components/presence-bar.tsx b/frontend/src/components/presence-bar.tsx
new file mode 100644
index 0000000..21e5364
--- /dev/null
+++ b/frontend/src/components/presence-bar.tsx
@@ -0,0 +1,99 @@
+"use client";
+
+import { cn } from "@/lib/utils";
+import {
+ Tooltip,
+ TooltipContent,
+ TooltipProvider,
+ TooltipTrigger,
+} from "@/components/ui/tooltip";
+
+interface PresenceUser {
+ id: string;
+ name: string;
+ activeSection?: string;
+}
+
+interface PresenceBarProps {
+ users: PresenceUser[];
+ connected: boolean;
+ className?: string;
+}
+
+const AVATAR_COLORS = [
+ "bg-blue-500",
+ "bg-green-500",
+ "bg-purple-500",
+ "bg-amber-500",
+ "bg-pink-500",
+ "bg-cyan-500",
+ "bg-red-500",
+ "bg-indigo-500",
+];
+
+function getColor(id: string): string {
+ let hash = 0;
+ for (let i = 0; i < id.length; i++) {
+ hash = (hash * 31 + id.charCodeAt(i)) | 0;
+ }
+ return AVATAR_COLORS[Math.abs(hash) % AVATAR_COLORS.length];
+}
+
+function getInitials(name: string): string {
+ return name
+ .split(" ")
+ .map((w) => w[0])
+ .join("")
+ .slice(0, 2)
+ .toUpperCase();
+}
+
+export function PresenceBar({ users, connected, className }: PresenceBarProps) {
+ return (
+
+
+
+ {connected ? "Live" : "Reconnecting..."}
+
+
+ {users.length > 0 && (
+
+
+ {users.slice(0, 8).map((user) => (
+
+
+
+ {getInitials(user.name)}
+
+
+
+ {user.name}
+ {user.activeSection && (
+
+ Viewing: {user.activeSection}
+
+ )}
+
+
+ ))}
+ {users.length > 8 && (
+
+ +{users.length - 8}
+
+ )}
+
+
+ )}
+
+ );
+}
diff --git a/frontend/src/components/section-sidebar.tsx b/frontend/src/components/section-sidebar.tsx
new file mode 100644
index 0000000..bcefcad
--- /dev/null
+++ b/frontend/src/components/section-sidebar.tsx
@@ -0,0 +1,47 @@
+"use client";
+
+import { StatusDot } from "@/components/status-dot";
+import { cn } from "@/lib/utils";
+import type { SectionListItem } from "@/lib/types";
+
+interface SectionSidebarProps {
+ sections: SectionListItem[];
+ activeSlug?: string;
+ onSelect: (slug: string) => void;
+}
+
+export function SectionSidebar({
+ sections,
+ activeSlug,
+ onSelect,
+}: SectionSidebarProps) {
+ return (
+
+ );
+}
diff --git a/frontend/src/components/section-viewer.tsx b/frontend/src/components/section-viewer.tsx
new file mode 100644
index 0000000..85376ad
--- /dev/null
+++ b/frontend/src/components/section-viewer.tsx
@@ -0,0 +1,507 @@
+"use client";
+
+import { useState, useCallback, useRef, useEffect } from "react";
+import { MessageSquarePlus, Pencil, Trash2, Check, X, ChevronRight, StickyNote } from "lucide-react";
+import { toast } from "sonner";
+import { Badge } from "@/components/ui/badge";
+import { Button } from "@/components/ui/button";
+import { Textarea } from "@/components/ui/textarea";
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger,
+} from "@/components/ui/dropdown-menu";
+import { MarkdownRenderer } from "@/components/markdown-renderer";
+import { StatusDot } from "@/components/status-dot";
+import { updateSectionNotes } from "@/lib/api";
+import type { SectionDetailResponse } from "@/lib/types";
+
+interface SectionViewerProps {
+ section: SectionDetailResponse["section"];
+ projectSlug: string;
+ dependsOn?: SectionDetailResponse["depends_on"];
+ dependedBy?: SectionDetailResponse["depended_by"];
+ comments?: SectionDetailResponse["comments"];
+ onCommentAdded?: () => void;
+ onTextSelected?: (text: string) => void;
+}
+
+export function SectionViewer({
+ section,
+ projectSlug,
+ dependsOn = [],
+ dependedBy = [],
+ comments = [],
+ onCommentAdded,
+ onTextSelected,
+}: SectionViewerProps) {
+ const contentRef = useRef(null);
+ const [selectedText, setSelectedText] = useState("");
+ const [selectionAnchor, setSelectionAnchor] = useState<{
+ anchor_text: string;
+ anchor_prefix: string;
+ anchor_suffix: string;
+ } | null>(null);
+ const [commentBody, setCommentBody] = useState("");
+ const [showCommentForm, setShowCommentForm] = useState(false);
+ const [submitting, setSubmitting] = useState(false);
+ const [editingId, setEditingId] = useState(null);
+ const [editBody, setEditBody] = useState("");
+
+ // Notes accordion state
+ const [notesExpanded, setNotesExpanded] = useState(false);
+ const [notesEditing, setNotesEditing] = useState(false);
+ const [notesDraft, setNotesDraft] = useState("");
+ const [notesSaving, setNotesSaving] = useState(false);
+
+ // Reset notes state when section changes
+ useEffect(() => {
+ setNotesExpanded(false);
+ setNotesEditing(false);
+ setNotesDraft("");
+ }, [section.slug]);
+
+ const handleStatusChange = async (newStatus: string) => {
+ try {
+ const res = await fetch(
+ `/api/projects/${projectSlug}/sections/${section.slug}`,
+ {
+ method: "PATCH",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ status: newStatus }),
+ }
+ );
+ if (!res.ok) throw new Error("Failed to update status");
+ toast.success(`Status changed to ${newStatus.replace("_", " ")}`);
+ onCommentAdded?.(); // triggers section reload
+ } catch {
+ toast.error("Failed to update status");
+ }
+ };
+
+ const handleTextSelect = useCallback(() => {
+ const sel = window.getSelection();
+ if (!sel || sel.isCollapsed || !contentRef.current) return;
+
+ const text = sel.toString().trim();
+ if (!text || text.length < 3) return;
+
+ // Check if selected text already has an unresolved comment
+ const existingComment = comments.find(
+ (c) => !c.resolved && text.includes(c.anchor_text)
+ ) || comments.find(
+ (c) => !c.resolved && c.anchor_text.includes(text)
+ );
+
+ if (existingComment) {
+ // Scroll to existing comment instead of creating new one
+ const el = document.getElementById(`comment-${existingComment.id}`);
+ if (el) {
+ el.scrollIntoView({ behavior: "smooth", block: "center" });
+ el.classList.add("ring-2", "ring-primary");
+ setTimeout(() => el.classList.remove("ring-2", "ring-primary"), 2000);
+ }
+ setShowCommentForm(false);
+ onTextSelected?.(text);
+ return;
+ }
+
+ const fullContent = section.content;
+ const idx = fullContent.indexOf(text);
+ if (idx === -1) {
+ setSelectedText(text);
+ setSelectionAnchor({ anchor_text: text, anchor_prefix: "", anchor_suffix: "" });
+ } else {
+ const prefixStart = Math.max(0, idx - 40);
+ const suffixEnd = Math.min(fullContent.length, idx + text.length + 40);
+ setSelectedText(text);
+ setSelectionAnchor({
+ anchor_text: text,
+ anchor_prefix: fullContent.slice(prefixStart, idx),
+ anchor_suffix: fullContent.slice(idx + text.length, suffixEnd),
+ });
+ }
+ setShowCommentForm(true);
+ onTextSelected?.(text);
+ }, [section.content, comments, onTextSelected]);
+
+ const handleAddComment = async () => {
+ if (!selectionAnchor || !commentBody.trim()) return;
+ setSubmitting(true);
+ try {
+ const res = await fetch(
+ `/api/projects/${projectSlug}/sections/${section.slug}/comments`,
+ {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ anchor_text: selectionAnchor.anchor_text,
+ anchor_prefix: selectionAnchor.anchor_prefix,
+ anchor_suffix: selectionAnchor.anchor_suffix,
+ body: commentBody.trim(),
+ }),
+ }
+ );
+ if (!res.ok) throw new Error("Failed to add comment");
+ toast.success("Comment added");
+ setShowCommentForm(false);
+ setCommentBody("");
+ setSelectedText("");
+ setSelectionAnchor(null);
+ onCommentAdded?.();
+ } catch {
+ toast.error("Failed to add comment");
+ } finally {
+ setSubmitting(false);
+ }
+ };
+
+ const handleToggleResolve = async (commentId: string, currentlyResolved: boolean) => {
+ try {
+ await fetch(
+ `/api/projects/${projectSlug}/sections/${section.slug}/comments/${commentId}/resolve`,
+ { method: "POST" }
+ );
+ toast.success(currentlyResolved ? "Comment reopened" : "Comment resolved");
+ onCommentAdded?.();
+ } catch {
+ toast.error("Failed to update comment");
+ }
+ };
+
+ const handleDelete = async (commentId: string) => {
+ if (!confirm("Delete this comment?")) return;
+ try {
+ await fetch(
+ `/api/projects/${projectSlug}/sections/${section.slug}/comments/${commentId}`,
+ { method: "DELETE" }
+ );
+ toast.success("Comment deleted");
+ onCommentAdded?.();
+ } catch {
+ toast.error("Failed to delete comment");
+ }
+ };
+
+ const handleEditSave = async (commentId: string) => {
+ if (!editBody.trim()) return;
+ try {
+ await fetch(
+ `/api/projects/${projectSlug}/sections/${section.slug}/comments/${commentId}`,
+ {
+ method: "PATCH",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ body: editBody.trim() }),
+ }
+ );
+ toast.success("Comment updated");
+ setEditingId(null);
+ setEditBody("");
+ onCommentAdded?.();
+ } catch {
+ toast.error("Failed to update comment");
+ }
+ };
+
+ const handleNotesSave = async () => {
+ setNotesSaving(true);
+ try {
+ await updateSectionNotes(projectSlug, section.slug, notesDraft);
+ toast.success("Notes updated");
+ setNotesEditing(false);
+ onCommentAdded?.(); // triggers section reload
+ } catch {
+ toast.error("Failed to update notes");
+ } finally {
+ setNotesSaving(false);
+ }
+ };
+
+ const handleNotesEditStart = () => {
+ setNotesDraft(section.notes || "");
+ setNotesEditing(true);
+ };
+
+ const handleNotesEditCancel = () => {
+ setNotesEditing(false);
+ setNotesDraft("");
+ };
+
+ return (
+
+
+ {/* Header */}
+
+
+
{section.title}
+
+
+
+
+
+ {(["draft", "in_progress", "review", "approved", "outdated"] as const).map((s) => (
+ handleStatusChange(s)}
+ className={section.status === s ? "font-semibold" : ""}
+ >
+
+
+ ))}
+
+
+
+
+ {section.word_count} words
+
+ {section.section_type}
+
+
+ Updated {new Date(section.updated_at).toLocaleDateString()}
+
+
+
+
+ {/* Dependencies */}
+ {dependsOn.length > 0 && (
+
+
Depends on
+
+ {dependsOn.map((dep) => (
+
+ {dep.title}
+ ({dep.dependency_type})
+
+ ))}
+
+
+ )}
+
+ {dependedBy.length > 0 && (
+
+
Depended by
+
+ {dependedBy.map((dep) => (
+ {dep.title}
+ ))}
+
+
+ )}
+
+ {/* Inline comment form */}
+ {showCommentForm && selectedText && (
+
+
+
+ Add comment on selected text
+
+
+
+
+ “{selectedText.length > 80 ? selectedText.slice(0, 80) + "..." : selectedText}”
+
+
+
+ )}
+
+ {/* Content */}
+
+
+
+
+ {/* Notes accordion */}
+
+
+
+
+ {notesEditing ? (
+
+ ) : section.notes ? (
+
+ ) : (
+
+ No notes yet.
+
+ )}
+
+
+
+
+ {/* Comments panel */}
+ {comments.length > 0 && (
+
+
+ Comments ({comments.length})
+
+
+ {comments.map((comment) => (
+
+ ))}
+
+
+ )}
+
+
+ );
+}
diff --git a/frontend/src/components/sidebar.tsx b/frontend/src/components/sidebar.tsx
new file mode 100644
index 0000000..0231116
--- /dev/null
+++ b/frontend/src/components/sidebar.tsx
@@ -0,0 +1,139 @@
+"use client";
+
+import { useState } from "react";
+import {
+ ChevronLeft,
+ ChevronRight,
+ FolderOpen,
+ Plus,
+} from "lucide-react";
+import { Button } from "@/components/ui/button";
+import { StatusDot } from "@/components/status-dot";
+import { cn } from "@/lib/utils";
+import type { Project, SectionListItem } from "@/lib/types";
+
+interface SidebarProps {
+ projects: Project[];
+ sections: SectionListItem[];
+ activeProject?: string;
+ activeSection?: string;
+ onProjectSelect: (slug: string) => void;
+ onSectionSelect: (slug: string) => void;
+ onCreateProject?: () => void;
+ onCreateSection?: () => void;
+}
+
+export function Sidebar({
+ projects,
+ sections,
+ activeProject,
+ activeSection,
+ onProjectSelect,
+ onSectionSelect,
+ onCreateProject,
+ onCreateSection,
+}: SidebarProps) {
+ const [collapsed, setCollapsed] = useState(false);
+
+ if (collapsed) {
+ return (
+
+ );
+ }
+
+ return (
+
+ );
+}
diff --git a/frontend/src/components/status-dot.tsx b/frontend/src/components/status-dot.tsx
new file mode 100644
index 0000000..2d60e52
--- /dev/null
+++ b/frontend/src/components/status-dot.tsx
@@ -0,0 +1,43 @@
+import { cn } from "@/lib/utils";
+import type { SectionStatus } from "@/lib/types";
+
+const STATUS_COLORS: Record = {
+ draft: "bg-gray-400",
+ in_progress: "bg-blue-500",
+ review: "bg-amber-500",
+ approved: "bg-green-500",
+ outdated: "bg-red-500",
+};
+
+const STATUS_LABELS: Record = {
+ draft: "Draft",
+ in_progress: "In Progress",
+ review: "Review",
+ approved: "Approved",
+ outdated: "Outdated",
+};
+
+interface StatusDotProps {
+ status: SectionStatus;
+ showLabel?: boolean;
+ className?: string;
+}
+
+export function StatusDot({ status, showLabel = false, className }: StatusDotProps) {
+ return (
+
+
+ {showLabel && (
+
+ {STATUS_LABELS[status] ?? status}
+
+ )}
+
+ );
+}
diff --git a/frontend/src/components/token-stats-dashboard.tsx b/frontend/src/components/token-stats-dashboard.tsx
new file mode 100644
index 0000000..48a8f61
--- /dev/null
+++ b/frontend/src/components/token-stats-dashboard.tsx
@@ -0,0 +1,280 @@
+"use client";
+
+import { useMemo } from "react";
+import {
+ AreaChart, Area, BarChart, Bar, PieChart, Pie, Cell,
+ XAxis, YAxis, Tooltip, ResponsiveContainer, CartesianGrid,
+} from "recharts";
+import { Wrench } from "lucide-react";
+import type { TokenStats } from "@/lib/types";
+
+interface TokenStatsDashboardProps {
+ stats: TokenStats;
+}
+
+function formatNum(n: number): string {
+ if (n >= 1_000_000) return (n / 1_000_000).toFixed(1) + "M";
+ if (n >= 1_000) return (n / 1_000).toFixed(1) + "K";
+ return n.toString();
+}
+
+function StatCard({ label, value, subtitle, color }: {
+ label: string; value: string; subtitle?: string; color: string;
+}) {
+ return (
+
+
{label}
+
{value}
+ {subtitle &&
{subtitle}
}
+
+ );
+}
+
+function GaugeRing({ percent, size = 100, label = "saved" }: { percent: number; size?: number; label?: string }) {
+ const r = (size - 12) / 2;
+ const circumference = 2 * Math.PI * r;
+ const offset = circumference * (1 - percent / 100);
+ const color = percent > 80 ? "#22c55e" : percent > 50 ? "#f59e0b" : "#ef4444";
+
+ return (
+
+ );
+}
+
+const COLORS = ["#6366f1", "#22c55e", "#f59e0b", "#ef4444", "#38bdf8", "#a855f7"];
+
+const tooltipStyle = {
+ contentStyle: {
+ background: "var(--card-bg)",
+ border: "1px solid var(--border-color)",
+ borderRadius: 8,
+ fontSize: 12,
+ color: "var(--fg)",
+ },
+ labelStyle: { color: "var(--fg-muted)" },
+};
+
+export function TokenStatsDashboard({ stats }: TokenStatsDashboardProps) {
+ const dailyData = useMemo(() =>
+ stats.daily_trend.map((d) => ({
+ day: d.day.slice(5), // MM-DD
+ saved: d.tokens_saved,
+ ops: d.operations,
+ })),
+ [stats.daily_trend]);
+
+ const comparisonData = useMemo(() => [
+ { name: "Full Doc", tokens: stats.total_full_doc_tokens, fill: "#ef4444" },
+ { name: "Loaded", tokens: stats.total_loaded_tokens, fill: "#22c55e" },
+ ], [stats]);
+
+ const opData = useMemo(() =>
+ stats.by_operation.map((op, i) => ({
+ name: op.operation.replace(/_/g, " "),
+ saved: op.full_tokens - op.loaded_tokens,
+ loaded: op.loaded_tokens,
+ count: op.count,
+ fill: COLORS[i % COLORS.length],
+ })),
+ [stats.by_operation]);
+
+ const activityByTool = useMemo(() => {
+ const map = new Map();
+ for (const a of stats.activity) {
+ const name = a.tool_name.replace(/^prd_/, "");
+ map.set(name, (map.get(name) || 0) + 1);
+ }
+ return Array.from(map.entries())
+ .map(([name, count], i) => ({ name, count, fill: COLORS[i % COLORS.length] }))
+ .sort((a, b) => b.count - a.count);
+ }, [stats.activity]);
+
+ return (
+
+ {/* Top stats row */}
+
+
+
+
+
0 ? stats.sessions.toString() : stats.operations.toLocaleString()} subtitle={stats.sessions > 0 ? `${stats.avg_sections_per_session.toFixed(1)} sections/session` : "operations total"} color="#6366f1" />
+
+
+
+
+
+ {/* Charts row */}
+
+ {/* 7-Day Trend — Area Chart */}
+
+
7-Day Token Savings
+
+
+
+
+
+
+
+
+
+
+
+ [formatNum(Number(v)), "Tokens Saved"]} />
+
+
+
+
+
+ {/* Token Comparison — Bar Chart */}
+
+
Full Doc vs Loaded
+
+ {comparisonData.map((d) => {
+ const maxH = 160;
+ const h = Math.max(8, (d.tokens / stats.total_full_doc_tokens) * maxH);
+ return (
+
+
{formatNum(d.tokens)}
+
+
{d.name}
+
+ );
+ })}
+
+
{formatNum(stats.total_saved_tokens)}
+
+
Saved
+
+
+
+
+
+ {/* Bottom row */}
+
+ {/* By Operation — Horizontal Bars */}
+
+
Savings by Operation
+ {opData.length === 0 ? (
+
No operations yet.
+ ) : (
+
+
+
+
+
+ [formatNum(Number(v)), name === "saved" ? "Tokens Saved" : "Tokens Loaded"]} />
+
+ {opData.map((d, i) => | )}
+
+
+
+
+ )}
+
+
+ {/* Activity Breakdown — Donut */}
+
+
Write Operations ({stats.activity.length})
+ {activityByTool.length === 0 ? (
+
No activity yet.
+ ) : (
+
+
+
+
+ {activityByTool.map((d, i) => | )}
+
+
+
+
+
+ {activityByTool.map((d) => (
+
+
+
{d.name}
+
{d.count}
+
+ ))}
+
+
+ )}
+
+
+
+ {/* Section Heatmap */}
+ {stats.section_heatmap && stats.section_heatmap.length > 0 && (
+
+
Section Access Heatmap
+
+ {stats.section_heatmap.map((s) => {
+ const maxCount = Math.max(...stats.section_heatmap.map((h) => h.access_count));
+ const intensity = maxCount > 0 ? s.access_count / maxCount : 0;
+ const bg = s.has_full_read
+ ? `rgba(99, 102, 241, ${0.15 + intensity * 0.6})`
+ : `rgba(148, 150, 173, ${0.1 + intensity * 0.3})`;
+ return (
+
+
+ {s.title.length > 14 ? s.title.slice(0, 13) + "…" : s.title}
+
+
+ {s.access_count}
+
+
+ );
+ })}
+
+
+ )}
+
+ {/* Recent Activity Timeline */}
+
+
Recent Activity
+
+ {stats.activity.slice(0, 15).map((item, i) => {
+ const detail = typeof item.detail === "string" ? JSON.parse(item.detail) : item.detail;
+ const slug = detail?.slug || detail?.from || detail?.to || "";
+ return (
+
+
+ {item.tool_name.replace(/^prd_/, "")}
+ {slug && {slug}}
+
+ {new Date(item.created_at).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}
+
+
+ );
+ })}
+
+
+
+ );
+}
diff --git a/frontend/src/components/top-bar.tsx b/frontend/src/components/top-bar.tsx
new file mode 100644
index 0000000..bddbc86
--- /dev/null
+++ b/frontend/src/components/top-bar.tsx
@@ -0,0 +1,102 @@
+"use client";
+
+import Link from "next/link";
+import { ChevronRight, Moon, Sun, User } from "lucide-react";
+import { Button } from "@/components/ui/button";
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuSeparator,
+ DropdownMenuTrigger,
+} from "@/components/ui/dropdown-menu";
+import { cn } from "@/lib/utils";
+import { useCallback, useEffect, useState } from "react";
+import { useRouter } from "next/navigation";
+import { signOut } from "@/lib/auth-client";
+
+interface TopBarProps {
+ projectName?: string;
+ projectSlug?: string;
+ sectionTitle?: string;
+}
+
+export function TopBar({ projectName, projectSlug, sectionTitle }: TopBarProps) {
+ const router = useRouter();
+ const [isDark, setIsDark] = useState(true);
+
+ useEffect(() => {
+ setIsDark(document.documentElement.classList.contains("dark"));
+ }, []);
+
+ const toggleTheme = useCallback(() => {
+ const next = !isDark;
+ setIsDark(next);
+ document.documentElement.classList.toggle("dark", next);
+ localStorage.setItem("prdforge-theme", next ? "dark" : "light");
+ }, [isDark]);
+
+ return (
+
+ );
+}
diff --git a/frontend/src/components/ui/avatar.tsx b/frontend/src/components/ui/avatar.tsx
new file mode 100644
index 0000000..4d14f2b
--- /dev/null
+++ b/frontend/src/components/ui/avatar.tsx
@@ -0,0 +1,50 @@
+"use client";
+
+import * as React from "react";
+import * as AvatarPrimitive from "@radix-ui/react-avatar";
+
+import { cn } from "@/lib/utils";
+
+const Avatar = React.forwardRef<
+ React.ComponentRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+Avatar.displayName = AvatarPrimitive.Root.displayName;
+
+const AvatarImage = React.forwardRef<
+ React.ComponentRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+AvatarImage.displayName = AvatarPrimitive.Image.displayName;
+
+const AvatarFallback = React.forwardRef<
+ React.ComponentRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
+
+export { Avatar, AvatarImage, AvatarFallback };
diff --git a/frontend/src/components/ui/badge.tsx b/frontend/src/components/ui/badge.tsx
new file mode 100644
index 0000000..fd92f29
--- /dev/null
+++ b/frontend/src/components/ui/badge.tsx
@@ -0,0 +1,36 @@
+import * as React from "react";
+import { cva, type VariantProps } from "class-variance-authority";
+
+import { cn } from "@/lib/utils";
+
+const badgeVariants = cva(
+ "inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
+ {
+ variants: {
+ variant: {
+ default:
+ "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
+ secondary:
+ "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
+ destructive:
+ "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
+ outline: "text-foreground",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ }
+);
+
+export interface BadgeProps
+ extends React.HTMLAttributes,
+ VariantProps {}
+
+function Badge({ className, variant, ...props }: BadgeProps) {
+ return (
+
+ );
+}
+
+export { Badge, badgeVariants };
diff --git a/frontend/src/components/ui/button.tsx b/frontend/src/components/ui/button.tsx
new file mode 100644
index 0000000..11770c9
--- /dev/null
+++ b/frontend/src/components/ui/button.tsx
@@ -0,0 +1,57 @@
+import * as React from "react";
+import { Slot } from "@radix-ui/react-slot";
+import { cva, type VariantProps } from "class-variance-authority";
+
+import { cn } from "@/lib/utils";
+
+const buttonVariants = cva(
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
+ {
+ variants: {
+ variant: {
+ default:
+ "bg-primary text-primary-foreground shadow hover:bg-primary/90",
+ destructive:
+ "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
+ outline:
+ "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
+ secondary:
+ "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
+ ghost: "hover:bg-accent hover:text-accent-foreground",
+ link: "text-primary underline-offset-4 hover:underline",
+ },
+ size: {
+ default: "h-9 px-4 py-2",
+ sm: "h-8 rounded-md px-3 text-xs",
+ lg: "h-10 rounded-md px-8",
+ icon: "h-9 w-9",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ }
+);
+
+export interface ButtonProps
+ extends React.ButtonHTMLAttributes,
+ VariantProps {
+ asChild?: boolean;
+}
+
+const Button = React.forwardRef(
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
+ const Comp = asChild ? Slot : "button";
+ return (
+
+ );
+ }
+);
+Button.displayName = "Button";
+
+export { Button, buttonVariants };
diff --git a/frontend/src/components/ui/card.tsx b/frontend/src/components/ui/card.tsx
new file mode 100644
index 0000000..188e729
--- /dev/null
+++ b/frontend/src/components/ui/card.tsx
@@ -0,0 +1,83 @@
+import * as React from "react";
+
+import { cn } from "@/lib/utils";
+
+const Card = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+Card.displayName = "Card";
+
+const CardHeader = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+CardHeader.displayName = "CardHeader";
+
+const CardTitle = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+CardTitle.displayName = "CardTitle";
+
+const CardDescription = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+CardDescription.displayName = "CardDescription";
+
+const CardContent = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+CardContent.displayName = "CardContent";
+
+const CardFooter = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+CardFooter.displayName = "CardFooter";
+
+export {
+ Card,
+ CardHeader,
+ CardFooter,
+ CardTitle,
+ CardDescription,
+ CardContent,
+};
diff --git a/frontend/src/components/ui/dialog.tsx b/frontend/src/components/ui/dialog.tsx
new file mode 100644
index 0000000..d75afcd
--- /dev/null
+++ b/frontend/src/components/ui/dialog.tsx
@@ -0,0 +1,122 @@
+"use client";
+
+import * as React from "react";
+import * as DialogPrimitive from "@radix-ui/react-dialog";
+import { X } from "lucide-react";
+
+import { cn } from "@/lib/utils";
+
+const Dialog = DialogPrimitive.Root;
+
+const DialogTrigger = DialogPrimitive.Trigger;
+
+const DialogPortal = DialogPrimitive.Portal;
+
+const DialogClose = DialogPrimitive.Close;
+
+const DialogOverlay = React.forwardRef<
+ React.ComponentRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
+
+const DialogContent = React.forwardRef<
+ React.ComponentRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+
+
+
+ {children}
+
+
+ Close
+
+
+
+));
+DialogContent.displayName = DialogPrimitive.Content.displayName;
+
+const DialogHeader = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
+
+);
+DialogHeader.displayName = "DialogHeader";
+
+const DialogFooter = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
+
+);
+DialogFooter.displayName = "DialogFooter";
+
+const DialogTitle = React.forwardRef<
+ React.ComponentRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+DialogTitle.displayName = DialogPrimitive.Title.displayName;
+
+const DialogDescription = React.forwardRef<
+ React.ComponentRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+DialogDescription.displayName = DialogPrimitive.Description.displayName;
+
+export {
+ Dialog,
+ DialogPortal,
+ DialogOverlay,
+ DialogTrigger,
+ DialogClose,
+ DialogContent,
+ DialogHeader,
+ DialogFooter,
+ DialogTitle,
+ DialogDescription,
+};
diff --git a/frontend/src/components/ui/dropdown-menu.tsx b/frontend/src/components/ui/dropdown-menu.tsx
new file mode 100644
index 0000000..e1131c0
--- /dev/null
+++ b/frontend/src/components/ui/dropdown-menu.tsx
@@ -0,0 +1,202 @@
+"use client";
+
+import * as React from "react";
+import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
+import { Check, ChevronRight, Circle } from "lucide-react";
+
+import { cn } from "@/lib/utils";
+
+const DropdownMenu = DropdownMenuPrimitive.Root;
+
+const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
+
+const DropdownMenuGroup = DropdownMenuPrimitive.Group;
+
+const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
+
+const DropdownMenuSub = DropdownMenuPrimitive.Sub;
+
+const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
+
+const DropdownMenuSubTrigger = React.forwardRef<
+ React.ComponentRef,
+ React.ComponentPropsWithoutRef & {
+ inset?: boolean;
+ }
+>(({ className, inset, children, ...props }, ref) => (
+
+ {children}
+
+
+));
+DropdownMenuSubTrigger.displayName =
+ DropdownMenuPrimitive.SubTrigger.displayName;
+
+const DropdownMenuSubContent = React.forwardRef<
+ React.ComponentRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+DropdownMenuSubContent.displayName =
+ DropdownMenuPrimitive.SubContent.displayName;
+
+const DropdownMenuContent = React.forwardRef<
+ React.ComponentRef,
+ React.ComponentPropsWithoutRef
+>(({ className, sideOffset = 4, ...props }, ref) => (
+
+
+
+));
+DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
+
+const DropdownMenuItem = React.forwardRef<
+ React.ComponentRef,
+ React.ComponentPropsWithoutRef & {
+ inset?: boolean;
+ }
+>(({ className, inset, ...props }, ref) => (
+
+));
+DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
+
+const DropdownMenuCheckboxItem = React.forwardRef<
+ React.ComponentRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, checked, ...props }, ref) => (
+
+
+
+
+
+
+ {children}
+
+));
+DropdownMenuCheckboxItem.displayName =
+ DropdownMenuPrimitive.CheckboxItem.displayName;
+
+const DropdownMenuRadioItem = React.forwardRef<
+ React.ComponentRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+
+
+
+
+
+
+ {children}
+
+));
+DropdownMenuRadioItem.displayName =
+ DropdownMenuPrimitive.RadioItem.displayName;
+
+const DropdownMenuLabel = React.forwardRef<
+ React.ComponentRef,
+ React.ComponentPropsWithoutRef & {
+ inset?: boolean;
+ }
+>(({ className, inset, ...props }, ref) => (
+
+));
+DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
+
+const DropdownMenuSeparator = React.forwardRef<
+ React.ComponentRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+DropdownMenuSeparator.displayName =
+ DropdownMenuPrimitive.Separator.displayName;
+
+const DropdownMenuShortcut = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => {
+ return (
+
+ );
+};
+DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
+
+export {
+ DropdownMenu,
+ DropdownMenuTrigger,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuCheckboxItem,
+ DropdownMenuRadioItem,
+ DropdownMenuLabel,
+ DropdownMenuSeparator,
+ DropdownMenuShortcut,
+ DropdownMenuGroup,
+ DropdownMenuPortal,
+ DropdownMenuSub,
+ DropdownMenuSubContent,
+ DropdownMenuSubTrigger,
+ DropdownMenuRadioGroup,
+};
diff --git a/frontend/src/components/ui/input.tsx b/frontend/src/components/ui/input.tsx
new file mode 100644
index 0000000..c60d725
--- /dev/null
+++ b/frontend/src/components/ui/input.tsx
@@ -0,0 +1,23 @@
+import * as React from "react";
+
+import { cn } from "@/lib/utils";
+
+const Input = React.forwardRef<
+ HTMLInputElement,
+ React.InputHTMLAttributes
+>(({ className, type, ...props }, ref) => {
+ return (
+
+ );
+});
+Input.displayName = "Input";
+
+export { Input };
diff --git a/frontend/src/components/ui/select.tsx b/frontend/src/components/ui/select.tsx
new file mode 100644
index 0000000..dc6aeb1
--- /dev/null
+++ b/frontend/src/components/ui/select.tsx
@@ -0,0 +1,160 @@
+"use client";
+
+import * as React from "react";
+import * as SelectPrimitive from "@radix-ui/react-select";
+import { Check, ChevronDown, ChevronUp } from "lucide-react";
+
+import { cn } from "@/lib/utils";
+
+const Select = SelectPrimitive.Root;
+
+const SelectGroup = SelectPrimitive.Group;
+
+const SelectValue = SelectPrimitive.Value;
+
+const SelectTrigger = React.forwardRef<
+ React.ComponentRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+ span]:line-clamp-1",
+ className
+ )}
+ {...props}
+ >
+ {children}
+
+
+
+
+));
+SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
+
+const SelectScrollUpButton = React.forwardRef<
+ React.ComponentRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+
+
+));
+SelectScrollUpButton.displayName =
+ SelectPrimitive.ScrollUpButton.displayName;
+
+const SelectScrollDownButton = React.forwardRef<
+ React.ComponentRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+
+
+));
+SelectScrollDownButton.displayName =
+ SelectPrimitive.ScrollDownButton.displayName;
+
+const SelectContent = React.forwardRef<
+ React.ComponentRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, position = "popper", ...props }, ref) => (
+
+
+
+
+ {children}
+
+
+
+
+));
+SelectContent.displayName = SelectPrimitive.Content.displayName;
+
+const SelectLabel = React.forwardRef<
+ React.ComponentRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+SelectLabel.displayName = SelectPrimitive.Label.displayName;
+
+const SelectItem = React.forwardRef<
+ React.ComponentRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+
+
+
+
+
+
+ {children}
+
+));
+SelectItem.displayName = SelectPrimitive.Item.displayName;
+
+const SelectSeparator = React.forwardRef<
+ React.ComponentRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
+
+export {
+ Select,
+ SelectGroup,
+ SelectValue,
+ SelectTrigger,
+ SelectContent,
+ SelectLabel,
+ SelectItem,
+ SelectSeparator,
+ SelectScrollUpButton,
+ SelectScrollDownButton,
+};
diff --git a/frontend/src/components/ui/skeleton.tsx b/frontend/src/components/ui/skeleton.tsx
new file mode 100644
index 0000000..c26c4ea
--- /dev/null
+++ b/frontend/src/components/ui/skeleton.tsx
@@ -0,0 +1,15 @@
+import { cn } from "@/lib/utils";
+
+function Skeleton({
+ className,
+ ...props
+}: React.HTMLAttributes) {
+ return (
+
+ );
+}
+
+export { Skeleton };
diff --git a/frontend/src/components/ui/tabs.tsx b/frontend/src/components/ui/tabs.tsx
new file mode 100644
index 0000000..e9c2804
--- /dev/null
+++ b/frontend/src/components/ui/tabs.tsx
@@ -0,0 +1,55 @@
+"use client";
+
+import * as React from "react";
+import * as TabsPrimitive from "@radix-ui/react-tabs";
+
+import { cn } from "@/lib/utils";
+
+const Tabs = TabsPrimitive.Root;
+
+const TabsList = React.forwardRef<
+ React.ComponentRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+TabsList.displayName = TabsPrimitive.List.displayName;
+
+const TabsTrigger = React.forwardRef<
+ React.ComponentRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
+
+const TabsContent = React.forwardRef<
+ React.ComponentRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+TabsContent.displayName = TabsPrimitive.Content.displayName;
+
+export { Tabs, TabsList, TabsTrigger, TabsContent };
diff --git a/frontend/src/components/ui/textarea.tsx b/frontend/src/components/ui/textarea.tsx
new file mode 100644
index 0000000..f186a15
--- /dev/null
+++ b/frontend/src/components/ui/textarea.tsx
@@ -0,0 +1,22 @@
+import * as React from "react";
+
+import { cn } from "@/lib/utils";
+
+const Textarea = React.forwardRef<
+ HTMLTextAreaElement,
+ React.TextareaHTMLAttributes
+>(({ className, ...props }, ref) => {
+ return (
+
+ );
+});
+Textarea.displayName = "Textarea";
+
+export { Textarea };
diff --git a/frontend/src/components/ui/tooltip.tsx b/frontend/src/components/ui/tooltip.tsx
new file mode 100644
index 0000000..61abc99
--- /dev/null
+++ b/frontend/src/components/ui/tooltip.tsx
@@ -0,0 +1,32 @@
+"use client";
+
+import * as React from "react";
+import * as TooltipPrimitive from "@radix-ui/react-tooltip";
+
+import { cn } from "@/lib/utils";
+
+const TooltipProvider = TooltipPrimitive.Provider;
+
+const Tooltip = TooltipPrimitive.Root;
+
+const TooltipTrigger = TooltipPrimitive.Trigger;
+
+const TooltipContent = React.forwardRef<
+ React.ComponentRef,
+ React.ComponentPropsWithoutRef
+>(({ className, sideOffset = 4, ...props }, ref) => (
+
+
+
+));
+TooltipContent.displayName = TooltipPrimitive.Content.displayName;
+
+export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts
new file mode 100644
index 0000000..b65ac44
--- /dev/null
+++ b/frontend/src/lib/api.ts
@@ -0,0 +1,71 @@
+import type {
+ Project,
+ ProjectDetailResponse,
+ SectionDetailResponse,
+ TokenStats,
+} from "./types";
+
+async function apiFetch(path: string, init?: RequestInit): Promise {
+ const res = await fetch(path, init);
+ if (!res.ok) {
+ const body = await res.json().catch(() => ({ error: res.statusText }));
+ throw new Error(body.error?.message ?? body.error ?? res.statusText);
+ }
+ return res.json();
+}
+
+export async function fetchProjects(): Promise {
+ return apiFetch("/api/projects");
+}
+
+export async function fetchProject(slug: string): Promise {
+ return apiFetch(`/api/projects/${slug}`);
+}
+
+export async function fetchSection(
+ projectSlug: string,
+ sectionSlug: string
+): Promise {
+ return apiFetch(
+ `/api/projects/${projectSlug}/sections/${sectionSlug}`
+ );
+}
+
+export async function fetchTokenStats(slug: string): Promise {
+ return apiFetch(`/api/projects/${slug}/token-stats`);
+}
+
+export async function createProject(data: {
+ name: string;
+ description?: string;
+ template_id?: string;
+}): Promise {
+ return apiFetch("/api/projects", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify(data),
+ });
+}
+
+export interface TemplateInfo {
+ id: string;
+ name: string;
+ description: string;
+ section_count: number;
+}
+
+export async function fetchTemplates(): Promise {
+ return apiFetch("/api/templates");
+}
+
+export async function updateSectionNotes(
+ projectSlug: string,
+ sectionSlug: string,
+ notes: string
+): Promise<{ ok: boolean; notes: string }> {
+ return apiFetch(`/api/projects/${projectSlug}/sections/${sectionSlug}/notes`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ notes }),
+ });
+}
diff --git a/frontend/src/lib/auth-client.ts b/frontend/src/lib/auth-client.ts
new file mode 100644
index 0000000..790008c
--- /dev/null
+++ b/frontend/src/lib/auth-client.ts
@@ -0,0 +1,8 @@
+import { createAuthClient } from "better-auth/react";
+import { organizationClient } from "better-auth/client/plugins";
+
+export const authClient = createAuthClient({
+ plugins: [organizationClient()],
+});
+
+export const { useSession, signIn, signOut, signUp } = authClient;
diff --git a/frontend/src/lib/auth.ts b/frontend/src/lib/auth.ts
new file mode 100644
index 0000000..2bdbfad
--- /dev/null
+++ b/frontend/src/lib/auth.ts
@@ -0,0 +1,16 @@
+import { betterAuth } from "better-auth";
+import { organization } from "better-auth/plugins";
+import { prismaAdapter } from "better-auth/adapters/prisma";
+import { prisma } from "./db";
+
+export const auth = betterAuth({
+ database: prismaAdapter(prisma, { provider: "postgresql" }),
+ emailAndPassword: {
+ enabled: true,
+ signUp: {
+ enabled: false, // Closed sign-up: admin creates users
+ },
+ },
+ plugins: [organization()],
+ trustedOrigins: [process.env.NEXT_PUBLIC_APP_URL || "http://localhost:3000"],
+});
diff --git a/frontend/src/lib/db.ts b/frontend/src/lib/db.ts
new file mode 100644
index 0000000..a6b4373
--- /dev/null
+++ b/frontend/src/lib/db.ts
@@ -0,0 +1,11 @@
+import { PrismaClient } from "@prisma/client";
+
+const globalForPrisma = globalThis as unknown as {
+ prisma: PrismaClient | undefined;
+};
+
+export const prisma = globalForPrisma.prisma ?? new PrismaClient();
+
+if (process.env.NODE_ENV !== "production") {
+ globalForPrisma.prisma = prisma;
+}
diff --git a/frontend/src/lib/types.ts b/frontend/src/lib/types.ts
new file mode 100644
index 0000000..21ec66d
--- /dev/null
+++ b/frontend/src/lib/types.ts
@@ -0,0 +1,139 @@
+export type SectionStatus =
+ | "draft"
+ | "in_progress"
+ | "review"
+ | "approved"
+ | "outdated";
+
+export interface Project {
+ slug: string;
+ name: string;
+ description: string;
+ version: number;
+ section_count: number;
+ total_words: number;
+ created_at: string;
+ updated_at: string;
+}
+
+export interface SectionListItem {
+ slug: string;
+ title: string;
+ section_type: string;
+ sort_order: number;
+ status: SectionStatus;
+ summary: string;
+ tags: string[];
+ word_count: number;
+ parent_slug: string | null;
+ revision_count: number;
+ updated_at: string;
+}
+
+export interface ProjectDetailResponse {
+ project: {
+ slug: string;
+ name: string;
+ description: string;
+ version: number;
+ created_at: string;
+ };
+ stats: {
+ sections: number;
+ words: number;
+ by_status: Record;
+ };
+ sections: SectionListItem[];
+ dependencies: {
+ from_slug: string;
+ to_slug: string;
+ type: string;
+ description: string;
+ }[];
+ changelog: {
+ section_slug: string;
+ section_title: string;
+ revision_number: number;
+ change_description: string;
+ created_at: string;
+ }[];
+}
+
+export interface SectionDetailResponse {
+ section: {
+ slug: string;
+ title: string;
+ content: string;
+ summary: string;
+ status: SectionStatus;
+ section_type: string;
+ tags: string[];
+ notes: string;
+ word_count: number;
+ updated_at: string;
+ };
+ depends_on: { slug: string; title: string; summary: string; dependency_type: string }[];
+ depended_by: { slug: string; title: string; summary: string; dependency_type: string }[];
+ revisions: { revision_number: number; change_description: string; created_at: string }[];
+ comments: {
+ id: string;
+ anchor_text: string;
+ body: string;
+ resolved: boolean;
+ created_at: string;
+ replies: { id: string; author: string; body: string; created_at: string }[];
+ }[];
+}
+
+export interface TokenStats {
+ operations: number;
+ total_full_doc_tokens: number;
+ total_loaded_tokens: number;
+ total_saved_tokens: number;
+ savings_percent: number;
+ sessions: number;
+ best_session_savings: number;
+ avg_sections_per_session: number;
+ by_operation: {
+ operation: string;
+ count: number;
+ full_tokens: number;
+ loaded_tokens: number;
+ }[];
+ daily_trend: {
+ day: string;
+ operations: number;
+ tokens_saved: number;
+ }[];
+ project_stats: {
+ sections: number;
+ dependencies: number;
+ revisions: number;
+ };
+ activity: {
+ tool_name: string;
+ detail: Record;
+ created_at: string;
+ }[];
+ section_heatmap: {
+ slug: string;
+ title: string;
+ access_count: number;
+ has_full_read: number;
+ }[];
+}
+
+export interface ChatMessage {
+ id: string;
+ role: "user" | "assistant" | "system" | "tool";
+ content: string;
+ metadata: Record;
+ created_at: string;
+}
+
+export interface ProjectSettings {
+ claude_comment_replies: boolean;
+ chat_enabled: boolean;
+ chat_provider: "claude_cli" | "anthropic_api";
+ chat_model: "sonnet" | "opus" | "haiku";
+}
diff --git a/frontend/src/lib/use-project-websocket.ts b/frontend/src/lib/use-project-websocket.ts
new file mode 100644
index 0000000..283047e
--- /dev/null
+++ b/frontend/src/lib/use-project-websocket.ts
@@ -0,0 +1,107 @@
+"use client";
+
+import { useEffect, useRef, useState, useCallback } from "react";
+
+interface WSEvent {
+ type: string;
+ data: Record;
+}
+
+interface PresenceUser {
+ id: string;
+ name: string;
+ activeSection?: string;
+}
+
+interface UseProjectWebSocketOptions {
+ projectSlug: string;
+ userId: string;
+ enabled?: boolean;
+ onEvent?: (event: WSEvent) => void;
+}
+
+export function useProjectWebSocket({
+ projectSlug,
+ userId,
+ enabled = true,
+ onEvent,
+}: UseProjectWebSocketOptions) {
+ const [connected, setConnected] = useState(false);
+ const [presence, setPresence] = useState([]);
+ const wsRef = useRef(null);
+ const retryRef = useRef(0);
+ const maxRetries = 10;
+
+ const connect = useCallback(async () => {
+ if (!enabled || !projectSlug || !userId) return;
+
+ try {
+ // Get WS token
+ const res = await fetch("/api/ws-token", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ project_slug: projectSlug }),
+ });
+ if (!res.ok) return;
+ const { token } = await res.json();
+
+ const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
+ const ws = new WebSocket(
+ `${protocol}//${window.location.host}/ws/projects/${projectSlug}?token=${token}`
+ );
+
+ ws.onopen = () => {
+ setConnected(true);
+ retryRef.current = 0;
+ };
+
+ ws.onmessage = (e) => {
+ try {
+ const event: WSEvent = JSON.parse(e.data);
+ if (event.type === "presence_update") {
+ setPresence(event.data.users as PresenceUser[]);
+ }
+ onEvent?.(event);
+ } catch {
+ // ignore malformed messages
+ }
+ };
+
+ ws.onclose = () => {
+ setConnected(false);
+ wsRef.current = null;
+ // Exponential backoff with jitter
+ if (retryRef.current < maxRetries) {
+ const delay = Math.min(
+ 1000 * Math.pow(2, retryRef.current),
+ 30000
+ );
+ const jitter = Math.random() * 1000 - 500;
+ retryRef.current++;
+ setTimeout(connect, delay + jitter);
+ }
+ };
+
+ ws.onerror = () => {
+ ws.close();
+ };
+
+ wsRef.current = ws;
+ } catch {
+ // token fetch failed, retry
+ if (retryRef.current < maxRetries) {
+ retryRef.current++;
+ setTimeout(connect, 3000);
+ }
+ }
+ }, [projectSlug, userId, enabled, onEvent]);
+
+ useEffect(() => {
+ connect();
+ return () => {
+ wsRef.current?.close();
+ };
+ }, [connect]);
+
+ return { connected, presence };
+}
diff --git a/frontend/src/lib/utils.ts b/frontend/src/lib/utils.ts
new file mode 100644
index 0000000..365058c
--- /dev/null
+++ b/frontend/src/lib/utils.ts
@@ -0,0 +1,6 @@
+import { type ClassValue, clsx } from "clsx";
+import { twMerge } from "tailwind-merge";
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs));
+}
diff --git a/frontend/src/middleware.ts b/frontend/src/middleware.ts
new file mode 100644
index 0000000..1d01d89
--- /dev/null
+++ b/frontend/src/middleware.ts
@@ -0,0 +1,34 @@
+import { NextRequest, NextResponse } from "next/server";
+
+const PYTHON_API = process.env.PYTHON_API_URL || "http://python-api:8088";
+
+// Paths that should be proxied to the Python API
+const PROXY_PREFIXES = ["/api/projects", "/api/chat", "/api/ws-token"];
+
+// Paths handled by Next.js API routes (not proxied)
+const NEXTJS_PREFIXES = ["/api/auth", "/api/orgs"];
+
+export function middleware(request: NextRequest) {
+ const { pathname } = request.nextUrl;
+
+ // Skip Next.js API routes
+ if (NEXTJS_PREFIXES.some((p) => pathname.startsWith(p))) {
+ return NextResponse.next();
+ }
+
+ // Proxy matching paths to Python API
+ if (PROXY_PREFIXES.some((p) => pathname.startsWith(p))) {
+ const url = new URL(pathname + request.nextUrl.search, PYTHON_API);
+ return NextResponse.rewrite(url);
+ }
+
+ if (pathname === "/health") {
+ return NextResponse.rewrite(new URL("/health", PYTHON_API));
+ }
+
+ return NextResponse.next();
+}
+
+export const config = {
+ matcher: ["/api/:path*", "/health"],
+};
diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json
new file mode 100644
index 0000000..c133409
--- /dev/null
+++ b/frontend/tsconfig.json
@@ -0,0 +1,27 @@
+{
+ "compilerOptions": {
+ "target": "ES2017",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "noEmit": true,
+ "esModuleInterop": true,
+ "module": "esnext",
+ "moduleResolution": "bundler",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "preserve",
+ "incremental": true,
+ "plugins": [
+ {
+ "name": "next"
+ }
+ ],
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ },
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
+ "exclude": ["node_modules"]
+}
diff --git a/frontend/tsconfig.tsbuildinfo b/frontend/tsconfig.tsbuildinfo
new file mode 100644
index 0000000..ef58911
--- /dev/null
+++ b/frontend/tsconfig.tsbuildinfo
@@ -0,0 +1 @@
+{"fileNames":["./node_modules/typescript/lib/lib.es5.d.ts","./node_modules/typescript/lib/lib.es2015.d.ts","./node_modules/typescript/lib/lib.es2016.d.ts","./node_modules/typescript/lib/lib.es2017.d.ts","./node_modules/typescript/lib/lib.es2018.d.ts","./node_modules/typescript/lib/lib.es2019.d.ts","./node_modules/typescript/lib/lib.es2020.d.ts","./node_modules/typescript/lib/lib.es2021.d.ts","./node_modules/typescript/lib/lib.es2022.d.ts","./node_modules/typescript/lib/lib.es2023.d.ts","./node_modules/typescript/lib/lib.es2024.d.ts","./node_modules/typescript/lib/lib.esnext.d.ts","./node_modules/typescript/lib/lib.dom.d.ts","./node_modules/typescript/lib/lib.dom.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.core.d.ts","./node_modules/typescript/lib/lib.es2015.collection.d.ts","./node_modules/typescript/lib/lib.es2015.generator.d.ts","./node_modules/typescript/lib/lib.es2015.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.promise.d.ts","./node_modules/typescript/lib/lib.es2015.proxy.d.ts","./node_modules/typescript/lib/lib.es2015.reflect.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2016.array.include.d.ts","./node_modules/typescript/lib/lib.es2016.intl.d.ts","./node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","./node_modules/typescript/lib/lib.es2017.date.d.ts","./node_modules/typescript/lib/lib.es2017.object.d.ts","./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2017.string.d.ts","./node_modules/typescript/lib/lib.es2017.intl.d.ts","./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","./node_modules/typescript/lib/lib.es2018.intl.d.ts","./node_modules/typescript/lib/lib.es2018.promise.d.ts","./node_modules/typescript/lib/lib.es2018.regexp.d.ts","./node_modules/typescript/lib/lib.es2019.array.d.ts","./node_modules/typescript/lib/lib.es2019.object.d.ts","./node_modules/typescript/lib/lib.es2019.string.d.ts","./node_modules/typescript/lib/lib.es2019.symbol.d.ts","./node_modules/typescript/lib/lib.es2019.intl.d.ts","./node_modules/typescript/lib/lib.es2020.bigint.d.ts","./node_modules/typescript/lib/lib.es2020.date.d.ts","./node_modules/typescript/lib/lib.es2020.promise.d.ts","./node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2020.string.d.ts","./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2020.intl.d.ts","./node_modules/typescript/lib/lib.es2020.number.d.ts","./node_modules/typescript/lib/lib.es2021.promise.d.ts","./node_modules/typescript/lib/lib.es2021.string.d.ts","./node_modules/typescript/lib/lib.es2021.weakref.d.ts","./node_modules/typescript/lib/lib.es2021.intl.d.ts","./node_modules/typescript/lib/lib.es2022.array.d.ts","./node_modules/typescript/lib/lib.es2022.error.d.ts","./node_modules/typescript/lib/lib.es2022.intl.d.ts","./node_modules/typescript/lib/lib.es2022.object.d.ts","./node_modules/typescript/lib/lib.es2022.string.d.ts","./node_modules/typescript/lib/lib.es2022.regexp.d.ts","./node_modules/typescript/lib/lib.es2023.array.d.ts","./node_modules/typescript/lib/lib.es2023.collection.d.ts","./node_modules/typescript/lib/lib.es2023.intl.d.ts","./node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts","./node_modules/typescript/lib/lib.es2024.collection.d.ts","./node_modules/typescript/lib/lib.es2024.object.d.ts","./node_modules/typescript/lib/lib.es2024.promise.d.ts","./node_modules/typescript/lib/lib.es2024.regexp.d.ts","./node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2024.string.d.ts","./node_modules/typescript/lib/lib.esnext.array.d.ts","./node_modules/typescript/lib/lib.esnext.collection.d.ts","./node_modules/typescript/lib/lib.esnext.intl.d.ts","./node_modules/typescript/lib/lib.esnext.disposable.d.ts","./node_modules/typescript/lib/lib.esnext.promise.d.ts","./node_modules/typescript/lib/lib.esnext.decorators.d.ts","./node_modules/typescript/lib/lib.esnext.iterator.d.ts","./node_modules/typescript/lib/lib.esnext.float16.d.ts","./node_modules/typescript/lib/lib.esnext.error.d.ts","./node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts","./node_modules/typescript/lib/lib.decorators.d.ts","./node_modules/typescript/lib/lib.decorators.legacy.d.ts","./.next/types/routes.d.ts","./node_modules/@types/react/global.d.ts","./node_modules/csstype/index.d.ts","./node_modules/@types/react/index.d.ts","./node_modules/next/dist/styled-jsx/types/css.d.ts","./node_modules/next/dist/styled-jsx/types/macro.d.ts","./node_modules/next/dist/styled-jsx/types/style.d.ts","./node_modules/next/dist/styled-jsx/types/global.d.ts","./node_modules/next/dist/styled-jsx/types/index.d.ts","./node_modules/next/dist/shared/lib/amp.d.ts","./node_modules/next/amp.d.ts","./node_modules/next/dist/server/get-page-files.d.ts","./node_modules/@types/node/compatibility/disposable.d.ts","./node_modules/@types/node/compatibility/indexable.d.ts","./node_modules/@types/node/compatibility/iterators.d.ts","./node_modules/@types/node/compatibility/index.d.ts","./node_modules/@types/node/globals.typedarray.d.ts","./node_modules/@types/node/buffer.buffer.d.ts","./node_modules/@types/node/globals.d.ts","./node_modules/@types/node/web-globals/abortcontroller.d.ts","./node_modules/@types/node/web-globals/domexception.d.ts","./node_modules/@types/node/web-globals/events.d.ts","./node_modules/@types/node/node_modules/undici-types/header.d.ts","./node_modules/@types/node/node_modules/undici-types/readable.d.ts","./node_modules/@types/node/node_modules/undici-types/file.d.ts","./node_modules/@types/node/node_modules/undici-types/fetch.d.ts","./node_modules/@types/node/node_modules/undici-types/formdata.d.ts","./node_modules/@types/node/node_modules/undici-types/connector.d.ts","./node_modules/@types/node/node_modules/undici-types/client.d.ts","./node_modules/@types/node/node_modules/undici-types/errors.d.ts","./node_modules/@types/node/node_modules/undici-types/dispatcher.d.ts","./node_modules/@types/node/node_modules/undici-types/global-dispatcher.d.ts","./node_modules/@types/node/node_modules/undici-types/global-origin.d.ts","./node_modules/@types/node/node_modules/undici-types/pool-stats.d.ts","./node_modules/@types/node/node_modules/undici-types/pool.d.ts","./node_modules/@types/node/node_modules/undici-types/handlers.d.ts","./node_modules/@types/node/node_modules/undici-types/balanced-pool.d.ts","./node_modules/@types/node/node_modules/undici-types/agent.d.ts","./node_modules/@types/node/node_modules/undici-types/mock-interceptor.d.ts","./node_modules/@types/node/node_modules/undici-types/mock-agent.d.ts","./node_modules/@types/node/node_modules/undici-types/mock-client.d.ts","./node_modules/@types/node/node_modules/undici-types/mock-pool.d.ts","./node_modules/@types/node/node_modules/undici-types/mock-errors.d.ts","./node_modules/@types/node/node_modules/undici-types/proxy-agent.d.ts","./node_modules/@types/node/node_modules/undici-types/env-http-proxy-agent.d.ts","./node_modules/@types/node/node_modules/undici-types/retry-handler.d.ts","./node_modules/@types/node/node_modules/undici-types/retry-agent.d.ts","./node_modules/@types/node/node_modules/undici-types/api.d.ts","./node_modules/@types/node/node_modules/undici-types/interceptors.d.ts","./node_modules/@types/node/node_modules/undici-types/util.d.ts","./node_modules/@types/node/node_modules/undici-types/cookies.d.ts","./node_modules/@types/node/node_modules/undici-types/patch.d.ts","./node_modules/@types/node/node_modules/undici-types/websocket.d.ts","./node_modules/@types/node/node_modules/undici-types/eventsource.d.ts","./node_modules/@types/node/node_modules/undici-types/filereader.d.ts","./node_modules/@types/node/node_modules/undici-types/diagnostics-channel.d.ts","./node_modules/@types/node/node_modules/undici-types/content-type.d.ts","./node_modules/@types/node/node_modules/undici-types/cache.d.ts","./node_modules/@types/node/node_modules/undici-types/index.d.ts","./node_modules/@types/node/web-globals/fetch.d.ts","./node_modules/@types/node/web-globals/navigator.d.ts","./node_modules/@types/node/web-globals/storage.d.ts","./node_modules/@types/node/assert.d.ts","./node_modules/@types/node/assert/strict.d.ts","./node_modules/@types/node/async_hooks.d.ts","./node_modules/@types/node/buffer.d.ts","./node_modules/@types/node/child_process.d.ts","./node_modules/@types/node/cluster.d.ts","./node_modules/@types/node/console.d.ts","./node_modules/@types/node/constants.d.ts","./node_modules/@types/node/crypto.d.ts","./node_modules/@types/node/dgram.d.ts","./node_modules/@types/node/diagnostics_channel.d.ts","./node_modules/@types/node/dns.d.ts","./node_modules/@types/node/dns/promises.d.ts","./node_modules/@types/node/domain.d.ts","./node_modules/@types/node/events.d.ts","./node_modules/@types/node/fs.d.ts","./node_modules/@types/node/fs/promises.d.ts","./node_modules/@types/node/http.d.ts","./node_modules/@types/node/http2.d.ts","./node_modules/@types/node/https.d.ts","./node_modules/@types/node/inspector.d.ts","./node_modules/@types/node/inspector.generated.d.ts","./node_modules/@types/node/module.d.ts","./node_modules/@types/node/net.d.ts","./node_modules/@types/node/os.d.ts","./node_modules/@types/node/path.d.ts","./node_modules/@types/node/perf_hooks.d.ts","./node_modules/@types/node/process.d.ts","./node_modules/@types/node/punycode.d.ts","./node_modules/@types/node/querystring.d.ts","./node_modules/@types/node/readline.d.ts","./node_modules/@types/node/readline/promises.d.ts","./node_modules/@types/node/repl.d.ts","./node_modules/@types/node/sea.d.ts","./node_modules/@types/node/sqlite.d.ts","./node_modules/@types/node/stream.d.ts","./node_modules/@types/node/stream/promises.d.ts","./node_modules/@types/node/stream/consumers.d.ts","./node_modules/@types/node/stream/web.d.ts","./node_modules/@types/node/string_decoder.d.ts","./node_modules/@types/node/test.d.ts","./node_modules/@types/node/timers.d.ts","./node_modules/@types/node/timers/promises.d.ts","./node_modules/@types/node/tls.d.ts","./node_modules/@types/node/trace_events.d.ts","./node_modules/@types/node/tty.d.ts","./node_modules/@types/node/url.d.ts","./node_modules/@types/node/util.d.ts","./node_modules/@types/node/v8.d.ts","./node_modules/@types/node/vm.d.ts","./node_modules/@types/node/wasi.d.ts","./node_modules/@types/node/worker_threads.d.ts","./node_modules/@types/node/zlib.d.ts","./node_modules/@types/node/index.d.ts","./node_modules/@types/react/canary.d.ts","./node_modules/@types/react/experimental.d.ts","./node_modules/@types/react-dom/index.d.ts","./node_modules/@types/react-dom/canary.d.ts","./node_modules/@types/react-dom/experimental.d.ts","./node_modules/next/dist/lib/fallback.d.ts","./node_modules/next/dist/compiled/webpack/webpack.d.ts","./node_modules/next/dist/server/config.d.ts","./node_modules/next/dist/lib/load-custom-routes.d.ts","./node_modules/next/dist/shared/lib/image-config.d.ts","./node_modules/next/dist/build/webpack/plugins/subresource-integrity-plugin.d.ts","./node_modules/next/dist/server/body-streams.d.ts","./node_modules/next/dist/server/lib/cache-control.d.ts","./node_modules/next/dist/lib/setup-exception-listeners.d.ts","./node_modules/next/dist/lib/worker.d.ts","./node_modules/next/dist/lib/constants.d.ts","./node_modules/next/dist/client/components/app-router-headers.d.ts","./node_modules/next/dist/build/rendering-mode.d.ts","./node_modules/next/dist/server/lib/router-utils/build-prefetch-segment-data-route.d.ts","./node_modules/next/dist/server/require-hook.d.ts","./node_modules/next/dist/server/lib/experimental/ppr.d.ts","./node_modules/next/dist/build/webpack/plugins/app-build-manifest-plugin.d.ts","./node_modules/next/dist/lib/page-types.d.ts","./node_modules/next/dist/build/segment-config/app/app-segment-config.d.ts","./node_modules/next/dist/build/segment-config/pages/pages-segment-config.d.ts","./node_modules/next/dist/build/analysis/get-page-static-info.d.ts","./node_modules/next/dist/build/webpack/loaders/get-module-build-info.d.ts","./node_modules/next/dist/build/webpack/plugins/middleware-plugin.d.ts","./node_modules/next/dist/server/node-polyfill-crypto.d.ts","./node_modules/next/dist/server/node-environment-baseline.d.ts","./node_modules/next/dist/server/node-environment-extensions/error-inspect.d.ts","./node_modules/next/dist/server/node-environment-extensions/random.d.ts","./node_modules/next/dist/server/node-environment-extensions/date.d.ts","./node_modules/next/dist/server/node-environment-extensions/web-crypto.d.ts","./node_modules/next/dist/server/node-environment-extensions/node-crypto.d.ts","./node_modules/next/dist/server/node-environment.d.ts","./node_modules/next/dist/build/page-extensions-type.d.ts","./node_modules/next/dist/build/webpack/plugins/flight-manifest-plugin.d.ts","./node_modules/next/dist/server/instrumentation/types.d.ts","./node_modules/next/dist/lib/coalesced-function.d.ts","./node_modules/next/dist/shared/lib/router/utils/middleware-route-matcher.d.ts","./node_modules/next/dist/server/lib/router-utils/types.d.ts","./node_modules/next/dist/shared/lib/modern-browserslist-target.d.ts","./node_modules/next/dist/shared/lib/constants.d.ts","./node_modules/next/dist/trace/types.d.ts","./node_modules/next/dist/trace/trace.d.ts","./node_modules/next/dist/trace/shared.d.ts","./node_modules/next/dist/trace/index.d.ts","./node_modules/next/dist/build/load-jsconfig.d.ts","./node_modules/@next/env/dist/index.d.ts","./node_modules/next/dist/build/webpack/plugins/telemetry-plugin/use-cache-tracker-utils.d.ts","./node_modules/next/dist/build/webpack/plugins/telemetry-plugin/telemetry-plugin.d.ts","./node_modules/next/dist/telemetry/storage.d.ts","./node_modules/next/dist/build/build-context.d.ts","./node_modules/next/dist/shared/lib/bloom-filter.d.ts","./node_modules/next/dist/build/webpack-config.d.ts","./node_modules/next/dist/server/route-kind.d.ts","./node_modules/next/dist/server/route-definitions/route-definition.d.ts","./node_modules/next/dist/build/swc/generated-native.d.ts","./node_modules/next/dist/build/swc/types.d.ts","./node_modules/next/dist/server/dev/parse-version-info.d.ts","./node_modules/next/dist/next-devtools/shared/types.d.ts","./node_modules/next/dist/server/dev/dev-indicator-server-state.d.ts","./node_modules/next/dist/server/lib/parse-stack.d.ts","./node_modules/next/dist/next-devtools/server/shared.d.ts","./node_modules/next/dist/next-devtools/shared/stack-frame.d.ts","./node_modules/next/dist/next-devtools/dev-overlay/utils/get-error-by-type.d.ts","./node_modules/@types/react/jsx-runtime.d.ts","./node_modules/next/dist/next-devtools/dev-overlay/container/runtime-error/render-error.d.ts","./node_modules/next/dist/next-devtools/dev-overlay/shared.d.ts","./node_modules/next/dist/server/dev/hot-reloader-types.d.ts","./node_modules/next/dist/server/lib/cache-handlers/types.d.ts","./node_modules/next/dist/server/response-cache/types.d.ts","./node_modules/next/dist/server/resume-data-cache/cache-store.d.ts","./node_modules/next/dist/server/resume-data-cache/resume-data-cache.d.ts","./node_modules/next/dist/server/render-result.d.ts","./node_modules/next/dist/server/lib/i18n-provider.d.ts","./node_modules/next/dist/server/web/next-url.d.ts","./node_modules/next/dist/compiled/@edge-runtime/cookies/index.d.ts","./node_modules/next/dist/server/web/spec-extension/cookies.d.ts","./node_modules/next/dist/server/web/spec-extension/request.d.ts","./node_modules/next/dist/server/after/builtin-request-context.d.ts","./node_modules/next/dist/server/web/spec-extension/fetch-event.d.ts","./node_modules/next/dist/server/web/spec-extension/response.d.ts","./node_modules/next/dist/build/segment-config/middleware/middleware-config.d.ts","./node_modules/next/dist/server/web/types.d.ts","./node_modules/next/dist/build/webpack/plugins/pages-manifest-plugin.d.ts","./node_modules/next/dist/shared/lib/router/utils/parse-url.d.ts","./node_modules/next/dist/server/base-http/node.d.ts","./node_modules/next/dist/build/webpack/plugins/next-font-manifest-plugin.d.ts","./node_modules/next/dist/server/route-definitions/locale-route-definition.d.ts","./node_modules/next/dist/server/route-definitions/pages-route-definition.d.ts","./node_modules/next/dist/shared/lib/mitt.d.ts","./node_modules/next/dist/client/with-router.d.ts","./node_modules/next/dist/client/router.d.ts","./node_modules/next/dist/client/route-loader.d.ts","./node_modules/next/dist/client/page-loader.d.ts","./node_modules/next/dist/shared/lib/router/router.d.ts","./node_modules/next/dist/shared/lib/router-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/loadable-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/loadable.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/image-config-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/hooks-client-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/head-manager-context.shared-runtime.d.ts","./node_modules/next/dist/server/route-definitions/app-page-route-definition.d.ts","./node_modules/next/dist/build/webpack/loaders/metadata/types.d.ts","./node_modules/next/dist/build/webpack/loaders/next-app-loader/index.d.ts","./node_modules/next/dist/server/lib/app-dir-module.d.ts","./node_modules/next/dist/server/web/spec-extension/adapters/request-cookies.d.ts","./node_modules/next/dist/server/async-storage/draft-mode-provider.d.ts","./node_modules/next/dist/server/web/spec-extension/adapters/headers.d.ts","./node_modules/next/dist/server/app-render/cache-signal.d.ts","./node_modules/next/dist/server/app-render/dynamic-rendering.d.ts","./node_modules/next/dist/server/request/fallback-params.d.ts","./node_modules/next/dist/server/app-render/work-unit-async-storage-instance.d.ts","./node_modules/next/dist/server/response-cache/index.d.ts","./node_modules/next/dist/server/lib/lazy-result.d.ts","./node_modules/next/dist/server/lib/implicit-tags.d.ts","./node_modules/next/dist/server/app-render/work-unit-async-storage.external.d.ts","./node_modules/next/dist/shared/lib/deep-readonly.d.ts","./node_modules/next/dist/shared/lib/router/utils/parse-relative-url.d.ts","./node_modules/next/dist/server/app-render/app-render.d.ts","./node_modules/next/dist/shared/lib/server-inserted-html.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/amp-context.shared-runtime.d.ts","./node_modules/next/dist/server/route-modules/app-page/vendored/contexts/entrypoints.d.ts","./node_modules/next/dist/server/route-modules/app-page/module.compiled.d.ts","./node_modules/next/dist/client/components/error-boundary.d.ts","./node_modules/next/dist/client/components/layout-router.d.ts","./node_modules/next/dist/client/components/render-from-template-context.d.ts","./node_modules/next/dist/server/app-render/action-async-storage-instance.d.ts","./node_modules/next/dist/server/app-render/action-async-storage.external.d.ts","./node_modules/next/dist/client/components/client-page.d.ts","./node_modules/next/dist/client/components/client-segment.d.ts","./node_modules/next/dist/server/request/search-params.d.ts","./node_modules/next/dist/client/components/hooks-server-context.d.ts","./node_modules/next/dist/client/components/http-access-fallback/error-boundary.d.ts","./node_modules/next/dist/lib/metadata/types/alternative-urls-types.d.ts","./node_modules/next/dist/lib/metadata/types/extra-types.d.ts","./node_modules/next/dist/lib/metadata/types/metadata-types.d.ts","./node_modules/next/dist/lib/metadata/types/manifest-types.d.ts","./node_modules/next/dist/lib/metadata/types/opengraph-types.d.ts","./node_modules/next/dist/lib/metadata/types/twitter-types.d.ts","./node_modules/next/dist/lib/metadata/types/metadata-interface.d.ts","./node_modules/next/dist/lib/metadata/types/resolvers.d.ts","./node_modules/next/dist/lib/metadata/types/icons.d.ts","./node_modules/next/dist/lib/metadata/resolve-metadata.d.ts","./node_modules/next/dist/lib/metadata/metadata.d.ts","./node_modules/next/dist/lib/framework/boundary-components.d.ts","./node_modules/next/dist/server/app-render/rsc/preloads.d.ts","./node_modules/next/dist/server/app-render/rsc/postpone.d.ts","./node_modules/next/dist/server/app-render/rsc/taint.d.ts","./node_modules/next/dist/shared/lib/segment-cache/segment-value-encoding.d.ts","./node_modules/next/dist/server/app-render/collect-segment-data.d.ts","./node_modules/next/dist/next-devtools/userspace/app/segment-explorer-node.d.ts","./node_modules/next/dist/server/app-render/entry-base.d.ts","./node_modules/next/dist/build/templates/app-page.d.ts","./node_modules/@types/react/jsx-dev-runtime.d.ts","./node_modules/@types/react/compiler-runtime.d.ts","./node_modules/next/dist/server/route-modules/app-page/vendored/rsc/entrypoints.d.ts","./node_modules/@types/react-dom/client.d.ts","./node_modules/@types/react-dom/static.d.ts","./node_modules/@types/react-dom/server.d.ts","./node_modules/next/dist/server/route-modules/app-page/vendored/ssr/entrypoints.d.ts","./node_modules/next/dist/server/route-modules/app-page/module.d.ts","./node_modules/next/dist/server/web/adapter.d.ts","./node_modules/next/dist/server/use-cache/cache-life.d.ts","./node_modules/next/dist/server/app-render/types.d.ts","./node_modules/next/dist/client/components/router-reducer/router-reducer-types.d.ts","./node_modules/next/dist/client/flight-data-helpers.d.ts","./node_modules/next/dist/client/components/router-reducer/fetch-server-response.d.ts","./node_modules/next/dist/shared/lib/app-router-context.shared-runtime.d.ts","./node_modules/next/dist/server/route-modules/pages/vendored/contexts/entrypoints.d.ts","./node_modules/next/dist/server/route-modules/pages/module.compiled.d.ts","./node_modules/next/dist/build/templates/pages.d.ts","./node_modules/next/dist/server/route-modules/pages/module.d.ts","./node_modules/next/dist/next-devtools/userspace/pages/pages-dev-overlay-setup.d.ts","./node_modules/next/dist/server/render.d.ts","./node_modules/next/dist/server/route-definitions/pages-api-route-definition.d.ts","./node_modules/next/dist/server/route-matches/pages-api-route-match.d.ts","./node_modules/next/dist/server/route-matchers/route-matcher.d.ts","./node_modules/next/dist/server/route-matcher-providers/route-matcher-provider.d.ts","./node_modules/next/dist/server/route-matcher-managers/route-matcher-manager.d.ts","./node_modules/next/dist/server/normalizers/normalizer.d.ts","./node_modules/next/dist/server/normalizers/locale-route-normalizer.d.ts","./node_modules/next/dist/server/normalizers/request/pathname-normalizer.d.ts","./node_modules/next/dist/server/normalizers/request/suffix.d.ts","./node_modules/next/dist/server/normalizers/request/rsc.d.ts","./node_modules/next/dist/server/normalizers/request/prefetch-rsc.d.ts","./node_modules/next/dist/server/normalizers/request/next-data.d.ts","./node_modules/next/dist/server/normalizers/request/segment-prefix-rsc.d.ts","./node_modules/next/dist/build/static-paths/types.d.ts","./node_modules/next/dist/server/base-server.d.ts","./node_modules/next/dist/server/lib/async-callback-set.d.ts","./node_modules/next/dist/shared/lib/router/utils/route-regex.d.ts","./node_modules/next/dist/shared/lib/router/utils/route-matcher.d.ts","./node_modules/sharp/lib/index.d.ts","./node_modules/next/dist/server/image-optimizer.d.ts","./node_modules/next/dist/server/next-server.d.ts","./node_modules/next/dist/server/lib/types.d.ts","./node_modules/next/dist/server/lib/lru-cache.d.ts","./node_modules/next/dist/server/lib/dev-bundler-service.d.ts","./node_modules/next/dist/server/dev/static-paths-worker.d.ts","./node_modules/next/dist/server/dev/next-dev-server.d.ts","./node_modules/next/dist/server/next.d.ts","./node_modules/next/dist/server/lib/render-server.d.ts","./node_modules/next/dist/server/lib/router-server.d.ts","./node_modules/next/dist/shared/lib/router/utils/path-match.d.ts","./node_modules/next/dist/server/lib/router-utils/filesystem.d.ts","./node_modules/next/dist/server/lib/router-utils/setup-dev-bundler.d.ts","./node_modules/next/dist/server/lib/router-utils/router-server-context.d.ts","./node_modules/next/dist/server/route-modules/route-module.d.ts","./node_modules/next/dist/server/load-components.d.ts","./node_modules/next/dist/server/route-definitions/app-route-route-definition.d.ts","./node_modules/next/dist/server/async-storage/work-store.d.ts","./node_modules/next/dist/server/web/http.d.ts","./node_modules/next/dist/server/route-modules/app-route/shared-modules.d.ts","./node_modules/next/dist/client/components/redirect-status-code.d.ts","./node_modules/next/dist/client/components/redirect-error.d.ts","./node_modules/next/dist/build/templates/app-route.d.ts","./node_modules/next/dist/server/route-modules/app-route/module.d.ts","./node_modules/next/dist/server/route-modules/app-route/module.compiled.d.ts","./node_modules/next/dist/build/segment-config/app/app-segments.d.ts","./node_modules/next/dist/build/utils.d.ts","./node_modules/next/dist/build/turborepo-access-trace/types.d.ts","./node_modules/next/dist/build/turborepo-access-trace/result.d.ts","./node_modules/next/dist/build/turborepo-access-trace/helpers.d.ts","./node_modules/next/dist/build/turborepo-access-trace/index.d.ts","./node_modules/next/dist/export/routes/types.d.ts","./node_modules/next/dist/export/types.d.ts","./node_modules/next/dist/export/worker.d.ts","./node_modules/next/dist/build/worker.d.ts","./node_modules/next/dist/build/index.d.ts","./node_modules/next/dist/server/lib/incremental-cache/index.d.ts","./node_modules/next/dist/server/after/after.d.ts","./node_modules/next/dist/server/after/after-context.d.ts","./node_modules/next/dist/server/app-render/work-async-storage-instance.d.ts","./node_modules/next/dist/server/app-render/work-async-storage.external.d.ts","./node_modules/next/dist/server/request/params.d.ts","./node_modules/next/dist/server/route-matches/route-match.d.ts","./node_modules/next/dist/server/request-meta.d.ts","./node_modules/next/dist/cli/next-test.d.ts","./node_modules/next/dist/server/config-shared.d.ts","./node_modules/next/dist/server/base-http/index.d.ts","./node_modules/next/dist/server/api-utils/index.d.ts","./node_modules/next/dist/types.d.ts","./node_modules/next/dist/shared/lib/html-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/utils.d.ts","./node_modules/next/dist/pages/_app.d.ts","./node_modules/next/app.d.ts","./node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts","./node_modules/next/dist/server/web/spec-extension/revalidate.d.ts","./node_modules/next/dist/server/web/spec-extension/unstable-no-store.d.ts","./node_modules/next/dist/server/use-cache/cache-tag.d.ts","./node_modules/next/cache.d.ts","./node_modules/next/dist/shared/lib/runtime-config.external.d.ts","./node_modules/next/config.d.ts","./node_modules/next/dist/pages/_document.d.ts","./node_modules/next/document.d.ts","./node_modules/next/dist/shared/lib/dynamic.d.ts","./node_modules/next/dynamic.d.ts","./node_modules/next/dist/pages/_error.d.ts","./node_modules/next/error.d.ts","./node_modules/next/dist/shared/lib/head.d.ts","./node_modules/next/head.d.ts","./node_modules/next/dist/server/request/cookies.d.ts","./node_modules/next/dist/server/request/headers.d.ts","./node_modules/next/dist/server/request/draft-mode.d.ts","./node_modules/next/headers.d.ts","./node_modules/next/dist/shared/lib/get-img-props.d.ts","./node_modules/next/dist/client/image-component.d.ts","./node_modules/next/dist/shared/lib/image-external.d.ts","./node_modules/next/image.d.ts","./node_modules/next/dist/client/link.d.ts","./node_modules/next/link.d.ts","./node_modules/next/dist/client/components/redirect.d.ts","./node_modules/next/dist/client/components/not-found.d.ts","./node_modules/next/dist/client/components/forbidden.d.ts","./node_modules/next/dist/client/components/unauthorized.d.ts","./node_modules/next/dist/client/components/unstable-rethrow.server.d.ts","./node_modules/next/dist/client/components/unstable-rethrow.d.ts","./node_modules/next/dist/client/components/navigation.react-server.d.ts","./node_modules/next/dist/client/components/unrecognized-action-error.d.ts","./node_modules/next/dist/client/components/navigation.d.ts","./node_modules/next/navigation.d.ts","./node_modules/next/router.d.ts","./node_modules/next/dist/client/script.d.ts","./node_modules/next/script.d.ts","./node_modules/next/dist/server/web/spec-extension/user-agent.d.ts","./node_modules/next/dist/compiled/@edge-runtime/primitives/url.d.ts","./node_modules/next/dist/server/web/spec-extension/image-response.d.ts","./node_modules/next/dist/compiled/@vercel/og/satori/index.d.ts","./node_modules/next/dist/compiled/@vercel/og/emoji/index.d.ts","./node_modules/next/dist/compiled/@vercel/og/types.d.ts","./node_modules/next/dist/server/after/index.d.ts","./node_modules/next/dist/server/request/root-params.d.ts","./node_modules/next/dist/server/request/connection.d.ts","./node_modules/next/server.d.ts","./node_modules/next/types/global.d.ts","./node_modules/next/types/compiled.d.ts","./node_modules/next/types.d.ts","./node_modules/next/index.d.ts","./node_modules/next/image-types/global.d.ts","./next-env.d.ts","./next.config.ts","./node_modules/@types/http-proxy/index.d.ts","./server.ts","./node_modules/@vitest/spy/dist/index.d.ts","./node_modules/@vitest/pretty-format/dist/index.d.ts","./node_modules/@vitest/utils/dist/types.d.ts","./node_modules/@vitest/utils/dist/helpers.d.ts","./node_modules/tinyrainbow/dist/index-8b61d5bc.d.ts","./node_modules/tinyrainbow/dist/node.d.ts","./node_modules/@vitest/utils/dist/index.d.ts","./node_modules/@vitest/utils/dist/types.d-bcelap-c.d.ts","./node_modules/@vitest/utils/dist/diff.d.ts","./node_modules/@vitest/expect/dist/index.d.ts","./node_modules/vite/types/hmrpayload.d.ts","./node_modules/vite/dist/node/chunks/modulerunnertransport.d.ts","./node_modules/vite/types/customevent.d.ts","./node_modules/@types/estree/index.d.ts","./node_modules/rollup/dist/rollup.d.ts","./node_modules/rollup/dist/parseast.d.ts","./node_modules/vite/types/hot.d.ts","./node_modules/vite/dist/node/module-runner.d.ts","./node_modules/esbuild/lib/main.d.ts","./node_modules/vite/types/internal/terseroptions.d.ts","./node_modules/source-map-js/source-map.d.ts","./node_modules/postcss/lib/previous-map.d.ts","./node_modules/postcss/lib/input.d.ts","./node_modules/postcss/lib/css-syntax-error.d.ts","./node_modules/postcss/lib/declaration.d.ts","./node_modules/postcss/lib/root.d.ts","./node_modules/postcss/lib/warning.d.ts","./node_modules/postcss/lib/lazy-result.d.ts","./node_modules/postcss/lib/no-work-result.d.ts","./node_modules/postcss/lib/processor.d.ts","./node_modules/postcss/lib/result.d.ts","./node_modules/postcss/lib/document.d.ts","./node_modules/postcss/lib/rule.d.ts","./node_modules/postcss/lib/node.d.ts","./node_modules/postcss/lib/comment.d.ts","./node_modules/postcss/lib/container.d.ts","./node_modules/postcss/lib/at-rule.d.ts","./node_modules/postcss/lib/list.d.ts","./node_modules/postcss/lib/postcss.d.ts","./node_modules/postcss/lib/postcss.d.mts","./node_modules/vite/types/internal/csspreprocessoroptions.d.ts","./node_modules/lightningcss/node/ast.d.ts","./node_modules/lightningcss/node/targets.d.ts","./node_modules/lightningcss/node/index.d.ts","./node_modules/vite/types/internal/lightningcssoptions.d.ts","./node_modules/vite/types/importglob.d.ts","./node_modules/vite/types/metadata.d.ts","./node_modules/vite/dist/node/index.d.ts","./node_modules/@vitest/runner/dist/tasks.d-cksck4of.d.ts","./node_modules/@vitest/runner/dist/types.d.ts","./node_modules/@vitest/utils/dist/error.d.ts","./node_modules/@vitest/runner/dist/index.d.ts","./node_modules/vitest/optional-types.d.ts","./node_modules/vitest/dist/chunks/environment.d.cl3nlxbe.d.ts","./node_modules/@vitest/mocker/dist/registry.d-d765pazg.d.ts","./node_modules/@vitest/mocker/dist/types.d-d_arzrdy.d.ts","./node_modules/@vitest/mocker/dist/index.d.ts","./node_modules/@vitest/utils/dist/source-map.d.ts","./node_modules/vite-node/dist/trace-mapping.d-dlvdeqop.d.ts","./node_modules/vite-node/dist/index.d-dgmxd2u7.d.ts","./node_modules/vite-node/dist/index.d.ts","./node_modules/@vitest/snapshot/dist/environment.d-dhdq1csl.d.ts","./node_modules/@vitest/snapshot/dist/rawsnapshot.d-lfsmjfud.d.ts","./node_modules/@vitest/snapshot/dist/index.d.ts","./node_modules/@vitest/snapshot/dist/environment.d.ts","./node_modules/vitest/dist/chunks/config.d.d2roskhv.d.ts","./node_modules/vitest/dist/chunks/worker.d.1gmbbd7g.d.ts","./node_modules/@types/deep-eql/index.d.ts","./node_modules/assertion-error/index.d.ts","./node_modules/@types/chai/index.d.ts","./node_modules/@vitest/runner/dist/utils.d.ts","./node_modules/tinybench/dist/index.d.ts","./node_modules/vitest/dist/chunks/benchmark.d.bwvbvtda.d.ts","./node_modules/vite-node/dist/client.d.ts","./node_modules/vitest/dist/chunks/coverage.d.s9rmnxie.d.ts","./node_modules/@vitest/snapshot/dist/manager.d.ts","./node_modules/vitest/dist/chunks/reporters.d.bflkqcl6.d.ts","./node_modules/vitest/dist/chunks/vite.d.cmlllifp.d.ts","./node_modules/vitest/dist/config.d.ts","./node_modules/vitest/config.d.ts","./node_modules/@babel/types/lib/index.d.ts","./node_modules/@types/babel__generator/index.d.ts","./node_modules/@babel/parser/typings/babel-parser.d.ts","./node_modules/@types/babel__template/index.d.ts","./node_modules/@types/babel__traverse/index.d.ts","./node_modules/@types/babel__core/index.d.ts","./node_modules/@vitejs/plugin-react/dist/index.d.ts","./vitest.config.ts","./src/middleware.ts","./node_modules/vitest/dist/chunks/worker.d.ckwwzbsj.d.ts","./node_modules/vitest/dist/chunks/global.d.mamajcmj.d.ts","./node_modules/vitest/dist/chunks/mocker.d.be_2ls6u.d.ts","./node_modules/vitest/dist/chunks/suite.d.fvehnv49.d.ts","./node_modules/expect-type/dist/utils.d.ts","./node_modules/expect-type/dist/overloads.d.ts","./node_modules/expect-type/dist/branding.d.ts","./node_modules/expect-type/dist/messages.d.ts","./node_modules/expect-type/dist/index.d.ts","./node_modules/vitest/dist/index.d.ts","./node_modules/clsx/clsx.d.mts","./node_modules/tailwind-merge/dist/types.d.ts","./src/lib/utils.ts","./src/__tests__/utils.test.ts","./node_modules/better-auth/dist/types/helper.d.mts","./node_modules/@better-auth/core/dist/index-brbu0-5h.d.mts","./node_modules/zod/v4/core/json-schema.d.cts","./node_modules/zod/v4/core/standard-schema.d.cts","./node_modules/zod/v4/core/registries.d.cts","./node_modules/zod/v4/core/to-json-schema.d.cts","./node_modules/zod/v4/core/util.d.cts","./node_modules/zod/v4/core/versions.d.cts","./node_modules/zod/v4/core/schemas.d.cts","./node_modules/zod/v4/core/checks.d.cts","./node_modules/zod/v4/core/errors.d.cts","./node_modules/zod/v4/core/core.d.cts","./node_modules/zod/v4/core/parse.d.cts","./node_modules/zod/v4/core/regexes.d.cts","./node_modules/zod/v4/locales/ar.d.cts","./node_modules/zod/v4/locales/az.d.cts","./node_modules/zod/v4/locales/be.d.cts","./node_modules/zod/v4/locales/bg.d.cts","./node_modules/zod/v4/locales/ca.d.cts","./node_modules/zod/v4/locales/cs.d.cts","./node_modules/zod/v4/locales/da.d.cts","./node_modules/zod/v4/locales/de.d.cts","./node_modules/zod/v4/locales/en.d.cts","./node_modules/zod/v4/locales/eo.d.cts","./node_modules/zod/v4/locales/es.d.cts","./node_modules/zod/v4/locales/fa.d.cts","./node_modules/zod/v4/locales/fi.d.cts","./node_modules/zod/v4/locales/fr.d.cts","./node_modules/zod/v4/locales/fr-ca.d.cts","./node_modules/zod/v4/locales/he.d.cts","./node_modules/zod/v4/locales/hu.d.cts","./node_modules/zod/v4/locales/hy.d.cts","./node_modules/zod/v4/locales/id.d.cts","./node_modules/zod/v4/locales/is.d.cts","./node_modules/zod/v4/locales/it.d.cts","./node_modules/zod/v4/locales/ja.d.cts","./node_modules/zod/v4/locales/ka.d.cts","./node_modules/zod/v4/locales/kh.d.cts","./node_modules/zod/v4/locales/km.d.cts","./node_modules/zod/v4/locales/ko.d.cts","./node_modules/zod/v4/locales/lt.d.cts","./node_modules/zod/v4/locales/mk.d.cts","./node_modules/zod/v4/locales/ms.d.cts","./node_modules/zod/v4/locales/nl.d.cts","./node_modules/zod/v4/locales/no.d.cts","./node_modules/zod/v4/locales/ota.d.cts","./node_modules/zod/v4/locales/ps.d.cts","./node_modules/zod/v4/locales/pl.d.cts","./node_modules/zod/v4/locales/pt.d.cts","./node_modules/zod/v4/locales/ru.d.cts","./node_modules/zod/v4/locales/sl.d.cts","./node_modules/zod/v4/locales/sv.d.cts","./node_modules/zod/v4/locales/ta.d.cts","./node_modules/zod/v4/locales/th.d.cts","./node_modules/zod/v4/locales/tr.d.cts","./node_modules/zod/v4/locales/ua.d.cts","./node_modules/zod/v4/locales/uk.d.cts","./node_modules/zod/v4/locales/ur.d.cts","./node_modules/zod/v4/locales/uz.d.cts","./node_modules/zod/v4/locales/vi.d.cts","./node_modules/zod/v4/locales/zh-cn.d.cts","./node_modules/zod/v4/locales/zh-tw.d.cts","./node_modules/zod/v4/locales/yo.d.cts","./node_modules/zod/v4/locales/index.d.cts","./node_modules/zod/v4/core/doc.d.cts","./node_modules/zod/v4/core/api.d.cts","./node_modules/zod/v4/core/json-schema-processors.d.cts","./node_modules/zod/v4/core/json-schema-generator.d.cts","./node_modules/zod/v4/core/index.d.cts","./node_modules/zod/v4/classic/errors.d.cts","./node_modules/zod/v4/classic/parse.d.cts","./node_modules/zod/v4/classic/schemas.d.cts","./node_modules/zod/v4/classic/checks.d.cts","./node_modules/zod/v4/classic/compat.d.cts","./node_modules/zod/v4/classic/from-json-schema.d.cts","./node_modules/zod/v4/classic/iso.d.cts","./node_modules/zod/v4/classic/coerce.d.cts","./node_modules/zod/v4/classic/external.d.cts","./node_modules/zod/index.d.cts","./node_modules/@better-fetch/fetch/dist/index.d.ts","./node_modules/jose/dist/types/types.d.ts","./node_modules/jose/dist/types/jwe/compact/decrypt.d.ts","./node_modules/jose/dist/types/jwe/flattened/decrypt.d.ts","./node_modules/jose/dist/types/jwe/general/decrypt.d.ts","./node_modules/jose/dist/types/jwe/general/encrypt.d.ts","./node_modules/jose/dist/types/jws/compact/verify.d.ts","./node_modules/jose/dist/types/jws/flattened/verify.d.ts","./node_modules/jose/dist/types/jws/general/verify.d.ts","./node_modules/jose/dist/types/jwt/verify.d.ts","./node_modules/jose/dist/types/jwt/decrypt.d.ts","./node_modules/jose/dist/types/jwe/compact/encrypt.d.ts","./node_modules/jose/dist/types/jwe/flattened/encrypt.d.ts","./node_modules/jose/dist/types/jws/compact/sign.d.ts","./node_modules/jose/dist/types/jws/flattened/sign.d.ts","./node_modules/jose/dist/types/jws/general/sign.d.ts","./node_modules/jose/dist/types/jwt/sign.d.ts","./node_modules/jose/dist/types/jwt/encrypt.d.ts","./node_modules/jose/dist/types/jwk/thumbprint.d.ts","./node_modules/jose/dist/types/jwk/embedded.d.ts","./node_modules/jose/dist/types/jwks/local.d.ts","./node_modules/jose/dist/types/jwks/remote.d.ts","./node_modules/jose/dist/types/jwt/unsecured.d.ts","./node_modules/jose/dist/types/key/export.d.ts","./node_modules/jose/dist/types/key/import.d.ts","./node_modules/jose/dist/types/util/decode_protected_header.d.ts","./node_modules/jose/dist/types/util/decode_jwt.d.ts","./node_modules/jose/dist/types/util/errors.d.ts","./node_modules/jose/dist/types/key/generate_key_pair.d.ts","./node_modules/jose/dist/types/key/generate_secret.d.ts","./node_modules/jose/dist/types/util/base64url.d.ts","./node_modules/jose/dist/types/index.d.ts","./node_modules/better-call/dist/router.d.ts","./node_modules/better-call/dist/index.d.ts","./node_modules/@standard-schema/spec/dist/index.d.ts","./node_modules/kysely/dist/esm/operation-node/operation-node.d.ts","./node_modules/kysely/dist/esm/operation-node/identifier-node.d.ts","./node_modules/kysely/dist/esm/operation-node/check-constraint-node.d.ts","./node_modules/kysely/dist/esm/operation-node/column-node.d.ts","./node_modules/kysely/dist/esm/operation-node/default-value-node.d.ts","./node_modules/kysely/dist/esm/operation-node/generated-node.d.ts","./node_modules/kysely/dist/esm/operation-node/schemable-identifier-node.d.ts","./node_modules/kysely/dist/esm/operation-node/table-node.d.ts","./node_modules/kysely/dist/esm/query-builder/insert-result.d.ts","./node_modules/kysely/dist/esm/query-builder/delete-result.d.ts","./node_modules/kysely/dist/esm/query-builder/update-result.d.ts","./node_modules/kysely/dist/esm/util/type-error.d.ts","./node_modules/kysely/dist/esm/query-builder/merge-result.d.ts","./node_modules/kysely/dist/esm/util/type-utils.d.ts","./node_modules/kysely/dist/esm/operation-node/references-node.d.ts","./node_modules/kysely/dist/esm/operation-node/column-definition-node.d.ts","./node_modules/kysely/dist/esm/operation-node/add-column-node.d.ts","./node_modules/kysely/dist/esm/operation-node/drop-column-node.d.ts","./node_modules/kysely/dist/esm/operation-node/rename-column-node.d.ts","./node_modules/kysely/dist/esm/operation-node/raw-node.d.ts","./node_modules/kysely/dist/esm/operation-node/alter-column-node.d.ts","./node_modules/kysely/dist/esm/operation-node/foreign-key-constraint-node.d.ts","./node_modules/kysely/dist/esm/operation-node/primary-key-constraint-node.d.ts","./node_modules/kysely/dist/esm/operation-node/unique-constraint-node.d.ts","./node_modules/kysely/dist/esm/operation-node/constraint-node.d.ts","./node_modules/kysely/dist/esm/operation-node/add-constraint-node.d.ts","./node_modules/kysely/dist/esm/operation-node/drop-constraint-node.d.ts","./node_modules/kysely/dist/esm/operation-node/modify-column-node.d.ts","./node_modules/kysely/dist/esm/operation-node/drop-index-node.d.ts","./node_modules/kysely/dist/esm/operation-node/add-index-node.d.ts","./node_modules/kysely/dist/esm/operation-node/rename-constraint-node.d.ts","./node_modules/kysely/dist/esm/operation-node/alter-table-node.d.ts","./node_modules/kysely/dist/esm/operation-node/where-node.d.ts","./node_modules/kysely/dist/esm/operation-node/create-index-node.d.ts","./node_modules/kysely/dist/esm/operation-node/create-schema-node.d.ts","./node_modules/kysely/dist/esm/operation-node/create-table-node.d.ts","./node_modules/kysely/dist/esm/operation-node/value-list-node.d.ts","./node_modules/kysely/dist/esm/operation-node/create-type-node.d.ts","./node_modules/kysely/dist/esm/operation-node/from-node.d.ts","./node_modules/kysely/dist/esm/operation-node/group-by-item-node.d.ts","./node_modules/kysely/dist/esm/operation-node/group-by-node.d.ts","./node_modules/kysely/dist/esm/operation-node/having-node.d.ts","./node_modules/kysely/dist/esm/operation-node/on-node.d.ts","./node_modules/kysely/dist/esm/operation-node/join-node.d.ts","./node_modules/kysely/dist/esm/operation-node/limit-node.d.ts","./node_modules/kysely/dist/esm/operation-node/offset-node.d.ts","./node_modules/kysely/dist/esm/operation-node/collate-node.d.ts","./node_modules/kysely/dist/esm/operation-node/order-by-item-node.d.ts","./node_modules/kysely/dist/esm/operation-node/order-by-node.d.ts","./node_modules/kysely/dist/esm/operation-node/alias-node.d.ts","./node_modules/kysely/dist/esm/operation-node/select-all-node.d.ts","./node_modules/kysely/dist/esm/operation-node/reference-node.d.ts","./node_modules/kysely/dist/esm/operation-node/simple-reference-expression-node.d.ts","./node_modules/kysely/dist/esm/operation-node/selection-node.d.ts","./node_modules/kysely/dist/esm/operation-node/common-table-expression-name-node.d.ts","./node_modules/kysely/dist/esm/operation-node/common-table-expression-node.d.ts","./node_modules/kysely/dist/esm/operation-node/with-node.d.ts","./node_modules/kysely/dist/esm/operation-node/select-modifier-node.d.ts","./node_modules/kysely/dist/esm/operation-node/operation-node-source.d.ts","./node_modules/kysely/dist/esm/expression/expression.d.ts","./node_modules/kysely/dist/esm/util/explainable.d.ts","./node_modules/kysely/dist/esm/operation-node/explain-node.d.ts","./node_modules/kysely/dist/esm/operation-node/set-operation-node.d.ts","./node_modules/kysely/dist/esm/operation-node/value-node.d.ts","./node_modules/kysely/dist/esm/operation-node/fetch-node.d.ts","./node_modules/kysely/dist/esm/operation-node/top-node.d.ts","./node_modules/kysely/dist/esm/operation-node/select-query-node.d.ts","./node_modules/kysely/dist/esm/operation-node/create-view-node.d.ts","./node_modules/kysely/dist/esm/operation-node/drop-schema-node.d.ts","./node_modules/kysely/dist/esm/operation-node/drop-table-node.d.ts","./node_modules/kysely/dist/esm/operation-node/drop-type-node.d.ts","./node_modules/kysely/dist/esm/operation-node/drop-view-node.d.ts","./node_modules/kysely/dist/esm/operation-node/output-node.d.ts","./node_modules/kysely/dist/esm/operation-node/returning-node.d.ts","./node_modules/kysely/dist/esm/operation-node/when-node.d.ts","./node_modules/kysely/dist/esm/operation-node/merge-query-node.d.ts","./node_modules/kysely/dist/esm/operation-node/column-update-node.d.ts","./node_modules/kysely/dist/esm/operation-node/on-conflict-node.d.ts","./node_modules/kysely/dist/esm/operation-node/on-duplicate-key-node.d.ts","./node_modules/kysely/dist/esm/operation-node/or-action-node.d.ts","./node_modules/kysely/dist/esm/operation-node/insert-query-node.d.ts","./node_modules/kysely/dist/esm/operation-node/update-query-node.d.ts","./node_modules/kysely/dist/esm/operation-node/using-node.d.ts","./node_modules/kysely/dist/esm/operation-node/delete-query-node.d.ts","./node_modules/kysely/dist/esm/operation-node/query-node.d.ts","./node_modules/kysely/dist/esm/operation-node/refresh-materialized-view-node.d.ts","./node_modules/kysely/dist/esm/util/query-id.d.ts","./node_modules/kysely/dist/esm/query-compiler/compiled-query.d.ts","./node_modules/kysely/dist/esm/query-compiler/query-compiler.d.ts","./node_modules/kysely/dist/esm/driver/database-connection.d.ts","./node_modules/kysely/dist/esm/driver/driver.d.ts","./node_modules/kysely/dist/esm/dialect/database-introspector.d.ts","./node_modules/kysely/dist/esm/dialect/dialect-adapter.d.ts","./node_modules/kysely/dist/esm/dialect/dialect.d.ts","./node_modules/kysely/dist/esm/driver/connection-provider.d.ts","./node_modules/kysely/dist/esm/plugin/kysely-plugin.d.ts","./node_modules/kysely/dist/esm/query-executor/query-executor.d.ts","./node_modules/kysely/dist/esm/util/compilable.d.ts","./node_modules/kysely/dist/esm/parser/default-value-parser.d.ts","./node_modules/kysely/dist/esm/schema/column-definition-builder.d.ts","./node_modules/kysely/dist/esm/operation-node/data-type-node.d.ts","./node_modules/kysely/dist/esm/parser/data-type-parser.d.ts","./node_modules/kysely/dist/esm/schema/foreign-key-constraint-builder.d.ts","./node_modules/kysely/dist/esm/schema/alter-column-builder.d.ts","./node_modules/kysely/dist/esm/schema/alter-table-executor.d.ts","./node_modules/kysely/dist/esm/schema/alter-table-add-foreign-key-constraint-builder.d.ts","./node_modules/kysely/dist/esm/schema/alter-table-drop-constraint-builder.d.ts","./node_modules/kysely/dist/esm/query-builder/select-query-builder-expression.d.ts","./node_modules/kysely/dist/esm/operation-node/binary-operation-node.d.ts","./node_modules/kysely/dist/esm/operation-node/operator-node.d.ts","./node_modules/kysely/dist/esm/parser/value-parser.d.ts","./node_modules/kysely/dist/esm/util/column-type.d.ts","./node_modules/kysely/dist/esm/parser/binary-operation-parser.d.ts","./node_modules/kysely/dist/esm/query-builder/join-builder.d.ts","./node_modules/kysely/dist/esm/dynamic/dynamic-table-builder.d.ts","./node_modules/kysely/dist/esm/parser/table-parser.d.ts","./node_modules/kysely/dist/esm/parser/join-parser.d.ts","./node_modules/kysely/dist/esm/dynamic/dynamic-reference-builder.d.ts","./node_modules/kysely/dist/esm/parser/select-parser.d.ts","./node_modules/kysely/dist/esm/parser/collate-parser.d.ts","./node_modules/kysely/dist/esm/query-builder/order-by-item-builder.d.ts","./node_modules/kysely/dist/esm/parser/order-by-parser.d.ts","./node_modules/kysely/dist/esm/parser/group-by-parser.d.ts","./node_modules/kysely/dist/esm/query-builder/where-interface.d.ts","./node_modules/kysely/dist/esm/query-builder/no-result-error.d.ts","./node_modules/kysely/dist/esm/query-builder/having-interface.d.ts","./node_modules/kysely/dist/esm/parser/set-operation-parser.d.ts","./node_modules/kysely/dist/esm/util/streamable.d.ts","./node_modules/kysely/dist/esm/operation-node/and-node.d.ts","./node_modules/kysely/dist/esm/operation-node/or-node.d.ts","./node_modules/kysely/dist/esm/operation-node/parens-node.d.ts","./node_modules/kysely/dist/esm/expression/expression-wrapper.d.ts","./node_modules/kysely/dist/esm/query-builder/order-by-interface.d.ts","./node_modules/kysely/dist/esm/query-builder/select-query-builder.d.ts","./node_modules/kysely/dist/esm/parser/coalesce-parser.d.ts","./node_modules/kysely/dist/esm/operation-node/partition-by-item-node.d.ts","./node_modules/kysely/dist/esm/operation-node/partition-by-node.d.ts","./node_modules/kysely/dist/esm/operation-node/over-node.d.ts","./node_modules/kysely/dist/esm/operation-node/aggregate-function-node.d.ts","./node_modules/kysely/dist/esm/parser/partition-by-parser.d.ts","./node_modules/kysely/dist/esm/query-builder/over-builder.d.ts","./node_modules/kysely/dist/esm/query-builder/aggregate-function-builder.d.ts","./node_modules/kysely/dist/esm/query-builder/function-module.d.ts","./node_modules/kysely/dist/esm/operation-node/case-node.d.ts","./node_modules/kysely/dist/esm/query-builder/case-builder.d.ts","./node_modules/kysely/dist/esm/operation-node/json-path-leg-node.d.ts","./node_modules/kysely/dist/esm/operation-node/json-path-node.d.ts","./node_modules/kysely/dist/esm/operation-node/json-operator-chain-node.d.ts","./node_modules/kysely/dist/esm/operation-node/json-reference-node.d.ts","./node_modules/kysely/dist/esm/query-builder/json-path-builder.d.ts","./node_modules/kysely/dist/esm/parser/tuple-parser.d.ts","./node_modules/kysely/dist/esm/parser/select-from-parser.d.ts","./node_modules/kysely/dist/esm/expression/expression-builder.d.ts","./node_modules/kysely/dist/esm/parser/expression-parser.d.ts","./node_modules/kysely/dist/esm/parser/reference-parser.d.ts","./node_modules/kysely/dist/esm/schema/alter-table-add-index-builder.d.ts","./node_modules/kysely/dist/esm/schema/unique-constraint-builder.d.ts","./node_modules/kysely/dist/esm/schema/primary-key-constraint-builder.d.ts","./node_modules/kysely/dist/esm/schema/check-constraint-builder.d.ts","./node_modules/kysely/dist/esm/schema/alter-table-builder.d.ts","./node_modules/kysely/dist/esm/schema/create-index-builder.d.ts","./node_modules/kysely/dist/esm/schema/create-schema-builder.d.ts","./node_modules/kysely/dist/esm/schema/create-table-builder.d.ts","./node_modules/kysely/dist/esm/schema/drop-index-builder.d.ts","./node_modules/kysely/dist/esm/schema/drop-schema-builder.d.ts","./node_modules/kysely/dist/esm/schema/drop-table-builder.d.ts","./node_modules/kysely/dist/esm/query-executor/query-executor-provider.d.ts","./node_modules/kysely/dist/esm/raw-builder/raw-builder.d.ts","./node_modules/kysely/dist/esm/schema/create-view-builder.d.ts","./node_modules/kysely/dist/esm/schema/drop-view-builder.d.ts","./node_modules/kysely/dist/esm/schema/create-type-builder.d.ts","./node_modules/kysely/dist/esm/schema/drop-type-builder.d.ts","./node_modules/kysely/dist/esm/schema/refresh-materialized-view-builder.d.ts","./node_modules/kysely/dist/esm/schema/schema.d.ts","./node_modules/kysely/dist/esm/dynamic/dynamic.d.ts","./node_modules/kysely/dist/esm/operation-node/primitive-value-list-node.d.ts","./node_modules/kysely/dist/esm/operation-node/values-node.d.ts","./node_modules/kysely/dist/esm/parser/insert-values-parser.d.ts","./node_modules/kysely/dist/esm/parser/update-set-parser.d.ts","./node_modules/kysely/dist/esm/parser/returning-parser.d.ts","./node_modules/kysely/dist/esm/query-builder/returning-interface.d.ts","./node_modules/kysely/dist/esm/query-builder/on-conflict-builder.d.ts","./node_modules/kysely/dist/esm/query-builder/output-interface.d.ts","./node_modules/kysely/dist/esm/query-builder/insert-query-builder.d.ts","./node_modules/kysely/dist/esm/query-builder/update-query-builder.d.ts","./node_modules/kysely/dist/esm/query-builder/delete-query-builder.d.ts","./node_modules/kysely/dist/esm/query-builder/cte-builder.d.ts","./node_modules/kysely/dist/esm/parser/with-parser.d.ts","./node_modules/kysely/dist/esm/parser/delete-from-parser.d.ts","./node_modules/kysely/dist/esm/parser/update-parser.d.ts","./node_modules/kysely/dist/esm/query-builder/merge-query-builder.d.ts","./node_modules/kysely/dist/esm/parser/merge-into-parser.d.ts","./node_modules/kysely/dist/esm/query-creator.d.ts","./node_modules/kysely/dist/esm/util/log.d.ts","./node_modules/kysely/dist/esm/parser/savepoint-parser.d.ts","./node_modules/kysely/dist/esm/util/provide-controlled-connection.d.ts","./node_modules/kysely/dist/esm/kysely.d.ts","./node_modules/kysely/dist/esm/raw-builder/sql.d.ts","./node_modules/kysely/dist/esm/query-executor/query-executor-base.d.ts","./node_modules/kysely/dist/esm/query-executor/default-query-executor.d.ts","./node_modules/kysely/dist/esm/query-executor/noop-query-executor.d.ts","./node_modules/kysely/dist/esm/operation-node/list-node.d.ts","./node_modules/kysely/dist/esm/operation-node/default-insert-value-node.d.ts","./node_modules/kysely/dist/esm/operation-node/unary-operation-node.d.ts","./node_modules/kysely/dist/esm/operation-node/function-node.d.ts","./node_modules/kysely/dist/esm/operation-node/tuple-node.d.ts","./node_modules/kysely/dist/esm/operation-node/matched-node.d.ts","./node_modules/kysely/dist/esm/operation-node/cast-node.d.ts","./node_modules/kysely/dist/esm/operation-node/operation-node-visitor.d.ts","./node_modules/kysely/dist/esm/query-compiler/default-query-compiler.d.ts","./node_modules/kysely/dist/esm/driver/default-connection-provider.d.ts","./node_modules/kysely/dist/esm/driver/single-connection-provider.d.ts","./node_modules/kysely/dist/esm/driver/dummy-driver.d.ts","./node_modules/kysely/dist/esm/dialect/dialect-adapter-base.d.ts","./node_modules/kysely/dist/esm/dialect/sqlite/sqlite-dialect-config.d.ts","./node_modules/kysely/dist/esm/dialect/sqlite/sqlite-dialect.d.ts","./node_modules/kysely/dist/esm/dialect/sqlite/sqlite-driver.d.ts","./node_modules/kysely/dist/esm/dialect/postgres/postgres-query-compiler.d.ts","./node_modules/kysely/dist/esm/dialect/postgres/postgres-introspector.d.ts","./node_modules/kysely/dist/esm/dialect/postgres/postgres-adapter.d.ts","./node_modules/kysely/dist/esm/dialect/mysql/mysql-dialect-config.d.ts","./node_modules/kysely/dist/esm/dialect/mysql/mysql-dialect.d.ts","./node_modules/kysely/dist/esm/dialect/mysql/mysql-driver.d.ts","./node_modules/kysely/dist/esm/dialect/mysql/mysql-query-compiler.d.ts","./node_modules/kysely/dist/esm/dialect/mysql/mysql-introspector.d.ts","./node_modules/kysely/dist/esm/dialect/mysql/mysql-adapter.d.ts","./node_modules/kysely/dist/esm/dialect/postgres/postgres-dialect-config.d.ts","./node_modules/kysely/dist/esm/dialect/postgres/postgres-driver.d.ts","./node_modules/kysely/dist/esm/dialect/postgres/postgres-dialect.d.ts","./node_modules/kysely/dist/esm/dialect/sqlite/sqlite-query-compiler.d.ts","./node_modules/kysely/dist/esm/dialect/sqlite/sqlite-introspector.d.ts","./node_modules/kysely/dist/esm/dialect/sqlite/sqlite-adapter.d.ts","./node_modules/kysely/dist/esm/dialect/mssql/mssql-adapter.d.ts","./node_modules/kysely/dist/esm/dialect/mssql/mssql-dialect-config.d.ts","./node_modules/kysely/dist/esm/dialect/mssql/mssql-dialect.d.ts","./node_modules/kysely/dist/esm/dialect/mssql/mssql-driver.d.ts","./node_modules/kysely/dist/esm/dialect/mssql/mssql-introspector.d.ts","./node_modules/kysely/dist/esm/dialect/mssql/mssql-query-compiler.d.ts","./node_modules/kysely/dist/esm/migration/migrator.d.ts","./node_modules/kysely/dist/esm/migration/file-migration-provider.d.ts","./node_modules/kysely/dist/esm/plugin/camel-case/camel-case-plugin.d.ts","./node_modules/kysely/dist/esm/plugin/deduplicate-joins/deduplicate-joins-plugin.d.ts","./node_modules/kysely/dist/esm/plugin/with-schema/with-schema-plugin.d.ts","./node_modules/kysely/dist/esm/plugin/parse-json-results/parse-json-results-plugin.d.ts","./node_modules/kysely/dist/esm/plugin/handle-empty-in-lists/handle-empty-in-lists.d.ts","./node_modules/kysely/dist/esm/plugin/handle-empty-in-lists/handle-empty-in-lists-plugin.d.ts","./node_modules/kysely/dist/esm/operation-node/operation-node-transformer.d.ts","./node_modules/kysely/dist/esm/util/infer-result.d.ts","./node_modules/kysely/dist/esm/util/log-once.d.ts","./node_modules/kysely/dist/esm/parser/unary-operation-parser.d.ts","./node_modules/kysely/dist/esm/index.d.ts","./node_modules/nanostores/atom/index.d.ts","./node_modules/nanostores/map/index.d.ts","./node_modules/nanostores/map-creator/index.d.ts","./node_modules/nanostores/clean-stores/index.d.ts","./node_modules/nanostores/task/index.d.ts","./node_modules/nanostores/computed/index.d.ts","./node_modules/nanostores/deep-map/path.d.ts","./node_modules/nanostores/deep-map/index.d.ts","./node_modules/nanostores/effect/index.d.ts","./node_modules/nanostores/keep-mount/index.d.ts","./node_modules/nanostores/lifecycle/index.d.ts","./node_modules/nanostores/listen-keys/index.d.ts","./node_modules/nanostores/index.d.ts","./node_modules/@better-auth/core/dist/index-neerjor2.d.mts","./node_modules/@better-auth/core/dist/index.d.mts","./node_modules/@better-auth/core/dist/db/index.d.mts","./node_modules/better-auth/dist/db/field.d.mts","./node_modules/@better-auth/core/dist/db/adapter/index.d.mts","./node_modules/better-auth/dist/db/adapter-base.d.mts","./node_modules/better-auth/dist/db/adapter-kysely.d.mts","./node_modules/better-auth/dist/db/field-converter.d.mts","./node_modules/better-auth/dist/adapters/kysely-adapter/types.d.mts","./node_modules/better-auth/dist/db/get-migration.d.mts","./node_modules/better-auth/dist/db/get-schema.d.mts","./node_modules/@better-auth/core/dist/env/index.d.mts","./node_modules/better-auth/dist/db/internal-adapter.d.mts","./node_modules/better-auth/dist/types/api.d.mts","./node_modules/better-auth/dist/types/plugins.d.mts","./node_modules/better-auth/dist/types/adapter.d.mts","./node_modules/better-auth/dist/types/index.d.mts","./node_modules/better-auth/dist/utils/get-request-ip.d.mts","./node_modules/better-auth/dist/api/middlewares/oauth.d.mts","./node_modules/better-auth/dist/api/middlewares/origin-check.d.mts","./node_modules/better-auth/dist/api/middlewares/index.d.mts","./node_modules/@better-auth/core/dist/oauth2/index.d.mts","./node_modules/better-auth/dist/api/routes/account.d.mts","./node_modules/better-auth/dist/api/routes/callback.d.mts","./node_modules/better-auth/dist/api/routes/email-verification.d.mts","./node_modules/better-auth/dist/api/routes/error.d.mts","./node_modules/better-auth/dist/api/routes/ok.d.mts","./node_modules/better-auth/dist/api/routes/reset-password.d.mts","./node_modules/better-auth/dist/api/routes/session.d.mts","./node_modules/better-auth/dist/api/routes/sign-in.d.mts","./node_modules/better-auth/dist/api/routes/sign-out.d.mts","./node_modules/better-auth/dist/api/routes/sign-up.d.mts","./node_modules/better-auth/dist/api/routes/update-user.d.mts","./node_modules/better-auth/dist/api/routes/index.d.mts","./node_modules/@better-auth/core/dist/api/index.d.mts","./node_modules/better-auth/dist/api/index.d.mts","./node_modules/@better-auth/core/dist/error/index.d.mts","./node_modules/better-auth/dist/types/auth.d.mts","./node_modules/better-auth/dist/types/models.d.mts","./node_modules/better-auth/dist/db/schema.d.mts","./node_modules/better-auth/dist/db/to-zod.d.mts","./node_modules/better-auth/dist/db/with-hooks.d.mts","./node_modules/better-auth/dist/db/index.d.mts","./node_modules/better-auth/dist/client/path-to-object.d.mts","./node_modules/better-auth/dist/client/types.d.mts","./node_modules/better-auth/dist/auth/auth.d.mts","./node_modules/better-auth/dist/auth/index.d.mts","./node_modules/better-auth/dist/oauth2/state.d.mts","./node_modules/better-auth/dist/utils/hide-metadata.d.mts","./node_modules/@better-auth/core/dist/utils/index.d.mts","./node_modules/better-auth/dist/utils/index.d.mts","./node_modules/@better-auth/core/dist/async_hooks/index.d.mts","./node_modules/@better-auth/core/dist/context/index.d.mts","./node_modules/@better-auth/telemetry/dist/index.d.mts","./node_modules/zod/v4/classic/index.d.cts","./node_modules/zod/v4/index.d.cts","./node_modules/better-auth/dist/index.d.mts","./node_modules/better-auth/dist/plugins/access/access.d.mts","./node_modules/better-auth/dist/plugins/access/types.d.mts","./node_modules/better-auth/dist/plugins/admin/schema.d.mts","./node_modules/better-auth/dist/plugins/admin/types.d.mts","./node_modules/better-auth/dist/plugins/admin/admin.d.mts","./node_modules/better-auth/dist/plugins/admin/index.d.mts","./node_modules/better-auth/dist/plugins/anonymous/schema.d.mts","./node_modules/better-auth/dist/plugins/anonymous/types.d.mts","./node_modules/better-auth/dist/plugins/anonymous/index.d.mts","./node_modules/better-auth/dist/plugins/api-key/schema.d.mts","./node_modules/better-auth/dist/plugins/api-key/types.d.mts","./node_modules/better-auth/dist/plugins/api-key/index.d.mts","./node_modules/better-auth/dist/plugins/bearer/index.d.mts","./node_modules/better-auth/dist/plugins/captcha/constants.d.mts","./node_modules/better-auth/dist/plugins/captcha/types.d.mts","./node_modules/better-auth/dist/plugins/captcha/index.d.mts","./node_modules/better-auth/dist/plugins/custom-session/index.d.mts","./node_modules/better-auth/dist/utils/time.d.mts","./node_modules/better-auth/dist/plugins/device-authorization/index.d.mts","./node_modules/better-auth/dist/plugins/email-otp/types.d.mts","./node_modules/better-auth/dist/plugins/email-otp/index.d.mts","./node_modules/better-auth/dist/plugins/generic-oauth/types.d.mts","./node_modules/better-auth/dist/plugins/generic-oauth/providers/hubspot.d.mts","./node_modules/better-auth/dist/plugins/generic-oauth/providers/keycloak.d.mts","./node_modules/better-auth/dist/plugins/generic-oauth/providers/line.d.mts","./node_modules/better-auth/dist/plugins/generic-oauth/providers/microsoft-entra-id.d.mts","./node_modules/better-auth/dist/plugins/generic-oauth/providers/okta.d.mts","./node_modules/better-auth/dist/plugins/generic-oauth/providers/slack.d.mts","./node_modules/better-auth/dist/plugins/generic-oauth/providers/index.d.mts","./node_modules/better-auth/dist/plugins/generic-oauth/index.d.mts","./node_modules/better-auth/dist/plugins/generic-oauth/providers/auth0.d.mts","./node_modules/better-auth/dist/plugins/haveibeenpwned/index.d.mts","./node_modules/better-auth/dist/plugins/jwt/schema.d.mts","./node_modules/better-auth/dist/plugins/jwt/types.d.mts","./node_modules/better-auth/dist/plugins/jwt/sign.d.mts","./node_modules/better-auth/dist/plugins/jwt/utils.d.mts","./node_modules/better-auth/dist/plugins/jwt/verify.d.mts","./node_modules/better-auth/dist/plugins/jwt/index.d.mts","./node_modules/better-auth/dist/plugins/last-login-method/index.d.mts","./node_modules/better-auth/dist/plugins/magic-link/index.d.mts","./node_modules/better-auth/dist/plugins/oidc-provider/schema.d.mts","./node_modules/better-auth/dist/plugins/oidc-provider/types.d.mts","./node_modules/better-auth/dist/plugins/oidc-provider/index.d.mts","./node_modules/better-auth/dist/plugins/mcp/index.d.mts","./node_modules/better-auth/dist/plugins/multi-session/index.d.mts","./node_modules/better-auth/dist/plugins/oauth-proxy/index.d.mts","./node_modules/better-auth/dist/plugins/one-tap/index.d.mts","./node_modules/better-auth/dist/plugins/one-time-token/index.d.mts","./node_modules/better-auth/dist/plugins/open-api/generator.d.mts","./node_modules/better-auth/dist/plugins/open-api/index.d.mts","./node_modules/better-auth/dist/plugins/phone-number/schema.d.mts","./node_modules/better-auth/dist/plugins/phone-number/types.d.mts","./node_modules/better-auth/dist/plugins/phone-number/index.d.mts","./node_modules/better-auth/dist/plugins/siwe/schema.d.mts","./node_modules/better-auth/dist/plugins/siwe/types.d.mts","./node_modules/better-auth/dist/plugins/siwe/index.d.mts","./node_modules/better-auth/dist/plugins/two-factor/backup-codes/index.d.mts","./node_modules/better-auth/dist/plugins/two-factor/schema.d.mts","./node_modules/better-auth/dist/plugins/two-factor/totp/index.d.mts","./node_modules/better-auth/dist/plugins/two-factor/types.d.mts","./node_modules/better-auth/dist/plugins/two-factor/otp/index.d.mts","./node_modules/better-auth/dist/plugins/two-factor/error-code.d.mts","./node_modules/better-auth/dist/plugins/two-factor/index.d.mts","./node_modules/better-auth/dist/plugins/two-factor/client.d.mts","./node_modules/better-auth/dist/plugins/username/error-codes.d.mts","./node_modules/better-auth/dist/plugins/username/schema.d.mts","./node_modules/better-auth/dist/plugins/username/index.d.mts","./node_modules/better-auth/dist/plugins/organization/access/statement.d.mts","./node_modules/better-auth/dist/plugins/organization/schema.d.mts","./node_modules/better-auth/dist/plugins/organization/types.d.mts","./node_modules/better-auth/dist/plugins/organization/adapter.d.mts","./node_modules/better-auth/dist/plugins/organization/error-codes.d.mts","./node_modules/better-auth/dist/plugins/organization/routes/crud-access-control.d.mts","./node_modules/better-auth/dist/plugins/organization/access/index.d.mts","./node_modules/better-auth/dist/plugins/organization/index.d.mts","./node_modules/better-auth/dist/plugins/organization/routes/crud-invites.d.mts","./node_modules/better-auth/dist/plugins/organization/routes/crud-members.d.mts","./node_modules/better-auth/dist/plugins/organization/routes/crud-org.d.mts","./node_modules/better-auth/dist/plugins/organization/routes/crud-team.d.mts","./node_modules/better-auth/dist/plugins/organization/organization.d.mts","./node_modules/better-auth/dist/plugins/index.d.mts","./node_modules/better-auth/dist/adapters/prisma-adapter/prisma-adapter.d.mts","./node_modules/better-auth/dist/adapters/prisma-adapter/index.d.mts","./node_modules/@prisma/client/runtime/library.d.ts","./node_modules/.prisma/client/index.d.ts","./node_modules/.prisma/client/default.d.ts","./node_modules/@prisma/client/default.d.ts","./src/lib/db.ts","./src/lib/auth.ts","./node_modules/better-auth/dist/integrations/next-js.d.mts","./src/app/api/auth/[...all]/route.ts","./node_modules/bcryptjs/types.d.ts","./node_modules/bcryptjs/index.d.ts","./src/app/api/auth/reset-password/route.ts","./src/app/api/auth/setup/route.ts","./src/app/api/orgs/[slug]/api-key/route.ts","./src/app/api/orgs/[slug]/members/[id]/reset-password/route.ts","./src/app/api/orgs/[slug]/members/create/route.ts","./src/lib/types.ts","./src/lib/api.ts","./node_modules/better-auth/dist/client/react/react-store.d.mts","./node_modules/better-auth/dist/client/react/index.d.mts","./node_modules/better-auth/dist/plugins/additional-fields/client.d.mts","./node_modules/better-auth/dist/plugins/admin/client.d.mts","./node_modules/better-auth/dist/plugins/anonymous/client.d.mts","./node_modules/better-auth/dist/plugins/api-key/client.d.mts","./node_modules/better-auth/dist/plugins/custom-session/client.d.mts","./node_modules/better-auth/dist/plugins/device-authorization/client.d.mts","./node_modules/better-auth/dist/plugins/email-otp/client.d.mts","./node_modules/better-auth/dist/plugins/generic-oauth/client.d.mts","./node_modules/better-auth/dist/plugins/jwt/client.d.mts","./node_modules/better-auth/dist/plugins/last-login-method/client.d.mts","./node_modules/better-auth/dist/plugins/magic-link/client.d.mts","./node_modules/better-auth/dist/plugins/multi-session/client.d.mts","./node_modules/better-auth/dist/plugins/oidc-provider/client.d.mts","./node_modules/better-auth/dist/plugins/one-tap/client.d.mts","./node_modules/better-auth/dist/plugins/one-time-token/client.d.mts","./node_modules/better-auth/dist/plugins/organization/permission.d.mts","./node_modules/better-auth/dist/plugins/organization/client.d.mts","./node_modules/better-auth/dist/plugins/phone-number/client.d.mts","./node_modules/better-auth/dist/plugins/siwe/client.d.mts","./node_modules/better-auth/dist/plugins/username/client.d.mts","./node_modules/better-auth/dist/client/plugins/infer-plugin.d.mts","./node_modules/better-auth/dist/client/plugins/index.d.mts","./src/lib/auth-client.ts","./src/lib/use-project-websocket.ts","./node_modules/next/dist/compiled/@next/font/dist/types.d.ts","./node_modules/next/dist/compiled/@next/font/dist/google/index.d.ts","./node_modules/next/font/google/index.d.ts","./node_modules/sonner/dist/index.d.mts","./src/components/ui/skeleton.tsx","./src/components/loading-overlay.tsx","./src/components/auth-guard.tsx","./src/app/layout.tsx","./src/app/page.tsx","./node_modules/@radix-ui/react-slot/dist/index.d.mts","./node_modules/class-variance-authority/dist/types.d.ts","./node_modules/class-variance-authority/dist/index.d.ts","./src/components/ui/button.tsx","./src/components/ui/input.tsx","./src/components/ui/card.tsx","./src/app/(auth)/reset/page.tsx","./src/app/(auth)/signin/page.tsx","./node_modules/lucide-react/dist/lucide-react.d.ts","./node_modules/@radix-ui/react-context/dist/index.d.mts","./node_modules/@radix-ui/react-primitive/dist/index.d.mts","./node_modules/@radix-ui/react-dismissable-layer/dist/index.d.mts","./node_modules/@radix-ui/react-focus-scope/dist/index.d.mts","./node_modules/@radix-ui/react-arrow/dist/index.d.mts","./node_modules/@radix-ui/rect/dist/index.d.mts","./node_modules/@radix-ui/react-popper/dist/index.d.mts","./node_modules/@radix-ui/react-portal/dist/index.d.mts","./node_modules/@radix-ui/react-roving-focus/dist/index.d.mts","./node_modules/@radix-ui/react-menu/dist/index.d.mts","./node_modules/@radix-ui/react-dropdown-menu/dist/index.d.mts","./src/components/ui/dropdown-menu.tsx","./src/components/top-bar.tsx","./node_modules/@radix-ui/react-dialog/dist/index.d.mts","./src/components/ui/dialog.tsx","./src/components/ui/textarea.tsx","./src/components/empty-state.tsx","./src/app/projects/page.tsx","./src/components/status-dot.tsx","./src/components/section-sidebar.tsx","./src/components/ui/badge.tsx","./node_modules/@types/unist/index.d.ts","./node_modules/@types/hast/index.d.ts","./node_modules/vfile-message/lib/index.d.ts","./node_modules/vfile-message/index.d.ts","./node_modules/vfile/lib/index.d.ts","./node_modules/vfile/index.d.ts","./node_modules/unified/lib/callable-instance.d.ts","./node_modules/trough/lib/index.d.ts","./node_modules/trough/index.d.ts","./node_modules/unified/lib/index.d.ts","./node_modules/unified/index.d.ts","./node_modules/@types/mdast/index.d.ts","./node_modules/mdast-util-to-hast/lib/state.d.ts","./node_modules/mdast-util-to-hast/lib/footer.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/blockquote.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/break.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/code.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/delete.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/emphasis.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/footnote-reference.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/heading.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/html.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/image-reference.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/image.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/inline-code.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/link-reference.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/link.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/list-item.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/list.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/paragraph.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/root.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/strong.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/table.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/table-cell.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/table-row.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/text.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/thematic-break.d.ts","./node_modules/mdast-util-to-hast/lib/handlers/index.d.ts","./node_modules/mdast-util-to-hast/lib/index.d.ts","./node_modules/mdast-util-to-hast/index.d.ts","./node_modules/remark-rehype/lib/index.d.ts","./node_modules/remark-rehype/index.d.ts","./node_modules/react-markdown/lib/index.d.ts","./node_modules/react-markdown/index.d.ts","./node_modules/highlight.js/types/index.d.ts","./node_modules/lowlight/lib/index.d.ts","./node_modules/lowlight/lib/all.d.ts","./node_modules/lowlight/lib/common.d.ts","./node_modules/lowlight/index.d.ts","./node_modules/rehype-highlight/lib/index.d.ts","./node_modules/rehype-highlight/index.d.ts","./node_modules/micromark-util-types/index.d.ts","./node_modules/micromark-extension-gfm-footnote/lib/html.d.ts","./node_modules/micromark-extension-gfm-footnote/lib/syntax.d.ts","./node_modules/micromark-extension-gfm-footnote/index.d.ts","./node_modules/micromark-extension-gfm-strikethrough/lib/html.d.ts","./node_modules/micromark-extension-gfm-strikethrough/lib/syntax.d.ts","./node_modules/micromark-extension-gfm-strikethrough/index.d.ts","./node_modules/micromark-extension-gfm/index.d.ts","./node_modules/mdast-util-from-markdown/lib/types.d.ts","./node_modules/mdast-util-from-markdown/lib/index.d.ts","./node_modules/mdast-util-from-markdown/index.d.ts","./node_modules/mdast-util-to-markdown/lib/types.d.ts","./node_modules/mdast-util-to-markdown/lib/index.d.ts","./node_modules/mdast-util-to-markdown/lib/handle/blockquote.d.ts","./node_modules/mdast-util-to-markdown/lib/handle/break.d.ts","./node_modules/mdast-util-to-markdown/lib/handle/code.d.ts","./node_modules/mdast-util-to-markdown/lib/handle/definition.d.ts","./node_modules/mdast-util-to-markdown/lib/handle/emphasis.d.ts","./node_modules/mdast-util-to-markdown/lib/handle/heading.d.ts","./node_modules/mdast-util-to-markdown/lib/handle/html.d.ts","./node_modules/mdast-util-to-markdown/lib/handle/image.d.ts","./node_modules/mdast-util-to-markdown/lib/handle/image-reference.d.ts","./node_modules/mdast-util-to-markdown/lib/handle/inline-code.d.ts","./node_modules/mdast-util-to-markdown/lib/handle/link.d.ts","./node_modules/mdast-util-to-markdown/lib/handle/link-reference.d.ts","./node_modules/mdast-util-to-markdown/lib/handle/list.d.ts","./node_modules/mdast-util-to-markdown/lib/handle/list-item.d.ts","./node_modules/mdast-util-to-markdown/lib/handle/paragraph.d.ts","./node_modules/mdast-util-to-markdown/lib/handle/root.d.ts","./node_modules/mdast-util-to-markdown/lib/handle/strong.d.ts","./node_modules/mdast-util-to-markdown/lib/handle/text.d.ts","./node_modules/mdast-util-to-markdown/lib/handle/thematic-break.d.ts","./node_modules/mdast-util-to-markdown/lib/handle/index.d.ts","./node_modules/mdast-util-to-markdown/index.d.ts","./node_modules/mdast-util-gfm-footnote/lib/index.d.ts","./node_modules/mdast-util-gfm-footnote/index.d.ts","./node_modules/markdown-table/index.d.ts","./node_modules/mdast-util-gfm-table/lib/index.d.ts","./node_modules/mdast-util-gfm-table/index.d.ts","./node_modules/mdast-util-gfm/lib/index.d.ts","./node_modules/mdast-util-gfm/index.d.ts","./node_modules/remark-gfm/lib/index.d.ts","./node_modules/remark-gfm/index.d.ts","./src/components/markdown-renderer.tsx","./src/components/section-viewer.tsx","./src/components/chat-panel.tsx","./src/components/dependency-graph.tsx","./node_modules/@types/d3-time/index.d.ts","./node_modules/@types/d3-scale/index.d.ts","./node_modules/victory-vendor/d3-scale.d.ts","./node_modules/recharts/types/shape/dot.d.ts","./node_modules/recharts/types/component/text.d.ts","./node_modules/recharts/types/zindex/zindexlayer.d.ts","./node_modules/recharts/types/cartesian/getcartesianposition.d.ts","./node_modules/recharts/types/component/label.d.ts","./node_modules/recharts/types/cartesian/cartesianaxis.d.ts","./node_modules/recharts/types/util/scale/customscaledefinition.d.ts","./node_modules/redux/dist/redux.d.ts","./node_modules/@reduxjs/toolkit/node_modules/immer/dist/immer.d.ts","./node_modules/reselect/dist/reselect.d.ts","./node_modules/redux-thunk/dist/redux-thunk.d.ts","./node_modules/@reduxjs/toolkit/dist/uncheckedindexed.ts","./node_modules/@reduxjs/toolkit/dist/index.d.mts","./node_modules/recharts/types/state/cartesianaxisslice.d.ts","./node_modules/recharts/types/synchronisation/types.d.ts","./node_modules/recharts/types/chart/types.d.ts","./node_modules/recharts/types/component/defaulttooltipcontent.d.ts","./node_modules/recharts/types/context/brushupdatecontext.d.ts","./node_modules/recharts/types/state/chartdataslice.d.ts","./node_modules/recharts/types/state/types/linesettings.d.ts","./node_modules/recharts/types/state/types/scattersettings.d.ts","./node_modules/@types/d3-path/index.d.ts","./node_modules/@types/d3-shape/index.d.ts","./node_modules/victory-vendor/d3-shape.d.ts","./node_modules/recharts/types/shape/curve.d.ts","./node_modules/recharts/types/component/labellist.d.ts","./node_modules/recharts/types/component/defaultlegendcontent.d.ts","./node_modules/recharts/types/util/payload/getuniqpayload.d.ts","./node_modules/recharts/types/util/useelementoffset.d.ts","./node_modules/recharts/types/component/legend.d.ts","./node_modules/recharts/types/state/legendslice.d.ts","./node_modules/recharts/types/state/types/stackedgraphicalitem.d.ts","./node_modules/recharts/types/util/stacks/stacktypes.d.ts","./node_modules/recharts/types/util/scale/rechartsscale.d.ts","./node_modules/recharts/types/util/chartutils.d.ts","./node_modules/recharts/types/state/selectors/areaselectors.d.ts","./node_modules/recharts/types/cartesian/area.d.ts","./node_modules/recharts/types/state/types/areasettings.d.ts","./node_modules/recharts/types/animation/easing.d.ts","./node_modules/recharts/types/shape/rectangle.d.ts","./node_modules/recharts/types/cartesian/bar.d.ts","./node_modules/recharts/types/util/barutils.d.ts","./node_modules/recharts/types/state/types/barsettings.d.ts","./node_modules/recharts/types/state/types/radialbarsettings.d.ts","./node_modules/recharts/types/util/svgpropertiesnoevents.d.ts","./node_modules/recharts/types/util/useuniqueid.d.ts","./node_modules/recharts/types/state/types/piesettings.d.ts","./node_modules/recharts/types/state/types/radarsettings.d.ts","./node_modules/recharts/types/state/graphicalitemsslice.d.ts","./node_modules/recharts/types/state/tooltipslice.d.ts","./node_modules/recharts/types/state/optionsslice.d.ts","./node_modules/recharts/types/state/layoutslice.d.ts","./node_modules/immer/dist/immer.d.ts","./node_modules/recharts/types/util/ifoverflow.d.ts","./node_modules/recharts/types/util/resolvedefaultprops.d.ts","./node_modules/recharts/types/cartesian/referenceline.d.ts","./node_modules/recharts/types/state/referenceelementsslice.d.ts","./node_modules/recharts/types/state/brushslice.d.ts","./node_modules/recharts/types/state/rootpropsslice.d.ts","./node_modules/recharts/types/state/polaraxisslice.d.ts","./node_modules/recharts/types/state/polaroptionsslice.d.ts","./node_modules/recharts/types/cartesian/line.d.ts","./node_modules/recharts/types/util/constants.d.ts","./node_modules/recharts/types/util/scatterutils.d.ts","./node_modules/recharts/types/shape/symbols.d.ts","./node_modules/recharts/types/cartesian/scatter.d.ts","./node_modules/recharts/types/cartesian/errorbar.d.ts","./node_modules/recharts/types/state/errorbarslice.d.ts","./node_modules/recharts/types/state/zindexslice.d.ts","./node_modules/recharts/types/state/eventsettingsslice.d.ts","./node_modules/recharts/types/state/renderedticksslice.d.ts","./node_modules/recharts/types/state/store.d.ts","./node_modules/recharts/types/cartesian/getticks.d.ts","./node_modules/recharts/types/cartesian/cartesiangrid.d.ts","./node_modules/recharts/types/state/selectors/combiners/combinedisplayedstackeddata.d.ts","./node_modules/recharts/types/state/selectors/selecttooltipaxistype.d.ts","./node_modules/recharts/types/types.d.ts","./node_modules/recharts/types/hooks.d.ts","./node_modules/recharts/types/state/selectors/axisselectors.d.ts","./node_modules/recharts/types/component/dots.d.ts","./node_modules/recharts/types/util/typeddatakey.d.ts","./node_modules/recharts/types/util/types.d.ts","./node_modules/recharts/types/container/surface.d.ts","./node_modules/recharts/types/container/layer.d.ts","./node_modules/recharts/types/component/cursor.d.ts","./node_modules/recharts/types/component/tooltip.d.ts","./node_modules/recharts/types/component/responsivecontainer.d.ts","./node_modules/recharts/types/component/cell.d.ts","./node_modules/recharts/types/component/customized.d.ts","./node_modules/recharts/types/shape/sector.d.ts","./node_modules/recharts/types/shape/polygon.d.ts","./node_modules/recharts/types/shape/cross.d.ts","./node_modules/recharts/types/polar/polargrid.d.ts","./node_modules/recharts/types/polar/defaultpolarradiusaxisprops.d.ts","./node_modules/recharts/types/polar/polarradiusaxis.d.ts","./node_modules/recharts/types/polar/defaultpolarangleaxisprops.d.ts","./node_modules/recharts/types/polar/polarangleaxis.d.ts","./node_modules/recharts/types/context/tooltipcontext.d.ts","./node_modules/recharts/types/polar/pie.d.ts","./node_modules/recharts/types/polar/radar.d.ts","./node_modules/recharts/types/util/radialbarutils.d.ts","./node_modules/recharts/types/polar/radialbar.d.ts","./node_modules/recharts/types/cartesian/brush.d.ts","./node_modules/recharts/types/cartesian/referencedot.d.ts","./node_modules/recharts/types/util/excludeeventprops.d.ts","./node_modules/recharts/types/util/svgpropertiesandevents.d.ts","./node_modules/recharts/types/cartesian/referencearea.d.ts","./node_modules/recharts/types/cartesian/barstack.d.ts","./node_modules/recharts/types/cartesian/xaxis.d.ts","./node_modules/recharts/types/cartesian/yaxis.d.ts","./node_modules/recharts/types/cartesian/zaxis.d.ts","./node_modules/recharts/types/chart/linechart.d.ts","./node_modules/recharts/types/chart/barchart.d.ts","./node_modules/recharts/types/chart/piechart.d.ts","./node_modules/recharts/types/chart/treemap.d.ts","./node_modules/recharts/types/chart/sankey.d.ts","./node_modules/recharts/types/chart/radarchart.d.ts","./node_modules/recharts/types/chart/scatterchart.d.ts","./node_modules/recharts/types/chart/areachart.d.ts","./node_modules/recharts/types/chart/radialbarchart.d.ts","./node_modules/recharts/types/chart/composedchart.d.ts","./node_modules/recharts/types/chart/sunburstchart.d.ts","./node_modules/recharts/types/shape/trapezoid.d.ts","./node_modules/recharts/types/cartesian/funnel.d.ts","./node_modules/recharts/types/chart/funnelchart.d.ts","./node_modules/recharts/types/util/global.d.ts","./node_modules/recharts/types/zindex/defaultzindexes.d.ts","./node_modules/decimal.js-light/decimal.d.ts","./node_modules/recharts/types/util/scale/getnicetickvalues.d.ts","./node_modules/recharts/types/context/chartlayoutcontext.d.ts","./node_modules/recharts/types/util/getrelativecoordinate.d.ts","./node_modules/recharts/types/util/createcartesiancharts.d.ts","./node_modules/recharts/types/util/createpolarcharts.d.ts","./node_modules/recharts/types/index.d.ts","./src/components/token-stats-dashboard.tsx","./node_modules/@radix-ui/react-tabs/dist/index.d.mts","./src/components/ui/tabs.tsx","./src/app/projects/[slug]/page.tsx","./node_modules/@radix-ui/react-select/dist/index.d.mts","./src/components/ui/select.tsx","./src/app/projects/[slug]/settings/page.tsx","./src/components/error-boundary.tsx","./src/components/member-manager.tsx","./node_modules/@radix-ui/react-tooltip/dist/index.d.mts","./src/components/ui/tooltip.tsx","./src/components/presence-bar.tsx","./src/components/sidebar.tsx","./node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-context/dist/index.d.mts","./node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-primitive/dist/index.d.mts","./node_modules/@radix-ui/react-avatar/dist/index.d.mts","./src/components/ui/avatar.tsx","./.next/types/cache-life.d.ts","./.next/types/validator.ts","./.next/types/app/layout.ts","./.next/types/app/page.ts","./.next/types/app/(auth)/reset/page.ts","./.next/types/app/(auth)/signin/page.ts","./.next/types/app/api/auth/[...all]/route.ts","./.next/types/app/api/auth/reset-password/route.ts","./.next/types/app/api/auth/setup/route.ts","./.next/types/app/api/orgs/[slug]/api-key/route.ts","./.next/types/app/api/orgs/[slug]/members/[id]/reset-password/route.ts","./.next/types/app/api/orgs/[slug]/members/create/route.ts","./.next/types/app/projects/page.ts","./.next/types/app/projects/[slug]/page.ts","./.next/types/app/projects/[slug]/settings/page.ts","./node_modules/@types/d3-array/index.d.ts","./node_modules/@types/d3-color/index.d.ts","./node_modules/@types/d3-ease/index.d.ts","./node_modules/@types/d3-interpolate/index.d.ts","./node_modules/@types/d3-timer/index.d.ts","./node_modules/@types/ms/index.d.ts","./node_modules/@types/debug/index.d.ts","./node_modules/@types/estree-jsx/index.d.ts","./node_modules/@types/json-schema/index.d.ts","./node_modules/@types/json5/index.d.ts","./node_modules/@types/use-sync-external-store/index.d.ts"],"fileIdsList":[[100,148,165,166,341,1184],[100,148,165,166,341,1185],[100,148,165,166,495,1133],[100,148,165,166,495,1136],[100,148,165,166,495,1137],[100,148,165,166,495,1138],[100,148,165,166,495,1139],[100,148,165,166,495,1140],[100,148,165,166,341,1176],[100,148,165,166,341,1177],[100,148,165,166,341,1446],[100,148,165,166,341,1449],[100,148,165,166,341,1204],[100,148,165,166,448,449,450,451],[100,148,165,166],[83,100,148,165,166,495,498,1133,1136,1137,1138,1139,1140,1176,1177,1184,1185,1204,1446,1449],[83,100,148,165,166,499,500],[100,148,165,166,499],[100,148,165,166,1127],[100,148,165,166,1126],[100,148,165,166,585],[100,148,165,166,986],[100,147,148,165,166],[100,148,165,166,720,986,1037],[100,148,165,166,609],[100,148,165,166,179,609,686,687,718,720,721,972,985],[100,148,165,166,987,988],[100,148,165,166,1128],[86,100,148,165,166,1188],[86,100,148,165,166,1456,1457],[86,100,148,165,166],[86,100,148,165,166,1187,1188,1189,1190,1194],[86,100,148,165,166,1187,1188,1196],[86,100,148,165,166,1187,1188,1189,1190,1193,1194,1195],[86,100,148,165,166,1187,1188,1191,1192],[86,100,148,165,166,1187,1188],[86,100,148,165,166,1187,1188,1189,1190,1193,1194],[86,90,100,148,165,166,199,200,201,202,203,443,491],[86,100,148,165,166,1187,1188,1195],[86,100,148,165,166,1187,1188,1189,1193,1194],[100,148,165,166,1316,1317,1318,1319,1320],[100,148,165,166,585,586,587,588,589],[100,148,165,166,585,587],[100,148,165,166,572,573],[100,148,165,166,1476],[100,148,165,166,1306],[100,148,165,166,1330],[100,148,165,166,1480],[100,148,165,166,518,519,1482],[100,148,165,166,1208],[100,148,159,162,164,165,166,168,180,191,198],[100,145,146,148,165,166],[148,165,166],[100,148,153,165,166,183],[100,148,149,154,159,165,166,168,180,191],[100,148,149,150,159,165,166,168],[95,96,97,100,148,165,166],[100,148,151,165,166,192],[100,148,152,153,160,165,166,169],[100,148,153,165,166,180,188],[100,148,154,156,159,165,166,168],[100,147,148,155,165,166],[100,148,156,157,165,166],[100,148,158,159,165,166],[100,147,148,159,165,166],[100,148,159,160,161,165,166,180,191],[100,148,159,160,161,165,166,175,180,183],[100,141,148,156,159,162,165,166,168,180,191],[100,148,159,160,162,163,165,166,168,180,188,191],[100,148,162,164,165,166,180,188,191],[98,99,100,101,102,103,104,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197],[100,148,159,165,166],[100,148,165,166,167,191],[100,148,156,159,165,166,168,180],[100,113,117,148,165,166,191],[100,113,148,165,166,180,191],[100,108,148,165,166],[100,110,113,148,165,166,188,191],[100,148,165,166,168,188],[100,148,165,166,198],[100,108,148,165,166,198],[100,110,113,148,165,166,168,191],[100,105,106,109,112,148,159,165,166,180,191],[100,113,120,148,165,166],[100,105,111,148,165,166],[100,113,134,135,148,165,166],[100,109,113,148,165,166,183,191,198],[100,134,148,165,166,198],[100,107,108,148,165,166,198],[100,113,148,165,166],[100,107,108,109,110,111,112,113,114,115,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,135,136,137,138,139,140,148,165,166],[100,113,128,148,165,166],[100,113,120,121,148,165,166],[100,111,113,121,122,148,165,166],[100,112,148,165,166],[100,105,108,113,148,165,166],[100,113,117,121,122,148,165,166],[100,117,148,165,166],[100,111,113,116,148,165,166,191],[100,105,110,113,120,148,165,166],[100,148,165,166,180],[100,108,113,134,148,165,166,196,198],[100,148,165,166,169],[100,148,165,166,170],[100,147,148,165,166,171],[100,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197],[100,148,165,166,173],[100,148,165,166,174],[100,148,159,165,166,175,176],[100,148,165,166,175,177,192,194],[100,148,160,165,166],[100,148,159,165,166,180,181,183],[100,148,165,166,182,183],[100,148,165,166,180,181],[100,148,165,166,183],[100,148,165,166,184],[100,145,148,165,166,180,185,191],[100,148,159,165,166,186,187],[100,148,165,166,186,187],[100,148,153,165,166,168,180,188],[100,148,165,166,189],[100,148,165,166,168,190],[100,148,162,165,166,174,191],[100,148,153,165,166,192],[100,148,165,166,180,193],[100,148,165,166,167,194],[100,148,165,166,195],[100,141,148,165,166],[100,141,148,159,161,165,166,171,180,183,191,193,194,196],[100,148,165,166,180,197],[86,90,100,148,165,166,199,200,201,203,443,491,1178],[86,90,100,148,165,166,199,200,201,202,358,443,491,1178],[86,90,100,148,165,166,199,200,202,203,443,491,1178],[86,100,148,165,166,203,358,359],[86,100,148,165,166,203,358],[86,90,100,148,165,166,200,201,202,203,443,491,1178],[86,90,100,148,165,166,199,201,202,203,443,491,1178],[84,85,100,148,165,166],[100,148,165,166,552,582,590],[100,148,165,166,505,510,511,513],[100,148,165,166,559,560],[100,148,165,166,511,513,553,554,555],[100,148,165,166,511],[100,148,165,166,511,513,553],[100,148,165,166,511,553],[100,148,165,166,566],[100,148,165,166,506,566,567],[100,148,165,166,506,566],[100,148,165,166,506,512],[100,148,165,166,507],[100,148,165,166,506,507,508,510],[100,148,165,166,506],[100,148,165,166,1134],[100,148,165,166,1124],[100,148,165,166,987,990],[100,148,165,166,608,676,686,720,987,989,997,1002,1003,1004,1005,1006,1007,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1019,1020,1023,1024,1028,1042],[100,148,165,166,1004,1005],[100,148,165,166,720,987],[100,148,165,166,686,720,1007],[100,148,165,166,686,720],[100,148,165,166,686,720,987,1002,1024],[100,148,165,166,720],[100,148,165,166,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018],[100,148,165,166,608,686,720,987,1002,1024],[100,148,165,166,987,1002,1023],[100,148,165,166,1031],[100,148,165,166,608,687,720,987,1030],[100,148,165,166,608,1046,1049,1050,1053,1064,1065,1066,1067,1068,1069,1070,1072,1073,1076,1084,1087,1090,1094,1099,1101,1102,1103,1106,1111,1145,1146,1147,1148,1149,1150,1151,1152,1153,1154,1155,1156,1157,1158,1159,1161,1162,1163,1164,1165],[100,148,165,166,987],[100,148,165,166,608,687,985,987,1022,1030,1143],[86,100,148,165,166,985],[100,148,165,166,608,987,989,1002,1023,1024,1028,1029],[100,148,165,166,988],[100,148,165,166,721,987,988],[100,148,165,166,987,988,994],[100,148,165,166,988,989,991,992,993,995,996,998,1025,1026,1027],[100,148,165,166,987,990,997],[100,148,165,166,987,988,1002,1024],[100,148,165,166,686,988],[100,148,165,166,987,988,990],[100,148,165,166,608,676,686,718,720,987,988,997,999,1000,1001,1002,1007,1021,1022,1023,1024,1030,1031,1032,1033,1034,1035,1036,1038,1039,1041],[100,148,165,166,1044],[100,148,165,166,608,1043],[100,148,165,166,676,686,720,987,988,1044,1046,1123],[100,148,165,166,1044,1046,1047,1123],[100,148,165,166,1046,1047],[100,148,165,166,1000,1002,1024,1044,1045],[100,148,165,166,1049,1050,1051],[100,148,165,166,720,987,1050],[100,148,165,166,720,987,1000,1002,1024,1049],[100,148,165,166,1053,1054],[100,148,165,166,676,686,720,987,988,1053],[100,148,165,166,987,1000,1002,1044,1052],[100,148,165,166,987,1057],[100,148,165,166,1056],[100,148,165,166,1002,1042],[100,148,165,166,1061],[100,148,165,166,686,720,1060],[100,148,165,166,1063],[100,148,165,166,676,686,720,987,988,1062],[100,148,165,166,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073],[100,148,165,166,676,686,720,987,1007,1064,1065,1066,1067,1068,1069,1070,1071,1073],[100,148,165,166,1064,1072],[100,148,165,166,1065,1066,1067,1068,1069,1070,1073],[100,148,165,166,987,988,1007],[100,148,165,166,1000,1020,1034,1043,1044,1046,1047,1048,1051,1053,1054,1055,1058,1059,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1072,1073,1074,1076,1077,1078,1079,1080,1081,1082,1084,1085,1086,1087,1088,1089,1090,1091,1092,1094,1095,1098,1099,1101,1102,1103,1104,1105,1106,1107,1109,1110,1111,1112,1113,1117,1122],[100,148,165,166,687,718,1076,1080],[100,148,165,166,686,718,720,987,1076,1077,1078,1079],[100,148,165,166,987,1076],[100,148,165,166,608,718,1000,1002,1024,1042,1075],[100,148,165,166,718,987,1076],[100,148,165,166,718,1076],[100,148,165,166,1082],[100,148,165,166,686,720,987],[100,148,165,166,686,720,987,1084,1085],[100,148,165,166,988,1087],[100,148,165,166,686,720,987,988,989,1028],[100,148,165,166,1084,1085],[100,148,165,166,686,720,987,988,1000,1083,1084,1123],[100,148,165,166,686],[100,148,165,166,1000,1002,1024,1083],[100,148,165,166,687,987],[100,148,165,166,1090],[100,148,165,166,720,987,988],[100,148,165,166,608,720,1091],[100,148,165,166,1110],[100,148,165,166,1043,1044,1123],[100,148,165,166,987,989,1002,1024,1028,1111,1112],[100,148,165,166,608,687,985,987,988,989,1002,1028,1030,1042,1044,1111,1112,1117,1122,1123,1160],[100,148,165,166,1110,1111,1112,1113,1116,1122],[100,148,165,166,686,720,988,1044,1111,1112,1114,1115,1118,1119,1120,1121,1123],[100,148,165,166,1112],[100,148,165,166,686,720,988,989,1002,1024,1028,1044,1111,1112,1123],[100,148,165,166,686,720,987,988,989,1028,1044,1110,1111,1112,1117,1123],[100,148,165,166,608,686,720,987,988,989,1028,1044,1110,1111,1112,1117,1123],[100,148,165,166,686,720,988,989,1028,1112],[100,148,165,166,987,988,1002,1024,1044,1111],[100,148,165,166,1094,1095],[100,148,165,166,676,686,720,987,1094],[100,148,165,166,608,987,1000,1002,1024,1093],[100,148,165,166,1098],[100,148,165,166,686,720,1000,1002,1096,1097],[100,148,165,166,687,1099,1101,1102,1103,1105],[100,148,165,166,686,720,987,1099,1101,1102,1103,1104,1106],[100,148,165,166,686,720,987,1102],[100,148,165,166,686,720,1099],[100,148,165,166,608,987,1000,1002,1024,1099,1100,1101,1103],[100,148,165,166,1109],[100,148,165,166,686,720,987,988,1000,1107,1108],[100,148,165,166,990],[100,148,165,166,608,720],[100,148,165,166,608,987,999,1000,1021,1022,1024],[100,148,165,166,608,987,999,1000,1001,1023,1024,1030],[100,148,165,166,608,987,988,989,1023,1028],[100,148,165,166,608,987,988],[100,148,165,166,1033,1034,1035],[100,148,165,166,719],[100,148,165,166,604,1179],[100,148,165,166,604],[100,148,165,166,598,599],[100,148,165,166,598,599,600,601],[100,148,165,166,598,600],[100,148,165,166,598],[100,148,165,166,1252],[100,148,165,166,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,717],[100,148,165,166,688],[100,148,165,166,814,918],[100,148,165,166,918],[100,148,165,166,810,812,813,814,918],[100,148,165,166,918,935],[100,148,165,166,733],[100,148,165,166,810,812,813,814,815,918,955],[100,148,165,166,809,811,812,955],[100,148,165,166,813,918],[100,148,165,166,738,739,753,767,768,797,931],[100,148,165,166,814,918,935],[100,148,165,166,811],[100,148,165,166,810,812,813,814,815,918,942],[100,148,165,166,809,810,811,812,942],[100,148,165,166,755,931],[100,148,165,166,810,812,813,814,815,918,948],[100,148,165,166,809,810,811,812,948],[100,148,165,166,931],[100,148,165,166,810,812,813,814,815,918,936],[100,148,165,166,810,811,812,936],[100,148,165,166,801,924,931],[100,148,165,166,809],[100,148,165,166,811,812,816],[100,148,165,166,735,810,811],[100,148,165,166,811,812],[100,148,165,166,811,816],[100,148,165,166,774,780],[100,148,165,166,771,780],[100,148,165,166,836,839],[100,148,165,166,733,735,781,818,823,831,832,833,834,837,853,855,864,866,871,872,873,875,876],[100,148,165,166,722,733,735,771,781,834,850,851,852,875,876],[100,148,165,166,722,771,780],[100,148,165,166,722,723,724,725,726,727,728,729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,821,822,824,825,830,831,832,833,834,835,836,837,838,839,840,841,842,843,845,846,847,849,850,851,852,853,854,855,857,858,859,860,863,864,865,866,867,868,869,870,871,874,875,876,881,882,883,884,885,886,887,888,889,890,891,892,893,894,895,896,897,898,899,900,902,903,904,905,906,907,909,912,914,915,918,919,921,922,923,924,925,926,927,928,929,930,931,932,933,934,935,936,937,938,939,940,941,942,943,944,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,962,963,964,965,966,967,968,969,970,971],[100,148,165,166,735,781,808,809,811,812,813,815,817,818,819,864,866,888,895,896,914,915,916,917],[100,148,165,166,960],[100,148,165,166,722,737],[100,148,165,166,722,746],[100,148,165,166,722,723,741],[100,148,165,166,722,754,769,770,859],[100,148,165,166,722],[100,148,165,166,722,725,741],[100,148,165,166,722,723,729,738,739,740,742,747,748,749,750,751,752],[100,148,165,166,722,796],[100,148,165,166,722,723],[100,148,165,166,722,724,725,726,727,736],[100,148,165,166,722,725,729],[100,148,165,166,722,776],[100,148,165,166,724,743,744,745],[100,148,165,166,722,723,729,741,754],[100,148,165,166,722,729,735,737,746],[100,148,165,166,722,728,758],[100,148,165,166,722,725,728,741,788],[100,148,165,166,722,754,760,765,766,769,770,778,783,787,794,795,804],[100,148,165,166,722,725],[100,148,165,166,722,728,729],[100,148,165,166,722,729],[100,148,165,166,722,728],[100,148,165,166,722,782],[100,148,165,166,722,785],[100,148,165,166,722,723,725,729,736],[100,148,165,166,722,761],[100,148,165,166,722,725,729,778,783,787,794,795,799,800,801],[100,148,165,166,722,764],[100,148,165,166,722,785,831],[100,148,165,166,722,831,867],[100,148,165,166,722,773,868,869],[100,148,165,166,722,729,765,771,778,787,794,795,796],[100,148,165,166,722,723,725,754,798],[100,148,165,166,722,798],[100,148,165,166,722,723,724,725,726,727,728,729,736,737,738,739,740,741,742,743,744,745,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,771,772,773,775,776,777,778,779,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,807,808,822,830,831,850,851,852,857,858,859,860,865,867,868,869,870,897,898,923,924,925,926,927,928,929],[100,148,165,166,722,723,724,725,726,727,728,729,736,737,738,739,740,741,742,743,744,745,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,771,772,773,775,776,777,778,779,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,807,822,830,831,850,851,852,857,858,859,860,865,867,868,869,870,897,898,923,924,925,926,927,928,929],[100,148,165,166,722,768],[100,148,165,166,722,769],[100,148,165,166,722,769,770,857,858],[100,148,165,166,722,774],[100,148,165,166,722,857],[100,148,165,166,722,723,725],[100,148,165,166,722,754,765,769,770,775,781,782,783,787,788,794,795,797,802,803,805],[100,148,165,166,722,725,729,772],[100,148,165,166,722,725,729,735],[100,148,165,166,722,775],[100,148,165,166,722,754,760,761,762,763,765,766,767,769,770,775,778,779,783,784,786,787],[100,148,165,166,722,729,771,772,774],[100,148,165,166,725,773],[100,148,165,166,722,754,760,765,766,770,778,783,787,794,795,798],[100,148,165,166,722,758,897],[100,148,165,166,722,777],[100,148,165,166,722,780,781,830,831,832,833,876],[100,148,165,166,876],[100,148,165,166,722,781,822],[100,148,165,166,722,781],[100,148,165,166,731,735,837,907],[100,148,165,166,722,771,781,829,874],[100,148,165,166,761,874,876],[100,148,165,166,725,832,833,874,898],[100,148,165,166,735,765,835,837],[100,148,165,166,734,735,837,912],[100,148,165,166,769,781,839,842,875,876],[100,148,165,166,839,857,876],[100,148,165,166,722,725,735,771,773,774,781,829,831,833,839,843,870,875],[100,148,165,166,730,731,732,734,840],[100,148,165,166,741],[100,148,165,166,735,837,855],[100,148,165,166,735,775,781,833,839,855,874,875],[100,148,165,166,781,784,874],[100,148,165,166,722,729,735,771,781,836,875],[100,148,165,166,735,832,876],[100,148,165,166,831,875,876,925],[100,148,165,166,732,735,837,906],[100,148,165,166,735,798,832,833,874,876],[100,148,165,166,722,781,785,829,875],[100,148,165,166,735,777,781,905,906,907,908,914],[100,148,165,166,735,810,811,817],[100,148,165,166,735,810,811,817,966],[100,148,165,166,758,830,831,897],[100,148,165,166,735,808,810,811],[100,148,165,166,735,771,781,834,843,854,860,862,875,876],[100,148,165,166,733,781,832,834,853,865,876],[100,148,165,166,777,780],[100,148,165,166,731,733,735,780,781,782,805,806,808,809,817,818,819,832,834,837,838,840,843,845,846,849,854,875,876,901,902,904],[100,148,165,166,733,735,781,829,833,853,856,863,876],[100,148,165,166,834,876],[100,148,165,166,730,733,735,780,781,782,802,806,808,809,817,818,819,833,840,846,849,875,899,900,901,902,903,904],[100,148,165,166,735,765,780,834,875,876],[100,148,165,166,722,771,781,868,870],[100,148,165,166,734,735,780,781,797,806,808,809,818,819,832,834,837,838,840,846,875,876,899,900,901,902,904,906],[100,148,165,166,806],[100,148,165,166,735,780,781,799,833,834,845,875,876,900],[100,148,165,166,781,843],[100,148,165,166,769,780,841],[100,148,165,166,735,874,875,901],[100,148,165,166,780,781,843,854,859,861],[100,148,165,166,833,840,901],[100,148,165,166,781,788],[100,148,165,166,733,735,781,782,786,787,788,806,808,809,817,818,819,829,832,833,834,837,838,840,843,844,845,846,847,848,849,853,854,875,876],[100,148,165,166,732,733,735,780,781,782,803,806,808,809,817,818,819,832,834,837,838,840,843,845,846,849,854,875,876,900,901,902,904],[100,148,165,166,735,834,875,876],[100,148,165,166,808,810],[100,148,165,166,722,723,724,725,726,727,728,729,736,737,738,739,740,741,742,743,744,745,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,771,772,773,775,776,777,778,779,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,807,808,809,810,822,830,831,850,851,852,857,858,859,860,865,867,868,869,870,897,898,923,924,925,926,927,928,929,930],[100,148,165,166,741,750,753,755,756,757,759,789,790,791,792,793,797,806,807,808,809],[100,148,165,166,730,778,817,818,837,840,855,873,905,908,909,910,911,913],[100,148,165,166,808,809,810,811,814,816,817,920],[100,148,165,166,809,814,817,920],[100,148,165,166,808,809,810,811,814,816,817,818],[100,148,165,166,818],[100,148,165,166,808,809,810,811,814,816,817],[100,148,165,166,741,781,808,809,811,817,888],[100,148,165,166,889],[100,148,165,166,742,780,820,823],[100,148,165,166,736,753,780,808,809,818,819,824],[100,148,165,166,753,755,780,781,808,809,818,819,876],[100,148,165,166,753,780,781,808,809,818,819,821,823,824,825,826,827,828,877,878,879,880],[100,148,165,166,753,780,808,809,818,819],[100,148,165,166,724,780],[100,148,165,166,736,737,780,781,820],[100,148,165,166,735,755,780,781,808,809,818,819,834,874,876],[100,148,165,166,756,780,808,809,818,819],[100,148,165,166,757,780,781,808,809,818,819,821,823,824,878,879,880],[100,148,165,166,759,780,808,809,818,819],[100,148,165,166,780,789,808,809,818,819,855,889],[100,148,165,166,750,780,808,809,818,819],[100,148,165,166,780,790,808,809,818,819],[100,148,165,166,780,791,808,809,818,819],[100,148,165,166,780,792,808,809,818,819],[100,148,165,166,780,793,808,809,818,819],[100,148,165,166,736,743,780],[100,148,165,166,744,780],[100,148,165,166,780,807,808,809,818,819],[100,148,165,166,817,818,881,882,883,884,885,886,887,890,891,892,893,894],[100,148,165,166,745,780],[100,148,165,166,735],[100,148,165,166,781],[100,148,165,166,730,731,732,734,735,809,819],[100,148,165,166,735,809],[100,148,165,166,730,731,732,733,734],[100,148,165,166,546,547],[100,148,165,166,1209,1247,1252,1253,1254,1255],[100,148,165,166,1209,1247,1252,1256],[100,148,165,166,1259,1262,1265,1267,1268,1269],[100,148,165,166,1219,1247,1259,1262,1265,1267,1269],[100,148,165,166,1219,1247,1259,1262,1265,1269],[100,148,165,166,1292,1293,1297],[100,148,165,166,1269,1292,1294,1297],[100,148,165,166,1269,1292,1294,1296],[100,148,165,166,1219,1247,1269,1292,1294,1295,1297],[100,148,165,166,1294,1297,1298],[100,148,165,166,1269,1292,1294,1297,1299],[100,148,165,166,1209,1219,1220,1221,1245,1246,1247,1256],[100,148,165,166,1209,1220,1247,1256],[100,148,165,166,1209,1219,1220,1247,1256],[100,148,165,166,1222,1223,1224,1225,1226,1227,1228,1229,1230,1231,1232,1233,1234,1235,1236,1237,1238,1239,1240,1241,1242,1243,1244],[100,148,165,166,1209,1213,1219,1221,1247,1256],[100,148,165,166,1270,1271,1291],[100,148,165,166,1219,1247,1292,1294,1297],[100,148,165,166,1219,1247],[100,148,165,166,1272,1273,1274,1275,1276,1277,1278,1279,1280,1281,1282,1283,1284,1285,1286,1287,1288,1289,1290],[100,148,165,166,1208,1219,1247],[100,148,165,166,1259,1260,1261,1265,1269],[100,148,165,166,1259,1262,1265,1269],[100,148,165,166,1259,1262,1263,1264,1269],[100,148,165,166,974,975],[100,148,165,166,973,974,977],[100,148,165,166,973,974,979],[100,148,165,166,974],[100,148,165,166,978,985],[100,148,165,166,973,974,975,976,977,978,980,981,982,983,984],[100,148,165,166,973],[92,100,148,165,166],[100,148,165,166,446],[100,148,165,166,453],[100,148,165,166,207,221,222,223,225,440],[100,148,165,166,207,246,248,250,251,254,440,442],[100,148,165,166,207,211,213,214,215,216,217,429,440,442],[100,148,165,166,440],[100,148,165,166,222,324,410,419,436],[100,148,165,166,207],[100,148,165,166,204,436],[100,148,165,166,258],[100,148,165,166,257,440,442],[100,148,162,165,166,306,324,353,497],[100,148,162,165,166,317,333,419,435],[100,148,162,165,166,371],[100,148,165,166,423],[100,148,165,166,422,423,424],[100,148,165,166,422],[94,100,148,162,165,166,204,207,211,214,218,219,220,222,226,234,235,364,389,420,440,443],[100,148,165,166,207,224,242,246,247,252,253,440,497],[100,148,165,166,224,497],[100,148,165,166,235,242,304,440,497],[100,148,165,166,497],[100,148,165,166,207,224,225,497],[100,148,165,166,249,497],[100,148,165,166,218,421,428],[100,148,165,166,174,266,436],[100,148,165,166,266,436],[86,100,148,165,166,266],[86,100,148,165,166,325],[100,148,165,166,321,369,436,479,480],[100,148,165,166,416,473,474,475,476,478],[100,148,165,166,415],[100,148,165,166,415,416],[100,148,165,166,215,365,366,367],[100,148,165,166,365,368,369],[100,148,165,166,477],[100,148,165,166,365,369],[86,100,148,165,166,208,467],[86,100,148,165,166,191],[86,100,148,165,166,224,294],[86,100,148,165,166,224],[100,148,165,166,292,296],[86,100,148,165,166,293,445],[100,148,165,166,1169],[86,90,100,148,162,165,166,198,199,200,201,202,203,443,489,490,1178],[100,148,162,165,166],[100,148,162,165,166,211,273,365,375,390,410,425,426,440,441,497],[100,148,165,166,234,427],[100,148,165,166,443],[100,148,165,166,206],[86,100,148,165,166,306,320,332,342,344,435],[100,148,165,166,174,306,320,341,342,343,435,496],[100,148,165,166,335,336,337,338,339,340],[100,148,165,166,337],[100,148,165,166,341],[100,148,165,166,264,265,266,268],[86,100,148,165,166,259,260,261,267],[100,148,165,166,264,267],[100,148,165,166,262],[100,148,165,166,263],[86,100,148,165,166,266,293,445],[86,100,148,165,166,266,444,445],[86,100,148,165,166,266,445],[100,148,165,166,390,432],[100,148,165,166,432],[100,148,162,165,166,441,445],[100,148,165,166,329],[100,147,148,165,166,328],[100,148,165,166,236,274,312,314,316,317,318,319,362,365,435,438,441],[100,148,165,166,236,350,365,369],[100,148,165,166,317,435],[86,100,148,165,166,317,326,327,329,330,331,332,333,334,345,346,347,348,349,351,352,435,436,497],[100,148,165,166,311],[100,148,162,165,166,174,236,237,273,288,318,362,363,364,369,390,410,431,440,441,442,443,497],[100,148,165,166,435],[100,147,148,165,166,222,315,318,364,431,433,434,441],[100,148,165,166,317],[100,147,148,165,166,273,278,307,308,309,310,311,312,313,314,316,435,436],[100,148,162,165,166,278,279,307,441,442],[100,148,165,166,222,364,365,390,431,435,441],[100,148,162,165,166,440,442],[100,148,162,165,166,180,438,441,442],[100,148,162,165,166,174,191,204,211,224,236,237,239,274,275,280,285,288,314,318,365,375,377,380,382,385,386,387,388,389,410,430,431,436,438,440,441,442],[100,148,162,165,166,180],[100,148,165,166,207,208,209,211,216,219,224,242,430,438,439,443,445,497],[100,148,162,165,166,180,191,254,256,258,259,260,261,268,497],[100,148,165,166,174,191,204,246,256,284,285,286,287,314,365,380,389,390,396,399,400,410,431,436,438],[100,148,165,166,218,219,234,364,389,431,440],[100,148,162,165,166,191,208,211,314,394,438,440],[100,148,165,166,305],[100,148,162,165,166,397,398,407],[100,148,165,166,438,440],[100,148,165,166,312,315],[100,148,165,166,314,318,430,445],[100,148,162,165,166,174,240,246,287,380,390,396,399,402,438],[100,148,162,165,166,218,234,246,403],[100,148,165,166,207,239,405,430,440],[100,148,162,165,166,191,440],[100,148,162,165,166,224,238,239,240,251,269,404,406,430,440],[94,100,148,165,166,236,318,409,443,445],[100,148,162,165,166,174,191,211,218,226,234,237,274,280,284,285,286,287,288,314,365,377,390,391,393,395,410,430,431,436,437,438,445],[100,148,162,165,166,180,218,396,401,407,438],[100,148,165,166,229,230,231,232,233],[100,148,165,166,275,381],[100,148,165,166,383],[100,148,165,166,381],[100,148,165,166,383,384],[100,148,162,165,166,211,214,215,273,441],[100,148,162,165,166,174,206,208,236,274,288,318,373,374,410,438,442,443,445],[100,148,162,165,166,174,191,210,215,314,374,437,441],[100,148,165,166,307],[100,148,165,166,308],[100,148,165,166,309],[100,148,165,166,436],[100,148,165,166,255,271],[100,148,162,165,166,211,255,274],[100,148,165,166,270,271],[100,148,165,166,272],[100,148,165,166,255,256],[100,148,165,166,255,289],[100,148,165,166,255],[100,148,165,166,275,379,437],[100,148,165,166,378],[100,148,165,166,256,436,437],[100,148,165,166,376,437],[100,148,165,166,256,436],[100,148,165,166,362],[100,148,165,166,211,216,274,303,306,312,314,318,320,323,354,357,361,365,409,430,438,441],[100,148,165,166,297,300,301,302,321,322,369],[86,100,148,165,166,201,203,266,355,356],[86,100,148,165,166,201,203,266,355,356,360],[100,148,165,166,418],[100,148,165,166,222,279,317,318,329,333,365,409,411,412,413,414,416,417,420,430,435,440],[100,148,165,166,369],[100,148,165,166,373],[100,148,162,165,166,274,290,370,372,375,409,438,443,445],[100,148,165,166,297,298,299,300,301,302,321,322,369,444],[94,100,148,162,165,166,174,191,237,255,256,288,314,318,407,408,410,430,431,440,441,443],[100,148,165,166,279,281,284,431],[100,148,162,165,166,275,440],[100,148,165,166,278,317],[100,148,165,166,277],[100,148,165,166,279,280],[100,148,165,166,276,278,440],[100,148,162,165,166,210,279,281,282,283,440,441],[86,100,148,165,166,365,366,368],[100,148,165,166,241],[86,100,148,165,166,208],[86,100,148,165,166,436],[86,94,100,148,165,166,288,318,443,445],[100,148,165,166,208,467,468],[86,100,148,165,166,296],[86,100,148,165,166,174,191,206,253,291,293,295,445],[100,148,165,166,224,436,441],[100,148,165,166,392,436],[100,148,165,166,365],[86,100,148,160,162,165,166,174,206,242,248,296,443,444],[86,100,148,165,166,199,200,201,202,203,443,491,1178],[86,87,88,89,90,100,148,165,166],[100,148,153,165,166],[100,148,165,166,243,244,245],[100,148,165,166,243],[86,90,100,148,162,164,165,166,174,198,199,200,201,202,203,204,206,237,341,402,440,442,445,491,1178],[100,148,165,166,455],[100,148,165,166,457],[100,148,165,166,459],[100,148,165,166,1170],[100,148,165,166,461],[100,148,165,166,463,464,465],[100,148,165,166,469],[91,93,100,148,165,166,447,452,454,456,458,460,462,466,470,472,482,483,485,495,496,497,498],[100,148,165,166,471],[100,148,165,166,481],[100,148,165,166,293],[100,148,165,166,484],[100,147,148,165,166,279,281,282,284,332,436,486,487,488,491,492,493,494],[100,148,165,166,540],[100,148,165,166,538,540],[100,148,165,166,529,537,538,539,541,543],[100,148,165,166,527],[100,148,165,166,530,535,540,543],[100,148,165,166,526,543],[100,148,165,166,530,531,534,535,536,543],[100,148,165,166,530,531,532,534,535,543],[100,148,165,166,527,528,529,530,531,535,536,537,539,540,541,543],[100,148,165,166,543],[100,148,165,166,525,527,528,529,530,531,532,534,535,536,537,538,539,540,541,542],[100,148,165,166,525,543],[100,148,165,166,530,532,533,535,536,543],[100,148,165,166,534,543],[100,148,165,166,535,536,540,543],[100,148,165,166,528,538],[100,148,165,166,1250],[86,100,148,165,166,1209,1218,1247,1249,1256],[86,100,148,165,166,1311,1322,1327,1333,1334,1341,1343,1344,1346,1387,1390],[86,100,148,165,166,1311,1322,1327,1332,1334,1343,1347,1348,1350,1351,1387,1390],[86,100,148,165,166,1343,1348,1392],[86,100,148,165,166,1326,1390],[86,100,148,165,166,1310,1311,1313,1322,1390],[86,100,148,165,166,1311,1322,1343,1381,1390],[86,100,148,165,166,1311,1349,1370,1374,1390],[86,100,148,165,166,1334,1357,1358,1390,1431],[100,148,165,166,1310,1390],[100,148,165,166,1322,1390],[86,100,148,165,166,1311,1322,1327,1333,1334,1387,1390],[86,100,148,165,166,1311,1313,1348,1362,1414],[86,100,148,165,166,1309,1311,1313,1362],[86,100,148,165,166,1311,1313,1342,1362,1363,1390],[86,100,148,165,166,1311,1322,1325,1329,1333,1334,1358,1372,1373,1387,1390],[86,100,148,165,166,1315,1322,1390],[86,100,148,165,166,1315,1322,1387,1390],[86,100,148,165,166,1390],[86,100,148,165,166,1348,1358,1390],[86,100,148,165,166,1310,1358,1390],[86,100,148,165,166,1358,1390],[86,100,148,165,166,1323],[86,100,148,165,166,1311,1358,1390],[86,100,148,165,166,1309,1311,1390],[86,100,148,165,166,1310,1311,1312,1390],[86,100,148,165,166,1310,1311,1313,1390,1442],[86,100,148,165,166,1335,1336,1337],[86,100,148,165,166,1322,1324,1325,1336,1358,1390,1393],[100,148,165,166,1380,1390],[100,148,165,166,1322,1323,1342,1385,1387,1390],[100,148,165,166,1309,1310,1311,1313,1314,1315,1322,1323,1325,1333,1334,1335,1338,1342,1345,1348,1349,1358,1362,1364,1370,1372,1373,1374,1375,1382,1385,1386,1387,1390,1391,1392,1394,1395,1396,1397,1398,1399,1400,1401,1403,1405,1407,1408,1409,1410,1411,1412,1415,1416,1417,1418,1419,1420,1421,1422,1423,1424,1425,1426,1427,1428,1429,1430,1431,1432,1433,1434,1435,1437,1438,1439,1440,1441],[86,100,148,165,166,1311,1327,1334,1353,1355,1390,1406],[86,100,148,165,166,1311,1315,1322,1363,1390,1404],[86,100,148,165,166,1311,1322],[86,100,148,165,166,1311,1315,1322,1363,1390,1402],[86,100,148,165,166,1311,1334,1342,1354,1363,1390],[86,100,148,165,166,1311,1322,1327,1332,1334,1343,1387,1390,1398,1406,1409],[86,100,148,165,166,1332,1390],[86,100,148,165,166,1347,1390],[100,148,165,166,1316,1321,1390],[100,148,165,166,1314,1315,1316,1321,1387,1390],[100,148,165,166,1316,1321,1326],[100,148,165,166,1316,1321,1357,1375,1390],[100,148,165,166,1316,1321,1322,1327,1328,1329,1346,1351,1352,1355,1356,1390],[100,148,165,166,1316,1321,1335,1338,1390],[100,148,165,166,1316,1321,1358,1390],[100,148,165,166,1316,1321,1322],[100,148,165,166,1316,1321],[100,148,165,166,1316,1321,1322,1361,1362,1364],[100,148,165,166,1316,1321,1322,1361,1390],[100,148,165,166,1316,1321,1323,1345,1390],[100,148,165,166,1341,1357,1380,1390],[100,148,165,166,1322,1327,1340,1341,1342,1357,1365,1368,1376,1380,1382,1383,1384,1386,1390],[100,148,165,166,1322,1327,1340,1341],[100,148,165,166,1380],[100,148,165,166,1321,1322,1327,1339,1357,1358,1359,1360,1365,1366,1367,1368,1369,1376,1377,1378,1379],[100,148,165,166,1316,1321,1322,1324,1325,1357,1390],[100,148,165,166,1327,1340,1345,1357,1390],[100,148,165,166,1340,1350,1357],[100,148,165,166,1327,1357,1390],[86,100,148,165,166,1325,1353,1354,1357,1390],[100,148,165,166,1357],[100,148,165,166,1340,1357],[100,148,165,166,1325,1327,1357,1390],[100,148,165,166,1343,1357,1390],[100,148,165,166,1358,1390],[86,100,148,165,166,1348,1349,1390],[100,148,165,166,1325,1332,1339,1341,1342,1358,1387,1390],[86,100,148,165,166,1345,1349,1370,1374,1390,1417,1418,1419,1432],[86,100,148,165,166,1390,1403,1405,1407,1408,1410],[100,148,165,166,1390],[86,100,148,165,166,1410],[100,148,165,166,1322,1390,1436],[100,148,165,166,1315,1390],[86,100,148,165,166,1357,1371,1374,1390],[100,148,165,166,1332,1340,1343,1357],[86,100,148,165,166,1353,1413],[86,100,148,165,166,1308,1309,1310,1313,1314,1315,1322,1323,1324,1327,1345,1353,1387,1388,1389,1442],[100,148,165,166,1316],[100,148,165,166,1257],[100,148,165,166,1209,1213,1247,1256],[100,148,165,166,1266,1299,1300],[100,148,165,166,1301],[100,148,165,166,1247,1248],[100,148,165,166,1209,1213,1218,1219,1247,1256],[100,148,165,166,519,551,552],[100,148,165,166,180,198],[100,148,165,166,509],[100,148,165,166,1215],[100,148,165,166,1213,1217],[100,148,165,166,1208,1213,1214,1216,1218],[100,148,165,166,1210],[100,148,165,166,1211,1212],[100,148,165,166,1208,1211,1213],[100,148,165,166,1307],[100,148,165,166,1331],[100,148,165,166,563,564],[100,148,165,166,563],[100,148,165,166,515],[100,148,159,160,162,163,164,165,166,168,180,188,191,197,198,515,516,517,519,520,522,523,524,544,545,549,550,551,552],[100,148,165,166,515,516,517,521],[100,148,165,166,517],[100,148,165,166,548],[100,148,165,166,519,552],[100,148,165,166,514,583,595],[100,148,165,166,556,575,576,595],[100,148,165,166,506,513,556,568,569,595],[100,148,165,166,578],[100,148,165,166,557],[100,148,165,166,506,514,556,558,568,577,595],[100,148,165,166,561],[100,148,151,160,165,166,180,506,511,513,552,556,558,561,562,565,568,570,571,574,577,579,580,582,595],[100,148,165,166,556,575,576,577,595],[100,148,165,166,552,581,582],[100,148,165,166,556,558,565,568,570,595],[100,148,165,166,196,571],[100,148,151,160,165,166,180,506,511,513,552,556,557,558,561,562,565,568,569,570,571,574,575,576,577,578,579,580,581,582,595],[100,148,151,160,165,166,180,196,505,506,511,513,514,552,556,557,558,561,562,565,568,569,570,571,574,575,576,577,578,579,580,581,582,594,595,596,597,602],[100,148,165,166,685],[100,148,165,166,676],[100,148,165,166,676,679],[100,148,165,166,671,674,676,677,678,679,680,681,682,683,684],[100,148,165,166,610,612,679],[100,148,165,166,676,677],[100,148,165,166,611,676,678],[100,148,165,166,612,614,616,617,618,619],[100,148,165,166,614,616,618,619],[100,148,165,166,614,616,618],[100,148,165,166,611,614,616,617,619],[100,148,165,166,610,612,613,614,615,616,617,618,619,620,621,671,672,673,674,675],[100,148,165,166,610,612,613,616],[100,148,165,166,612,613,616],[100,148,165,166,616,619],[100,148,165,166,610,611,613,614,615,617,618,619],[100,148,165,166,610,611,612,616,676],[100,148,165,166,616,617,618,619],[100,148,165,166,1040],[100,148,165,166,618],[100,148,165,166,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,644,645,646,647,648,649,650,651,652,653,654,655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670],[100,148,162,165,166,191,499,503],[100,148,165,166,603,606],[86,100,148,165,166,482,1181,1182,1183],[86,100,148,165,166,482,1167,1181,1182,1183],[100,148,165,166,1131,1132],[100,148,165,166,495,1130,1131,1135],[100,148,165,166,495,1130,1131],[100,148,153,165,166,495,1130],[100,148,165,166,495,1131],[100,148,165,166,499,1171,1172,1175],[100,148,165,166,482],[86,100,148,165,166,482,1141,1142,1174,1181,1186,1199,1203,1206,1207,1303,1304,1305,1443,1445],[86,100,148,165,166,482,1172,1174,1181,1182,1183,1186,1199,1448],[86,100,148,165,166,482,1141,1142,1174,1181,1182,1183,1186,1199,1201,1202,1203],[86,100,148,165,166,482,1167,1174],[86,100,148,165,166,606,1181,1186,1202,1302],[86,100,148,165,166,606,1181,1186,1207],[100,148,165,166,606,1181,1186],[86,100,148,165,166,1181,1186],[100,148,165,166,606,1173],[100,148,165,166,606,1251,1258,1301],[86,100,148,165,166,1181,1182,1186,1201,1207,1448],[100,148,165,166,606,1453],[100,148,165,166,606,1141,1205],[86,100,148,165,166,1141,1142,1172,1181,1186,1198,1202,1205,1207,1302],[86,100,148,165,166,606,1141,1181,1186,1205],[100,148,165,166,606,1141],[86,100,148,165,166,1141,1186,1442],[86,100,148,165,166,472,482,606,1167,1181,1186,1198],[86,100,148,165,166,606,1458],[86,100,148,165,166,606,1180],[86,100,148,165,166,606,1178,1180],[86,100,148,165,166,606],[86,100,148,165,166,606,1186,1200],[86,100,148,165,166,606,1186,1197],[86,100,148,165,166,606,1186,1447],[100,148,165,166,606],[86,100,148,165,166,606,1444],[86,100,148,165,166,606,1452],[100,148,165,166,1141],[100,148,165,166,1144,1166],[100,148,165,166,1042,1123,1125,1130],[100,148,165,166,1129],[100,148,165,166,604,605],[100,148,165,166,495],[100,148,165,166,170,584,591]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","impliedFormat":1},{"version":"ee7bad0c15b58988daa84371e0b89d313b762ab83cb5b31b8a2d1162e8eb41c2","impliedFormat":1},{"version":"27bdc30a0e32783366a5abeda841bc22757c1797de8681bbe81fbc735eeb1c10","impliedFormat":1},{"version":"8fd575e12870e9944c7e1d62e1f5a73fcf23dd8d3a321f2a2c74c20d022283fe","impliedFormat":1},{"version":"2ab096661c711e4a81cc464fa1e6feb929a54f5340b46b0a07ac6bbf857471f0","impliedFormat":1},{"version":"080941d9f9ff9307f7e27a83bcd888b7c8270716c39af943532438932ec1d0b9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2e80ee7a49e8ac312cc11b77f1475804bee36b3b2bc896bead8b6e1266befb43","affectsGlobalScope":true,"impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a680117f487a4d2f30ea46f1b4b7f58bef1480456e18ba53ee85c2746eeca012","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true,"impliedFormat":1},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true,"impliedFormat":1},{"version":"959d36cddf5e7d572a65045b876f2956c973a586da58e5d26cde519184fd9b8a","affectsGlobalScope":true,"impliedFormat":1},{"version":"965f36eae237dd74e6cca203a43e9ca801ce38824ead814728a2807b1910117d","affectsGlobalScope":true,"impliedFormat":1},{"version":"3925a6c820dcb1a06506c90b1577db1fdbf7705d65b62b99dce4be75c637e26b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a3d63ef2b853447ec4f749d3f368ce642264246e02911fcb1590d8c161b8005","affectsGlobalScope":true,"impliedFormat":1},{"version":"8cdf8847677ac7d20486e54dd3fcf09eda95812ac8ace44b4418da1bbbab6eb8","affectsGlobalScope":true,"impliedFormat":1},{"version":"8444af78980e3b20b49324f4a16ba35024fef3ee069a0eb67616ea6ca821c47a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3287d9d085fbd618c3971944b65b4be57859f5415f495b33a6adc994edd2f004","affectsGlobalScope":true,"impliedFormat":1},{"version":"b4b67b1a91182421f5df999988c690f14d813b9850b40acd06ed44691f6727ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"df83c2a6c73228b625b0beb6669c7ee2a09c914637e2d35170723ad49c0f5cd4","affectsGlobalScope":true,"impliedFormat":1},{"version":"436aaf437562f276ec2ddbee2f2cdedac7664c1e4c1d2c36839ddd582eeb3d0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e3c06ea092138bf9fa5e874a1fdbc9d54805d074bee1de31b99a11e2fec239d","affectsGlobalScope":true,"impliedFormat":1},{"version":"87dc0f382502f5bbce5129bdc0aea21e19a3abbc19259e0b43ae038a9fc4e326","affectsGlobalScope":true,"impliedFormat":1},{"version":"b1cb28af0c891c8c96b2d6b7be76bd394fddcfdb4709a20ba05a7c1605eea0f9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2fef54945a13095fdb9b84f705f2b5994597640c46afeb2ce78352fab4cb3279","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac77cb3e8c6d3565793eb90a8373ee8033146315a3dbead3bde8db5eaf5e5ec6","affectsGlobalScope":true,"impliedFormat":1},{"version":"56e4ed5aab5f5920980066a9409bfaf53e6d21d3f8d020c17e4de584d29600ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ece9f17b3866cc077099c73f4983bddbcb1dc7ddb943227f1ec070f529dedd1","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a6282c8827e4b9a95f4bf4f5c205673ada31b982f50572d27103df8ceb8013c","affectsGlobalScope":true,"impliedFormat":1},{"version":"1c9319a09485199c1f7b0498f2988d6d2249793ef67edda49d1e584746be9032","affectsGlobalScope":true,"impliedFormat":1},{"version":"e3a2a0cee0f03ffdde24d89660eba2685bfbdeae955a6c67e8c4c9fd28928eeb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811c71eee4aa0ac5f7adf713323a5c41b0cf6c4e17367a34fbce379e12bbf0a4","affectsGlobalScope":true,"impliedFormat":1},{"version":"51ad4c928303041605b4d7ae32e0c1ee387d43a24cd6f1ebf4a2699e1076d4fa","affectsGlobalScope":true,"impliedFormat":1},{"version":"60037901da1a425516449b9a20073aa03386cce92f7a1fd902d7602be3a7c2e9","affectsGlobalScope":true,"impliedFormat":1},{"version":"d4b1d2c51d058fc21ec2629fff7a76249dec2e36e12960ea056e3ef89174080f","affectsGlobalScope":true,"impliedFormat":1},{"version":"22adec94ef7047a6c9d1af3cb96be87a335908bf9ef386ae9fd50eeb37f44c47","affectsGlobalScope":true,"impliedFormat":1},{"version":"196cb558a13d4533a5163286f30b0509ce0210e4b316c56c38d4c0fd2fb38405","affectsGlobalScope":true,"impliedFormat":1},{"version":"73f78680d4c08509933daf80947902f6ff41b6230f94dd002ae372620adb0f60","affectsGlobalScope":true,"impliedFormat":1},{"version":"c5239f5c01bcfa9cd32f37c496cf19c61d69d37e48be9de612b541aac915805b","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"b4f843262b884a9bfd886722a8b95bde4e42566948d2460d3ffa29739e59f055","affectsGlobalScope":true},{"version":"7e29f41b158de217f94cb9676bf9cbd0cd9b5a46e1985141ed36e075c52bf6ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac51dd7d31333793807a6abaa5ae168512b6131bd41d9c5b98477fc3b7800f9f","impliedFormat":1},{"version":"dc0a7f107690ee5cd8afc8dbf05c4df78085471ce16bdd9881642ec738bc81fe","impliedFormat":1},{"version":"acd8fd5090ac73902278889c38336ff3f48af6ba03aa665eb34a75e7ba1dccc4","impliedFormat":1},{"version":"d6258883868fb2680d2ca96bc8b1352cab69874581493e6d52680c5ffecdb6cc","impliedFormat":1},{"version":"1b61d259de5350f8b1e5db06290d31eaebebc6baafd5f79d314b5af9256d7153","impliedFormat":1},{"version":"f258e3960f324a956fc76a3d3d9e964fff2244ff5859dcc6ce5951e5413ca826","impliedFormat":1},{"version":"643f7232d07bf75e15bd8f658f664d6183a0efaca5eb84b48201c7671a266979","impliedFormat":1},{"version":"0f6666b58e9276ac3a38fdc80993d19208442d6027ab885580d93aec76b4ef00","impliedFormat":1},{"version":"05fd364b8ef02fb1e174fbac8b825bdb1e5a36a016997c8e421f5fab0a6da0a0","impliedFormat":1},{"version":"631eff75b0e35d1b1b31081d55209abc43e16b49426546ab5a9b40bdd40b1f60","impliedFormat":1},{"version":"6c7176368037af28cb72f2392010fa1cef295d6d6744bca8cfb54985f3a18c3e","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true,"impliedFormat":1},{"version":"437e20f2ba32abaeb7985e0afe0002de1917bc74e949ba585e49feba65da6ca1","affectsGlobalScope":true,"impliedFormat":1},{"version":"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a","impliedFormat":1},{"version":"98cffbf06d6bab333473c70a893770dbe990783904002c4f1a960447b4b53dca","affectsGlobalScope":true,"impliedFormat":1},{"version":"3af97acf03cc97de58a3a4bc91f8f616408099bc4233f6d0852e72a8ffb91ac9","affectsGlobalScope":true,"impliedFormat":1},{"version":"808069bba06b6768b62fd22429b53362e7af342da4a236ed2d2e1c89fcca3b4a","affectsGlobalScope":true,"impliedFormat":1},{"version":"1db0b7dca579049ca4193d034d835f6bfe73096c73663e5ef9a0b5779939f3d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"f26b11d8d8e4b8028f1c7d618b22274c892e4b0ef5b3678a8ccbad85419aef43","affectsGlobalScope":true,"impliedFormat":1},{"version":"5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","impliedFormat":1},{"version":"763fe0f42b3d79b440a9b6e51e9ba3f3f91352469c1e4b3b67bfa4ff6352f3f4","impliedFormat":1},{"version":"25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","impliedFormat":1},{"version":"c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","impliedFormat":1},{"version":"78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","impliedFormat":1},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","impliedFormat":1},{"version":"1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","impliedFormat":1},{"version":"5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","impliedFormat":1},{"version":"7f182617db458e98fc18dfb272d40aa2fff3a353c44a89b2c0ccb3937709bfb5","impliedFormat":1},{"version":"cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","impliedFormat":1},{"version":"385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","impliedFormat":1},{"version":"9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","impliedFormat":1},{"version":"0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","impliedFormat":1},{"version":"11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","impliedFormat":1},{"version":"ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","impliedFormat":1},{"version":"4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","impliedFormat":1},{"version":"c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","impliedFormat":1},{"version":"13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","impliedFormat":1},{"version":"9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","impliedFormat":1},{"version":"4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","impliedFormat":1},{"version":"24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","impliedFormat":1},{"version":"ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","impliedFormat":1},{"version":"24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","impliedFormat":1},{"version":"dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","impliedFormat":1},{"version":"405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","impliedFormat":1},{"version":"0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","impliedFormat":1},{"version":"e61be3f894b41b7baa1fbd6a66893f2579bfad01d208b4ff61daef21493ef0a8","impliedFormat":1},{"version":"bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","impliedFormat":1},{"version":"89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","impliedFormat":1},{"version":"615ba88d0128ed16bf83ef8ccbb6aff05c3ee2db1cc0f89ab50a4939bfc1943f","impliedFormat":1},{"version":"a4d551dbf8746780194d550c88f26cf937caf8d56f102969a110cfaed4b06656","impliedFormat":1},{"version":"8bd86b8e8f6a6aa6c49b71e14c4ffe1211a0e97c80f08d2c8cc98838006e4b88","impliedFormat":1},{"version":"317e63deeb21ac07f3992f5b50cdca8338f10acd4fbb7257ebf56735bf52ab00","impliedFormat":1},{"version":"4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107","impliedFormat":1},{"version":"b52476feb4a0cbcb25e5931b930fc73cb6643fb1a5060bf8a3dda0eeae5b4b68","affectsGlobalScope":true,"impliedFormat":1},{"version":"f9501cc13ce624c72b61f12b3963e84fad210fbdf0ffbc4590e08460a3f04eba","affectsGlobalScope":true,"impliedFormat":1},{"version":"e7721c4f69f93c91360c26a0a84ee885997d748237ef78ef665b153e622b36c1","affectsGlobalScope":true,"impliedFormat":1},{"version":"0fa06ada475b910e2106c98c68b10483dc8811d0c14a8a8dd36efb2672485b29","impliedFormat":1},{"version":"33e5e9aba62c3193d10d1d33ae1fa75c46a1171cf76fef750777377d53b0303f","impliedFormat":1},{"version":"2b06b93fd01bcd49d1a6bd1f9b65ddcae6480b9a86e9061634d6f8e354c1468f","impliedFormat":1},{"version":"6a0cd27e5dc2cfbe039e731cf879d12b0e2dded06d1b1dedad07f7712de0d7f4","affectsGlobalScope":true,"impliedFormat":1},{"version":"13f5c844119c43e51ce777c509267f14d6aaf31eafb2c2b002ca35584cd13b29","impliedFormat":1},{"version":"e60477649d6ad21542bd2dc7e3d9ff6853d0797ba9f689ba2f6653818999c264","impliedFormat":1},{"version":"c2510f124c0293ab80b1777c44d80f812b75612f297b9857406468c0f4dafe29","affectsGlobalScope":true,"impliedFormat":1},{"version":"5524481e56c48ff486f42926778c0a3cce1cc85dc46683b92b1271865bcf015a","impliedFormat":1},{"version":"4c829ab315f57c5442c6667b53769975acbf92003a66aef19bce151987675bd1","affectsGlobalScope":true,"impliedFormat":1},{"version":"b2ade7657e2db96d18315694789eff2ddd3d8aea7215b181f8a0b303277cc579","impliedFormat":1},{"version":"9855e02d837744303391e5623a531734443a5f8e6e8755e018c41d63ad797db2","impliedFormat":1},{"version":"4d631b81fa2f07a0e63a9a143d6a82c25c5f051298651a9b69176ba28930756d","impliedFormat":1},{"version":"836a356aae992ff3c28a0212e3eabcb76dd4b0cc06bcb9607aeef560661b860d","impliedFormat":1},{"version":"1e0d1f8b0adfa0b0330e028c7941b5a98c08b600efe7f14d2d2a00854fb2f393","impliedFormat":1},{"version":"41670ee38943d9cbb4924e436f56fc19ee94232bc96108562de1a734af20dc2c","affectsGlobalScope":true,"impliedFormat":1},{"version":"c906fb15bd2aabc9ed1e3f44eb6a8661199d6c320b3aa196b826121552cb3695","impliedFormat":1},{"version":"22295e8103f1d6d8ea4b5d6211e43421fe4564e34d0dd8e09e520e452d89e659","impliedFormat":1},{"version":"58647d85d0f722a1ce9de50955df60a7489f0593bf1a7015521efe901c06d770","impliedFormat":1},{"version":"6b4e081d55ac24fc8a4631d5dd77fe249fa25900abd7d046abb87d90e3b45645","impliedFormat":1},{"version":"a10f0e1854f3316d7ee437b79649e5a6ae3ae14ffe6322b02d4987071a95362e","impliedFormat":1},{"version":"e208f73ef6a980104304b0d2ca5f6bf1b85de6009d2c7e404028b875020fa8f2","impliedFormat":1},{"version":"d163b6bc2372b4f07260747cbc6c0a6405ab3fbcea3852305e98ac43ca59f5bc","impliedFormat":1},{"version":"e6fa9ad47c5f71ff733744a029d1dc472c618de53804eae08ffc243b936f87ff","affectsGlobalScope":true,"impliedFormat":1},{"version":"83e63d6ccf8ec004a3bb6d58b9bb0104f60e002754b1e968024b320730cc5311","impliedFormat":1},{"version":"24826ed94a78d5c64bd857570fdbd96229ad41b5cb654c08d75a9845e3ab7dde","impliedFormat":1},{"version":"8b479a130ccb62e98f11f136d3ac80f2984fdc07616516d29881f3061f2dd472","impliedFormat":1},{"version":"928af3d90454bf656a52a48679f199f64c1435247d6189d1caf4c68f2eaf921f","affectsGlobalScope":true,"impliedFormat":1},{"version":"bceb58df66ab8fb00170df20cd813978c5ab84be1d285710c4eb005d8e9d8efb","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f16a7e4deafa527ed9995a772bb380eb7d3c2c0fd4ae178c5263ed18394db2c","impliedFormat":1},{"version":"933921f0bb0ec12ef45d1062a1fc0f27635318f4d294e4d99de9a5493e618ca2","impliedFormat":1},{"version":"71a0f3ad612c123b57239a7749770017ecfe6b66411488000aba83e4546fde25","impliedFormat":1},{"version":"77fbe5eecb6fac4b6242bbf6eebfc43e98ce5ccba8fa44e0ef6a95c945ff4d98","impliedFormat":1},{"version":"4f9d8ca0c417b67b69eeb54c7ca1bedd7b56034bb9bfd27c5d4f3bc4692daca7","impliedFormat":1},{"version":"814118df420c4e38fe5ae1b9a3bafb6e9c2aa40838e528cde908381867be6466","impliedFormat":1},{"version":"a3fc63c0d7b031693f665f5494412ba4b551fe644ededccc0ab5922401079c95","impliedFormat":1},{"version":"f27524f4bef4b6519c604bdb23bf4465bddcccbf3f003abb901acbd0d7404d99","impliedFormat":1},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","impliedFormat":1},{"version":"45650f47bfb376c8a8ed39d4bcda5902ab899a3150029684ee4c10676d9fbaee","impliedFormat":1},{"version":"6b039f55681caaf111d5eb84d292b9bee9e0131d0db1ad0871eef0964f533c73","affectsGlobalScope":true,"impliedFormat":1},{"version":"18fd40412d102c5564136f29735e5d1c3b455b8a37f920da79561f1fde068208","impliedFormat":1},{"version":"c8d3e5a18ba35629954e48c4cc8f11dc88224650067a172685c736b27a34a4dc","impliedFormat":1},{"version":"f0be1b8078cd549d91f37c30c222c2a187ac1cf981d994fb476a1adc61387b14","affectsGlobalScope":true,"impliedFormat":1},{"version":"0aaed1d72199b01234152f7a60046bc947f1f37d78d182e9ae09c4289e06a592","impliedFormat":1},{"version":"2b55d426ff2b9087485e52ac4bc7cfafe1dc420fc76dad926cd46526567c501a","impliedFormat":1},{"version":"66ba1b2c3e3a3644a1011cd530fb444a96b1b2dfe2f5e837a002d41a1a799e60","impliedFormat":1},{"version":"7e514f5b852fdbc166b539fdd1f4e9114f29911592a5eb10a94bb3a13ccac3c4","impliedFormat":1},{"version":"5b7aa3c4c1a5d81b411e8cb302b45507fea9358d3569196b27eb1a27ae3a90ef","affectsGlobalScope":true,"impliedFormat":1},{"version":"5987a903da92c7462e0b35704ce7da94d7fdc4b89a984871c0e2b87a8aae9e69","affectsGlobalScope":true,"impliedFormat":1},{"version":"ea08a0345023ade2b47fbff5a76d0d0ed8bff10bc9d22b83f40858a8e941501c","impliedFormat":1},{"version":"47613031a5a31510831304405af561b0ffaedb734437c595256bb61a90f9311b","impliedFormat":1},{"version":"ae062ce7d9510060c5d7e7952ae379224fb3f8f2dd74e88959878af2057c143b","impliedFormat":1},{"version":"8a1a0d0a4a06a8d278947fcb66bf684f117bf147f89b06e50662d79a53be3e9f","affectsGlobalScope":true,"impliedFormat":1},{"version":"358765d5ea8afd285d4fd1532e78b88273f18cb3f87403a9b16fef61ac9fdcfe","impliedFormat":1},{"version":"9f55299850d4f0921e79b6bf344b47c420ce0f507b9dcf593e532b09ea7eeea1","impliedFormat":1},{"version":"2beff543f6e9a9701df88daeee3cdd70a34b4a1c11cb4c734472195a5cb2af54","impliedFormat":1},{"version":"2e07abf27aa06353d46f4448c0bbac73431f6065eef7113128a5cd804d0c384d","impliedFormat":1},{"version":"be1cc4d94ea60cbe567bc29ed479d42587bf1e6cba490f123d329976b0fe4ee5","impliedFormat":1},{"version":"42bc0e1a903408137c3df2b06dfd7e402cdab5bbfa5fcfb871b22ebfdb30bd0b","impliedFormat":1},{"version":"9894dafe342b976d251aac58e616ac6df8db91fb9d98934ff9dd103e9e82578f","impliedFormat":1},{"version":"413df52d4ea14472c2fa5bee62f7a40abd1eb49be0b9722ee01ee4e52e63beb2","impliedFormat":1},{"version":"db6d2d9daad8a6d83f281af12ce4355a20b9a3e71b82b9f57cddcca0a8964a96","impliedFormat":1},{"version":"829b9e6028b29e6a8b1c01ddb713efe59da04d857089298fa79acbdb3cfcfdef","impliedFormat":1},{"version":"24f8562308dd8ba6013120557fa7b44950b619610b2c6cb8784c79f11e3c4f90","impliedFormat":1},{"version":"5d8717b437b9d6afeb4da84b9082db35cafce3dfd025bc7c9ad7abbe50fa2778","impliedFormat":1},{"version":"a86f82d646a739041d6702101afa82dcb935c416dd93cbca7fd754fd0282ce1f","impliedFormat":1},{"version":"ad0d1d75d129b1c80f911be438d6b61bfa8703930a8ff2be2f0e1f8a91841c64","impliedFormat":1},{"version":"ce75b1aebb33d510ff28af960a9221410a3eaf7f18fc5f21f9404075fba77256","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"496bbf339f3838c41f164238543e9fe5f1f10659cb30b68903851618464b98ba","impliedFormat":1},{"version":"5178eb4415a172c287c711dc60a619e110c3fd0b7de01ed0627e51a5336aa09c","impliedFormat":1},{"version":"ca6e5264278b53345bc1ce95f42fb0a8b733a09e3d6479c6ccfca55cdc45038c","impliedFormat":1},{"version":"9e2739b32f741859263fdba0244c194ca8e96da49b430377930b8f721d77c000","impliedFormat":1},{"version":"fb1d8e814a3eeb5101ca13515e0548e112bd1ff3fb358ece535b93e94adf5a3a","impliedFormat":1},{"version":"ffa495b17a5ef1d0399586b590bd281056cee6ce3583e34f39926f8dcc6ecdb5","impliedFormat":1},{"version":"98b18458acb46072947aabeeeab1e410f047e0cacc972943059ca5500b0a5e95","impliedFormat":1},{"version":"361e2b13c6765d7f85bb7600b48fde782b90c7c41105b7dab1f6e7871071ba20","impliedFormat":1},{"version":"c86fe861cf1b4c46a0fb7d74dffe596cf679a2e5e8b1456881313170f092e3fa","impliedFormat":1},{"version":"b6db56e4903e9c32e533b78ac85522de734b3d3a8541bf24d256058d464bf04b","impliedFormat":1},{"version":"24daa0366f837d22c94a5c0bad5bf1fd0f6b29e1fae92dc47c3072c3fdb2fbd5","impliedFormat":1},{"version":"570bb5a00836ffad3e4127f6adf581bfc4535737d8ff763a4d6f4cc877e60d98","impliedFormat":1},{"version":"889c00f3d32091841268f0b994beba4dceaa5df7573be12c2c829d7c5fbc232c","impliedFormat":1},{"version":"65f43099ded6073336e697512d9b80f2d4fec3182b7b2316abf712e84104db00","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"acf5a2ac47b59ca07afa9abbd2b31d001bf7448b041927befae2ea5b1951d9f9","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"d71291eff1e19d8762a908ba947e891af44749f3a2cbc5bd2ec4b72f72ea795f","impliedFormat":1},{"version":"c0480e03db4b816dff2682b347c95f2177699525c54e7e6f6aa8ded890b76be7","impliedFormat":1},{"version":"27ab780875bcbb65e09da7496f2ca36288b0c541abaa75c311450a077d54ec15","impliedFormat":1},{"version":"b620391fe8060cf9bedc176a4d01366e6574d7a71e0ac0ab344a4e76576fcbb8","impliedFormat":1},{"version":"380647d8f3b7f852cca6d154a376dbf8ac620a2f12b936594504a8a852e71d2f","impliedFormat":1},{"version":"208c9af9429dd3c76f5927b971263174aaa4bc7621ddec63f163640cbd3c473c","impliedFormat":1},{"version":"6459054aabb306821a043e02b89d54da508e3a6966601a41e71c166e4ea1474f","impliedFormat":1},{"version":"a23185bc5ef590c287c28a91baf280367b50ae4ea40327366ad01f6f4a8edbc5","impliedFormat":1},{"version":"bb37588926aba35c9283fe8d46ebf4e79ffe976343105f5c6d45f282793352b2","impliedFormat":1},{"version":"002eae065e6960458bda3cf695e578b0d1e2785523476f8a9170b103c709cd4f","impliedFormat":1},{"version":"c83bb0c9c5645a46c68356c2f73fdc9de339ce77f7f45a954f560c7e0b8d5ebb","impliedFormat":1},{"version":"05c97cddbaf99978f83d96de2d8af86aded9332592f08ce4a284d72d0952c391","impliedFormat":1},{"version":"72179f9dd22a86deaad4cc3490eb0fe69ee084d503b686985965654013f1391b","impliedFormat":1},{"version":"2e6114a7dd6feeef85b2c80120fdbfb59a5529c0dcc5bfa8447b6996c97a69f5","impliedFormat":1},{"version":"7b6ff760c8a240b40dab6e4419b989f06a5b782f4710d2967e67c695ef3e93c4","impliedFormat":1},{"version":"c8f004e6036aa1c764ad4ec543cf89a5c1893a9535c80ef3f2b653e370de45e6","impliedFormat":1},{"version":"dd80b1e600d00f5c6a6ba23f455b84a7db121219e68f89f10552c54ba46e4dc9","impliedFormat":1},{"version":"b064c36f35de7387d71c599bfcf28875849a1dbc733e82bd26cae3d1cd060521","impliedFormat":1},{"version":"6a148329edecbda07c21098639ef4254ef7869fb25a69f58e5d6a8b7b69d4236","impliedFormat":1},{"version":"8de9fe97fa9e00ec00666fa77ab6e91b35d25af8ca75dabcb01e14ad3299b150","impliedFormat":1},{"version":"f63ab283a1c8f5c79fabe7ca4ef85f9633339c4f0e822fce6a767f9d59282af2","impliedFormat":1},{"version":"dba114fb6a32b355a9cfc26ca2276834d72fe0e94cd2c3494005547025015369","impliedFormat":1},{"version":"a54c996c8870ef1728a2c1fa9b8eaec0bf4a8001cd2583c02dd5869289465b10","impliedFormat":1},{"version":"3e7efde639c6a6c3edb9847b3f61e308bf7a69685b92f665048c45132f51c218","impliedFormat":1},{"version":"df45ca1176e6ac211eae7ddf51336dc075c5314bc5c253651bae639defd5eec5","impliedFormat":1},{"version":"3754982006a3b32c502cff0867ca83584f7a43b1035989ca73603f400de13c96","impliedFormat":1},{"version":"a30ae9bb8a8fa7b90f24b8a0496702063ae4fe75deb27da731ed4a03b2eb6631","impliedFormat":1},{"version":"f974e4a06953682a2c15d5bd5114c0284d5abf8bc0fe4da25cb9159427b70072","impliedFormat":1},{"version":"50256e9c31318487f3752b7ac12ff365c8949953e04568009c8705db802776fb","impliedFormat":1},{"version":"7d73b24e7bf31dfb8a931ca6c4245f6bb0814dfae17e4b60c9e194a631fe5f7b","impliedFormat":1},{"version":"413586add0cfe7369b64979d4ec2ed56c3f771c0667fbde1bf1f10063ede0b08","impliedFormat":1},{"version":"06472528e998d152375ad3bd8ebcb69ff4694fd8d2effaf60a9d9f25a37a097a","impliedFormat":1},{"version":"50b5bc34ce6b12eccb76214b51aadfa56572aa6cc79c2b9455cdbb3d6c76af1d","impliedFormat":1},{"version":"b7e16ef7f646a50991119b205794ebfd3a4d8f8e0f314981ebbe991639023d0e","impliedFormat":1},{"version":"42c169fb8c2d42f4f668c624a9a11e719d5d07dacbebb63cbcf7ef365b0a75b3","impliedFormat":1},{"version":"a401617604fa1f6ce437b81689563dfdc377069e4c58465dbd8d16069aede0a5","impliedFormat":1},{"version":"e9dd71cf12123419c60dab867d44fbee5c358169f99529121eaef277f5c83531","impliedFormat":1},{"version":"5b6a189ba3a0befa1f5d9cb028eb9eec2af2089c32f04ff50e2411f63d70f25d","impliedFormat":1},{"version":"d6e73f8010935b7b4c7487b6fb13ea197cc610f0965b759bec03a561ccf8423a","impliedFormat":1},{"version":"174f3864e398f3f33f9a446a4f403d55a892aa55328cf6686135dfaf9e171657","impliedFormat":1},{"version":"824c76aec8d8c7e65769688cbee102238c0ef421ed6686f41b2a7d8e7e78a931","impliedFormat":1},{"version":"75b868be3463d5a8cfc0d9396f0a3d973b8c297401d00bfb008a42ab16643f13","impliedFormat":1},{"version":"15a234e5031b19c48a69ccc1607522d6e4b50f57d308ecb7fe863d44cd9f9eb3","impliedFormat":1},{"version":"d682336018141807fb602709e2d95a192828fcb8d5ba06dda3833a8ea98f69e3","impliedFormat":1},{"version":"6124e973eab8c52cabf3c07575204efc1784aca6b0a30c79eb85fe240a857efa","impliedFormat":1},{"version":"0d891735a21edc75df51f3eb995e18149e119d1ce22fd40db2b260c5960b914e","impliedFormat":1},{"version":"3b414b99a73171e1c4b7b7714e26b87d6c5cb03d200352da5342ab4088a54c85","impliedFormat":1},{"version":"4fbd3116e00ed3a6410499924b6403cc9367fdca303e34838129b328058ede40","impliedFormat":1},{"version":"b01bd582a6e41457bc56e6f0f9de4cb17f33f5f3843a7cf8210ac9c18472fb0f","impliedFormat":1},{"version":"0a437ae178f999b46b6153d79095b60c42c996bc0458c04955f1c996dc68b971","impliedFormat":1},{"version":"74b2a5e5197bd0f2e0077a1ea7c07455bbea67b87b0869d9786d55104006784f","impliedFormat":1},{"version":"4a7baeb6325920044f66c0f8e5e6f1f52e06e6d87588d837bdf44feb6f35c664","impliedFormat":1},{"version":"6dcf60530c25194a9ee0962230e874ff29d34c59605d8e069a49928759a17e0a","impliedFormat":1},{"version":"7274fbffbd7c9589d8d0ffba68157237afd5cecff1e99881ea3399127e60572f","impliedFormat":1},{"version":"1a42d2ec31a1fe62fdc51591768695ed4a2dc64c01be113e7ff22890bebb5e3f","impliedFormat":1},{"version":"1a82deef4c1d39f6882f28d275cad4c01f907b9b39be9cbc472fcf2cf051e05b","impliedFormat":1},{"version":"c5426dbfc1cf90532f66965a7aa8c1136a78d4d0f96d8180ecbfc11d7722f1a5","impliedFormat":1},{"version":"65a15fc47900787c0bd18b603afb98d33ede930bed1798fc984d5ebb78b26cf9","impliedFormat":1},{"version":"9d202701f6e0744adb6314d03d2eb8fc994798fc83d91b691b75b07626a69801","impliedFormat":1},{"version":"de9d2df7663e64e3a91bf495f315a7577e23ba088f2949d5ce9ec96f44fba37d","impliedFormat":1},{"version":"c7af78a2ea7cb1cd009cfb5bdb48cd0b03dad3b54f6da7aab615c2e9e9d570c5","impliedFormat":1},{"version":"1ee45496b5f8bdee6f7abc233355898e5bf9bd51255db65f5ff7ede617ca0027","impliedFormat":1},{"version":"0c7c947ff881c4274c0800deaa0086971e0bfe51f89a33bd3048eaa3792d4876","affectsGlobalScope":true,"impliedFormat":1},{"version":"db01d18853469bcb5601b9fc9826931cc84cc1a1944b33cad76fd6f1e3d8c544","affectsGlobalScope":true,"impliedFormat":1},{"version":"a8f8e6ab2fa07b45251f403548b78eaf2022f3c2254df3dc186cb2671fe4996d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fa6c12a7c0f6b84d512f200690bfc74819e99efae69e4c95c4cd30f6884c526e","impliedFormat":1},{"version":"f1c32f9ce9c497da4dc215c3bc84b722ea02497d35f9134db3bb40a8d918b92b","impliedFormat":1},{"version":"b73c319af2cc3ef8f6421308a250f328836531ea3761823b4cabbd133047aefa","affectsGlobalScope":true,"impliedFormat":1},{"version":"e433b0337b8106909e7953015e8fa3f2d30797cea27141d1c5b135365bb975a6","impliedFormat":1},{"version":"15b36126e0089bfef173ab61329e8286ce74af5e809d8a72edcafd0cc049057f","impliedFormat":1},{"version":"ddff7fc6edbdc5163a09e22bf8df7bef75f75369ebd7ecea95ba55c4386e2441","impliedFormat":1},{"version":"106c6025f1d99fd468fd8bf6e5bda724e11e5905a4076c5d29790b6c3745e50c","impliedFormat":1},{"version":"a57b1802794433adec9ff3fed12aa79d671faed86c49b09e02e1ac41b4f1d33a","impliedFormat":1},{"version":"ad10d4f0517599cdeca7755b930f148804e3e0e5b5a3847adce0f1f71bbccd74","impliedFormat":1},{"version":"1042064ece5bb47d6aba91648fbe0635c17c600ebdf567588b4ca715602f0a9d","impliedFormat":1},{"version":"c49469a5349b3cc1965710b5b0f98ed6c028686aa8450bcb3796728873eb923e","impliedFormat":1},{"version":"4a889f2c763edb4d55cb624257272ac10d04a1cad2ed2948b10ed4a7fda2a428","impliedFormat":1},{"version":"7bb79aa2fead87d9d56294ef71e056487e848d7b550c9a367523ee5416c44cfa","impliedFormat":1},{"version":"72d63643a657c02d3e51cd99a08b47c9b020a565c55f246907050d3c8a5e77fb","impliedFormat":1},{"version":"1d415445ea58f8033ba199703e55ff7483c52ac6742075b803bd3e7bbe9f5d61","impliedFormat":1},{"version":"d6406c629bb3efc31aedb2de809bef471e475c86c7e67f3ef9b676b5d7e0d6b2","impliedFormat":1},{"version":"27ff4196654e6373c9af16b6165120e2dd2169f9ad6abb5c935af5abd8c7938c","impliedFormat":1},{"version":"71d8ba39a9e024d9e4bb922464d18542ed8d2c25ee78efa7890c27213cc6e5d3","impliedFormat":1},{"version":"8c030e515014c10a2b98f9f48408e3ba18023dfd3f56e3312c6c2f3ae1f55a16","impliedFormat":1},{"version":"dafc31e9e8751f437122eb8582b93d477e002839864410ff782504a12f2a550c","impliedFormat":1},{"version":"754498c5208ce3c5134f6eabd49b25cf5e1a042373515718953581636491f3c3","impliedFormat":1},{"version":"9c82171d836c47486074e4ca8e059735bf97b205e70b196535b5efd40cbe1bc5","impliedFormat":1},{"version":"f56bdc6884648806d34bc66d31cdb787c4718d04105ce2cd88535db214631f82","impliedFormat":1},{"version":"633d58a237f4bb25ec7d565e4ffa32cecdcee8660ac12189c4351c52557cee9e","impliedFormat":1},{"version":"2e4f37ffe8862b14d8e24ae8763daaa8340c0df0b859d9a9733def0eee7562d9","impliedFormat":1},{"version":"13283350547389802aa35d9f2188effaeac805499169a06ef5cd77ce2a0bd63f","impliedFormat":1},{"version":"ce791f6ea807560f08065d1af6014581eeb54a05abd73294777a281b6dfd73c2","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"49f95e989b4632c6c2a578cc0078ee19a5831832d79cc59abecf5160ea71abad","impliedFormat":1},{"version":"9666533332f26e8995e4d6fe472bdeec9f15d405693723e6497bf94120c566c8","impliedFormat":1},{"version":"ce0df82a9ae6f914ba08409d4d883983cc08e6d59eb2df02d8e4d68309e7848b","impliedFormat":1},{"version":"796273b2edc72e78a04e86d7c58ae94d370ab93a0ddf40b1aa85a37a1c29ecd7","impliedFormat":1},{"version":"5df15a69187d737d6d8d066e189ae4f97e41f4d53712a46b2710ff9f8563ec9f","impliedFormat":1},{"version":"e17cd049a1448de4944800399daa4a64c5db8657cc9be7ef46be66e2a2cd0e7c","impliedFormat":1},{"version":"43fa6ea8714e18adc312b30450b13562949ba2f205a1972a459180fa54471018","impliedFormat":1},{"version":"6e89c2c177347d90916bad67714d0fb473f7e37fb3ce912f4ed521fe2892cd0d","impliedFormat":1},{"version":"43ba4f2fa8c698f5c304d21a3ef596741e8e85a810b7c1f9b692653791d8d97a","impliedFormat":1},{"version":"4d4927cbee21750904af7acf940c5e3c491b4d5ebc676530211e389dd375607a","impliedFormat":1},{"version":"72105519d0390262cf0abe84cf41c926ade0ff475d35eb21307b2f94de985778","impliedFormat":1},{"version":"8a97e578a9bc40eb4f1b0ca78f476f2e9154ecbbfd5567ee72943bab37fc156a","impliedFormat":1},{"version":"c857e0aae3f5f444abd791ec81206020fbcc1223e187316677e026d1c1d6fe08","impliedFormat":1},{"version":"ccf6dd45b708fb74ba9ed0f2478d4eb9195c9dfef0ff83a6092fa3cf2ff53b4f","impliedFormat":1},{"version":"2d7db1d73456e8c5075387d4240c29a2a900847f9c1bff106a2e490da8fbd457","impliedFormat":1},{"version":"2b15c805f48e4e970f8ec0b1915f22d13ca6212375e8987663e2ef5f0205e832","impliedFormat":1},{"version":"f22d05663d873ee7a600faf78abb67f3f719d32266803440cf11d5db7ac0cab2","impliedFormat":1},{"version":"d93c544ad20197b3976b0716c6d5cd5994e71165985d31dcab6e1f77feb4b8f2","impliedFormat":1},{"version":"35069c2c417bd7443ae7c7cafd1de02f665bf015479fec998985ffbbf500628c","impliedFormat":1},{"version":"a8b1c79a833ee148251e88a2553d02ce1641d71d2921cce28e79678f3d8b96aa","impliedFormat":1},{"version":"126d4f950d2bba0bd45b3a86c76554d4126c16339e257e6d2fabf8b6bf1ce00c","impliedFormat":1},{"version":"7e0b7f91c5ab6e33f511efc640d36e6f933510b11be24f98836a20a2dc914c2d","impliedFormat":1},{"version":"045b752f44bf9bbdcaffd882424ab0e15cb8d11fa94e1448942e338c8ef19fba","impliedFormat":1},{"version":"2894c56cad581928bb37607810af011764a2f511f575d28c9f4af0f2ef02d1ab","impliedFormat":1},{"version":"0a72186f94215d020cb386f7dca81d7495ab6c17066eb07d0f44a5bf33c1b21a","impliedFormat":1},{"version":"2d3cc2211f352f46ea6b7cf2c751c141ffcdf514d6e7ae7ee20b7b6742da313f","impliedFormat":1},{"version":"c75445151ff8b77d9923191efed7203985b1a9e09eccf4b054e7be864e27923d","impliedFormat":1},{"version":"0aedb02516baf3e66b2c1db9fef50666d6ed257edac0f866ea32f1aa05aa474f","impliedFormat":1},{"version":"fa8a8fbf91ee2a4779496225f0312aac6635b0f21aa09cdafa4283fe32d519c5","affectsGlobalScope":true,"impliedFormat":1},{"version":"0e8aef93d79b000deb6ec336b5645c87de167168e184e84521886f9ecc69a4b5","impliedFormat":1},{"version":"56ccb49443bfb72e5952f7012f0de1a8679f9f75fc93a5c1ac0bafb28725fc5f","impliedFormat":1},{"version":"20fa37b636fdcc1746ea0738f733d0aed17890d1cd7cb1b2f37010222c23f13e","impliedFormat":1},{"version":"d90b9f1520366d713a73bd30c5a9eb0040d0fb6076aff370796bc776fd705943","impliedFormat":1},{"version":"bc03c3c352f689e38c0ddd50c39b1e65d59273991bfc8858a9e3c0ebb79c023b","impliedFormat":1},{"version":"19df3488557c2fc9b4d8f0bac0fd20fb59aa19dec67c81f93813951a81a867f8","affectsGlobalScope":true,"impliedFormat":1},{"version":"b25350193e103ae90423c5418ddb0ad1168dc9c393c9295ef34980b990030617","affectsGlobalScope":true,"impliedFormat":1},{"version":"bef86adb77316505c6b471da1d9b8c9e428867c2566270e8894d4d773a1c4dc2","impliedFormat":1},{"version":"de7052bfee2981443498239a90c04ea5cc07065d5b9bb61b12cb6c84313ad4ef","impliedFormat":1},{"version":"a3e7d932dc9c09daa99141a8e4800fc6c58c625af0d4bbb017773dc36da75426","impliedFormat":1},{"version":"43e96a3d5d1411ab40ba2f61d6a3192e58177bcf3b133a80ad2a16591611726d","impliedFormat":1},{"version":"4a2edd238d9104eac35b60d727f1123de5062f452b70ed8e0366cb36387dfdfd","impliedFormat":1},{"version":"ca921bf56756cb6fe957f6af693a35251b134fb932dc13f3dfff0bb7106f80b4","impliedFormat":1},{"version":"fee92c97f1aa59eb7098a0cc34ff4df7e6b11bae71526aca84359a2575f313d8","impliedFormat":1},{"version":"0bd0297484aacea217d0b76e55452862da3c5d9e33b24430e0719d1161657225","impliedFormat":1},{"version":"2ab6d334bcbf2aff3acfc4fd8c73ecd82b981d3c3aa47b3f3b89281772286904","impliedFormat":1},{"version":"d07cbc787a997d83f7bde3877fec5fb5b12ce8c1b7047eb792996ed9726b4dde","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"4805f6161c2c8cefb8d3b8bd96a080c0fe8dbc9315f6ad2e53238f9a79e528a6","impliedFormat":1},{"version":"b83cb14474fa60c5f3ec660146b97d122f0735627f80d82dd03e8caa39b4388c","impliedFormat":1},{"version":"f374cb24e93e7798c4d9e83ff872fa52d2cdb36306392b840a6ddf46cb925cb6","impliedFormat":1},{"version":"49179c6a23701c642bd99abe30d996919748014848b738d8e85181fc159685ff","impliedFormat":1},{"version":"b73cbf0a72c8800cf8f96a9acfe94f3ad32ca71342a8908b8ae484d61113f647","impliedFormat":1},{"version":"bae6dd176832f6423966647382c0d7ba9e63f8c167522f09a982f086cd4e8b23","impliedFormat":1},{"version":"20865ac316b8893c1a0cc383ccfc1801443fbcc2a7255be166cf90d03fac88c9","impliedFormat":1},{"version":"c9958eb32126a3843deedda8c22fb97024aa5d6dd588b90af2d7f2bfac540f23","impliedFormat":1},{"version":"461d0ad8ae5f2ff981778af912ba71b37a8426a33301daa00f21c6ccb27f8156","impliedFormat":1},{"version":"e927c2c13c4eaf0a7f17e6022eee8519eb29ef42c4c13a31e81a611ab8c95577","impliedFormat":1},{"version":"fcafff163ca5e66d3b87126e756e1b6dfa8c526aa9cd2a2b0a9da837d81bbd72","impliedFormat":1},{"version":"70246ad95ad8a22bdfe806cb5d383a26c0c6e58e7207ab9c431f1cb175aca657","impliedFormat":1},{"version":"f00f3aa5d64ff46e600648b55a79dcd1333458f7a10da2ed594d9f0a44b76d0b","impliedFormat":1},{"version":"772d8d5eb158b6c92412c03228bd9902ccb1457d7a705b8129814a5d1a6308fc","impliedFormat":1},{"version":"45490817629431853543adcb91c0673c25af52a456479588b6486daba34f68bb","impliedFormat":1},{"version":"802e797bcab5663b2c9f63f51bdf67eff7c41bc64c0fd65e6da3e7941359e2f7","impliedFormat":1},{"version":"8b4327413e5af38cd8cb97c59f48c3c866015d5d642f28518e3a891c469f240e","impliedFormat":1},{"version":"8514c62ce38e58457d967e9e73f128eedc1378115f712b9eef7127f7c88f82ae","impliedFormat":1},{"version":"f1289e05358c546a5b664fbb35a27738954ec2cc6eb4137350353099d154fc62","impliedFormat":1},{"version":"4b20fcf10a5413680e39f5666464859fc56b1003e7dfe2405ced82371ebd49b6","impliedFormat":1},{"version":"1d17ba45cfbe77a9c7e0df92f7d95f3eefd49ee23d1104d0548b215be56945ad","impliedFormat":1},{"version":"f7d628893c9fa52ba3ab01bcb5e79191636c4331ee5667ecc6373cbccff8ae12","impliedFormat":1},{"version":"1d879125d1ec570bf04bc1f362fdbe0cb538315c7ac4bcfcdf0c1e9670846aa6","impliedFormat":1},{"version":"e16344db9b8ee59d41abdb3a61e4470955b5712c0ee869fb47112e152aabe142","impliedFormat":1},{"version":"46273e8c29816125d0d0b56ce9a849cc77f60f9a5ba627447501d214466f0ff3","impliedFormat":1},{"version":"d663134457d8d669ae0df34eabd57028bddc04fc444c4bc04bc5215afc91e1f4","impliedFormat":1},{"version":"144bc326e90b894d1ec78a2af3ffb2eb3733f4d96761db0ca0b6239a8285f972","impliedFormat":1},{"version":"3af3584f79c57853028ef9421ec172539e1fe01853296dc05a9d615ade4ffaf6","impliedFormat":1},{"version":"f82579d87701d639ff4e3930a9b24f4ee13ca74221a9a3a792feb47f01881a9c","impliedFormat":1},{"version":"d7e5d5245a8ba34a274717d085174b2c9827722778129b0081fefd341cca8f55","impliedFormat":1},{"version":"d9d32f94056181c31f553b32ce41d0ef75004912e27450738d57efcd2409c324","impliedFormat":1},{"version":"752513f35f6cff294ffe02d6027c41373adf7bfa35e593dbfd53d95c203635ee","impliedFormat":1},{"version":"6c800b281b9e89e69165fd11536195488de3ff53004e55905e6c0059a2d8591e","impliedFormat":1},{"version":"7d4254b4c6c67a29d5e7f65e67d72540480ac2cfb041ca484847f5ae70480b62","impliedFormat":1},{"version":"1a7e2ea171726446850ec72f4d1525d547ff7e86724cc9e7eec509725752a758","impliedFormat":1},{"version":"8c901126d73f09ecdea4785e9a187d1ac4e793e07da308009db04a7283ec2f37","impliedFormat":1},{"version":"db97922b767bd2675fdfa71e08b49c38b7d2c847a1cc4a7274cb77be23b026f1","impliedFormat":1},{"version":"aab290b8e4b7c399f2c09b957666fc95335eb4522b2dd9ead1bf0cb64da6d6ee","impliedFormat":1},{"version":"94fe3281392e1015b22f39535878610b4fa6f1388dc8d78746be3bc4e4bb8950","impliedFormat":1},{"version":"2652448ac55a2010a1f71dd141f828b682298d39728f9871e1cdf8696ef443fd","impliedFormat":1},{"version":"06c25ddfc2242bd06c19f66c9eae4c46d937349a267810f89783680a1d7b5259","impliedFormat":1},{"version":"120599fd965257b1f4d0ff794bc696162832d9d8467224f4665f713a3119078b","impliedFormat":1},{"version":"5433f33b0a20300cca35d2f229a7fc20b0e8477c44be2affeb21cb464af60c76","impliedFormat":1},{"version":"db036c56f79186da50af66511d37d9fe77fa6793381927292d17f81f787bb195","impliedFormat":1},{"version":"bd4131091b773973ca5d2326c60b789ab1f5e02d8843b3587effe6e1ea7c9d86","impliedFormat":1},{"version":"c7f6485931085bf010fbaf46880a9b9ec1a285ad9dc8c695a9e936f5a48f34b4","impliedFormat":1},{"version":"14f6b927888a1112d662877a5966b05ac1bf7ed25d6c84386db4c23c95a5363b","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"0427df5c06fafc5fe126d14b9becd24160a288deff40e838bfbd92a35f8d0d00","impliedFormat":1},{"version":"90c54a02432d04e4246c87736e53a6a83084357acfeeba7a489c5422b22f5c7a","impliedFormat":1},{"version":"49c346823ba6d4b12278c12c977fb3a31c06b9ca719015978cb145eb86da1c61","impliedFormat":1},{"version":"bfac6e50eaa7e73bb66b7e052c38fdc8ccfc8dbde2777648642af33cf349f7f1","impliedFormat":1},{"version":"92f7c1a4da7fbfd67a2228d1687d5c2e1faa0ba865a94d3550a3941d7527a45d","impliedFormat":1},{"version":"f53b120213a9289d9a26f5af90c4c686dd71d91487a0aa5451a38366c70dc64b","impliedFormat":1},{"version":"83fe880c090afe485a5c02262c0b7cdd76a299a50c48d9bde02be8e908fb4ae6","impliedFormat":1},{"version":"0a372c2d12a259da78e21b25974d2878502f14d89c6d16b97bd9c5017ab1bc12","impliedFormat":1},{"version":"57d67b72e06059adc5e9454de26bbfe567d412b962a501d263c75c2db430f40e","impliedFormat":1},{"version":"6511e4503cf74c469c60aafd6589e4d14d5eb0a25f9bf043dcbecdf65f261972","impliedFormat":1},{"version":"ec1ca97598eda26b7a5e6c8053623acbd88e43be7c4d29c77ccd57abc4c43999","impliedFormat":1},{"version":"6e2261cd9836b2c25eecb13940d92c024ebed7f8efe23c4b084145cd3a13b8a6","impliedFormat":1},{"version":"a67b87d0281c97dfc1197ef28dfe397fc2c865ccd41f7e32b53f647184cc7307","impliedFormat":1},{"version":"771ffb773f1ddd562492a6b9aaca648192ac3f056f0e1d997678ff97dbb6bf9b","impliedFormat":1},{"version":"232f70c0cf2b432f3a6e56a8dc3417103eb162292a9fd376d51a3a9ea5fbbf6f","impliedFormat":1},{"version":"a47e6d954d22dd9ebb802e7e431b560ed7c581e79fb885e44dc92ed4f60d4c07","impliedFormat":1},{"version":"f019e57d2491c159d47a107fd90219a1734bdd2e25cd8d1db3c8fae5c6b414c4","impliedFormat":1},{"version":"8a0e762ceb20c7e72504feef83d709468a70af4abccb304f32d6b9bac1129b2c","impliedFormat":1},{"version":"d1c9bf292a54312888a77bb19dba5e2503ad803f5393beafd45d78d2f4fe9b48","impliedFormat":1},{"version":"9252d498a77517aab5d8d4b5eb9d71e4b225bbc7123df9713e08181de63180f6","impliedFormat":1},{"version":"cb8d8ef7b9ce8ed3e6f1c814fcbf3f90dab0cb8863079236784fc350746e27c4","impliedFormat":1},{"version":"35e6379c3f7cb27b111ad4c1aa69538fd8e788ab737b8ff7596a1b40e96f4f90","impliedFormat":1},{"version":"1fffe726740f9787f15b532e1dc870af3cd964dbe29e191e76121aa3dd8693f2","impliedFormat":1},{"version":"3be035da7bee86b4c3abf392e0edaa44fc6e45092995eefe36b39118c8a84068","affectsGlobalScope":true,"impliedFormat":1},{"version":"8f828825d077c2fa0ea606649faeb122749273a353daab23924fe674e98ba44c","impliedFormat":1},{"version":"2896c2e673a5d3bd9b4246811f79486a073cbb03950c3d252fba10003c57411a","impliedFormat":1},{"version":"616775f16134fa9d01fc677ad3f76e68c051a056c22ab552c64cc281a9686790","impliedFormat":1},{"version":"65c24a8baa2cca1de069a0ba9fba82a173690f52d7e2d0f1f7542d59d5eb4db0","impliedFormat":1},{"version":"f9fe6af238339a0e5f7563acee3178f51db37f32a2e7c09f85273098cee7ec49","impliedFormat":1},{"version":"407a06ba04eede4074eec470ecba2784cbb3bf4e7de56833b097dd90a2aa0651","impliedFormat":1},{"version":"77e71242e71ebf8528c5802993697878f0533db8f2299b4d36aa015bae08a79c","impliedFormat":1},{"version":"98a787be42bd92f8c2a37d7df5f13e5992da0d967fab794adbb7ee18370f9849","impliedFormat":1},{"version":"5c96bad5f78466785cdad664c056e9e2802d5482ca5f862ed19ba34ffbb7b3a4","impliedFormat":1},{"version":"81d8603ac527e75cfec72bb9391228b58f161c2b33514a9d814c7f3ebd3ef466","impliedFormat":1},{"version":"5f3dc10ae646f375776b4e028d2bed039a93eebbba105694d8b910feebbe8b9c","impliedFormat":1},{"version":"bb0cd7862b72f5eba39909c9889d566e198fcaddf7207c16737d0c2246112678","impliedFormat":1},{"version":"4545c1a1ceca170d5d83452dd7c4994644c35cf676a671412601689d9a62da35","impliedFormat":1},{"version":"320f4091e33548b554d2214ce5fc31c96631b513dffa806e2e3a60766c8c49d9","impliedFormat":1},{"version":"a2d648d333cf67b9aeac5d81a1a379d563a8ffa91ddd61c6179f68de724260ff","impliedFormat":1},{"version":"d90d5f524de38889d1e1dbc2aeef00060d779f8688c02766ddb9ca195e4a713d","impliedFormat":1},{"version":"a3f41ed1b4f2fc3049394b945a68ae4fdefd49fa1739c32f149d32c0545d67f5","impliedFormat":1},{"version":"bad68fd0401eb90fe7da408565c8aee9c7a7021c2577aec92fa1382e8876071a","impliedFormat":1},{"version":"47699512e6d8bebf7be488182427189f999affe3addc1c87c882d36b7f2d0b0e","impliedFormat":1},{"version":"fec01479923e169fb52bd4f668dbeef1d7a7ea6e6d491e15617b46f2cacfa37d","impliedFormat":1},{"version":"8a8fb3097ba52f0ae6530ec6ab34e43e316506eb1d9aa29420a4b1e92a81442d","impliedFormat":1},{"version":"44e09c831fefb6fe59b8e65ad8f68a7ecc0e708d152cfcbe7ba6d6080c31c61e","impliedFormat":1},{"version":"1c0a98de1323051010ce5b958ad47bc1c007f7921973123c999300e2b7b0ecc0","impliedFormat":1},{"version":"4655709c9cb3fd6db2b866cab7c418c40ed9533ce8ea4b66b5f17ec2feea46a9","impliedFormat":1},{"version":"87affad8e2243635d3a191fa72ef896842748d812e973b7510a55c6200b3c2a4","impliedFormat":1},{"version":"ad036a85efcd9e5b4f7dd5c1a7362c8478f9a3b6c3554654ca24a29aa850a9c5","impliedFormat":1},{"version":"fedebeae32c5cdd1a85b4e0504a01996e4a8adf3dfa72876920d3dd6e42978e7","impliedFormat":1},{"version":"3eecb25bb467a948c04874d70452b14ae7edb707660aac17dc053e42f2088b00","impliedFormat":1},{"version":"cdf21eee8007e339b1b9945abf4a7b44930b1d695cc528459e68a3adc39a622e","impliedFormat":1},{"version":"330896c1a2b9693edd617be24fbf9e5895d6e18c7955d6c08f028f272b37314d","impliedFormat":1},{"version":"1d9c0a9a6df4e8f29dc84c25c5aa0bb1da5456ebede7a03e03df08bb8b27bae6","impliedFormat":1},{"version":"84380af21da938a567c65ef95aefb5354f676368ee1a1cbb4cae81604a4c7d17","impliedFormat":1},{"version":"1af3e1f2a5d1332e136f8b0b95c0e6c0a02aaabd5092b36b64f3042a03debf28","impliedFormat":1},{"version":"30d8da250766efa99490fc02801047c2c6d72dd0da1bba6581c7e80d1d8842a4","impliedFormat":1},{"version":"03566202f5553bd2d9de22dfab0c61aa163cabb64f0223c08431fb3fc8f70280","impliedFormat":1},{"version":"5f0292a40df210ab94b9fb44c8b775c51e96777e14e073900e392b295ca1061b","impliedFormat":1},{"version":"bc9ee0192f056b3d5527bcd78dc3f9e527a9ba2bdc0a2c296fbc9027147df4b2","impliedFormat":1},{"version":"8627ad129bcf56e82adff0ab5951627c993937aa99f5949c33240d690088b803","impliedFormat":1},{"version":"1de80059b8078ea5749941c9f863aa970b4735bdbb003be4925c853a8b6b4450","impliedFormat":1},{"version":"1d079c37fa53e3c21ed3fa214a27507bda9991f2a41458705b19ed8c2b61173d","impliedFormat":1},{"version":"5bf5c7a44e779790d1eb54c234b668b15e34affa95e78eada73e5757f61ed76a","impliedFormat":1},{"version":"5835a6e0d7cd2738e56b671af0e561e7c1b4fb77751383672f4b009f4e161d70","impliedFormat":1},{"version":"5c634644d45a1b6bc7b05e71e05e52ec04f3d73d9ac85d5927f647a5f965181a","impliedFormat":1},{"version":"4b7f74b772140395e7af67c4841be1ab867c11b3b82a51b1aeb692822b76c872","impliedFormat":1},{"version":"27be6622e2922a1b412eb057faa854831b95db9db5035c3f6d4b677b902ab3b7","impliedFormat":1},{"version":"a68d4b3182e8d776cdede7ac9630c209a7bfbb59191f99a52479151816ef9f9e","impliedFormat":99},{"version":"39644b343e4e3d748344af8182111e3bbc594930fff0170256567e13bbdbebb0","impliedFormat":99},{"version":"ed7fd5160b47b0de3b1571c5c5578e8e7e3314e33ae0b8ea85a895774ee64749","impliedFormat":99},{"version":"63a7595a5015e65262557f883463f934904959da563b4f788306f699411e9bac","impliedFormat":1},{"version":"ecbaf0da125974be39c0aac869e403f72f033a4e7fd0d8cd821a8349b4159628","impliedFormat":1},{"version":"4ba137d6553965703b6b55fd2000b4e07ba365f8caeb0359162ad7247f9707a6","impliedFormat":1},{"version":"ceec3c81b2d81f5e3b855d9367c1d4c664ab5046dff8fd56552df015b7ccbe8f","affectsGlobalScope":true,"impliedFormat":1},{"version":"8fac4a15690b27612d8474fb2fc7cc00388df52d169791b78d1a3645d60b4c8b","affectsGlobalScope":true,"impliedFormat":1},{"version":"064ac1c2ac4b2867c2ceaa74bbdce0cb6a4c16e7c31a6497097159c18f74aa7c","impliedFormat":1},{"version":"3dc14e1ab45e497e5d5e4295271d54ff689aeae00b4277979fdd10fa563540ae","impliedFormat":1},{"version":"1d63055b690a582006435ddd3aa9c03aac16a696fac77ce2ed808f3e5a06efab","impliedFormat":1},{"version":"b789bf89eb19c777ed1e956dbad0925ca795701552d22e68fd130a032008b9f9","impliedFormat":1},"85ae5aee75f011967cf2d25cbc342f62d69314e9d925f7f4aa3456fc2cffcca6",{"version":"0bd283852c5f9c47677ad35c0359b0825c1c39b3268ea1ae86156f9574acfd5a","signature":"435a1e418e8338be3f39614b96b81a9aa2700bc8c27bc6b98f064ff9ce17c363"},{"version":"26b7d0cd4b41ab557ef9e3bfeec42dcf24252843633e3d29f38d2c0b13aaa528","impliedFormat":1},{"version":"b464a45c821b4ae4d147335d0c341c164520492197b5a8143b20c010c41e8700","signature":"b6822da30ff8e02201bdae4150c9e7bb229a89b50ee466336aeac6d98e0c2462"},{"version":"04471dc55f802c29791cc75edda8c4dd2a121f71c2401059da61eff83099e8ab","impliedFormat":99},{"version":"5c54a34e3d91727f7ae840bfe4d5d1c9a2f93c54cb7b6063d06ee4a6c3322656","impliedFormat":99},{"version":"db4da53b03596668cf6cc9484834e5de3833b9e7e64620cf08399fe069cd398d","impliedFormat":99},{"version":"ac7c28f153820c10850457994db1462d8c8e462f253b828ad942a979f726f2f9","impliedFormat":99},{"version":"f9b028d3c3891dd817e24d53102132b8f696269309605e6ed4f0db2c113bbd82","impliedFormat":99},{"version":"fb7c8d90e52e2884509166f96f3d591020c7b7977ab473b746954b0c8d100960","impliedFormat":99},{"version":"0bff51d6ed0c9093f6955b9d8258ce152ddb273359d50a897d8baabcb34de2c4","impliedFormat":99},{"version":"ef13c73d6157a32933c612d476c1524dd674cf5b9a88571d7d6a0d147544d529","impliedFormat":99},{"version":"13918e2b81c4288695f9b1f3dcc2468caf0f848d5c1f3dc00071c619d34ff63a","impliedFormat":99},{"version":"120a80aa556732f684db3ed61aeff1d6671e1655bd6cba0aa88b22b88ac9a6b1","affectsGlobalScope":true,"impliedFormat":99},{"version":"a7ca8df4f2931bef2aa4118078584d84a0b16539598eaadf7dce9104dfaa381c","impliedFormat":1},{"version":"10073cdcf56982064c5337787cc59b79586131e1b28c106ede5bff362f912b70","impliedFormat":99},{"version":"72950913f4900b680f44d8cab6dd1ea0311698fc1eefb014eb9cdfc37ac4a734","impliedFormat":1},{"version":"151ff381ef9ff8da2da9b9663ebf657eac35c4c9a19183420c05728f31a6761d","impliedFormat":1},{"version":"ee70b8037ecdf0de6c04f35277f253663a536d7e38f1539d270e4e916d225a3f","affectsGlobalScope":true,"impliedFormat":1},{"version":"a660aa95476042d3fdcc1343cf6bb8fdf24772d31712b1db321c5a4dcc325434","impliedFormat":1},{"version":"36977c14a7f7bfc8c0426ae4343875689949fb699f3f84ecbe5b300ebf9a2c55","impliedFormat":1},{"version":"ff0a83c9a0489a627e264ffcb63f2264b935b20a502afa3a018848139e3d8575","impliedFormat":99},{"version":"161c8e0690c46021506e32fda85956d785b70f309ae97011fd27374c065cac9b","affectsGlobalScope":true,"impliedFormat":1},{"version":"f582b0fcbf1eea9b318ab92fb89ea9ab2ebb84f9b60af89328a91155e1afce72","impliedFormat":1},{"version":"402e5c534fb2b85fa771170595db3ac0dd532112c8fa44fc23f233bc6967488b","impliedFormat":1},{"version":"7965dc3c7648e2a7a586d11781cabb43d4859920716bc2fdc523da912b06570d","impliedFormat":1},{"version":"90c2bd9a3e72fe08b8fa5982e78cb8dc855a1157b26e11e37a793283c52bf64b","impliedFormat":1},{"version":"a8122fe390a2a987079e06c573b1471296114677923c1c094c24a53ddd7344a2","impliedFormat":1},{"version":"70c2cb19c0c42061a39351156653aa0cf5ba1ecdc8a07424dd38e3a1f1e3c7f4","impliedFormat":1},{"version":"a8fb10fd8c7bc7d9b8f546d4d186d1027f8a9002a639bec689b5000dab68e35c","impliedFormat":1},{"version":"c9b467ea59b86bd27714a879b9ad43c16f186012a26d0f7110b1322025ceaa83","impliedFormat":1},{"version":"57ea19c2e6ba094d8087c721bac30ff1c681081dbd8b167ac068590ef633e7a5","impliedFormat":1},{"version":"cba81ec9ae7bc31a4dc56f33c054131e037649d6b9a2cfa245124c67e23e4721","impliedFormat":1},{"version":"ad193f61ba708e01218496f093c23626aa3808c296844a99189be7108a9c8343","impliedFormat":1},{"version":"a0544b3c8b70b2f319a99ea380b55ab5394ede9188cdee452a5d0ce264f258b2","impliedFormat":1},{"version":"8c654c17c334c7c168c1c36e5336896dc2c892de940886c1639bebd9fc7b9be4","impliedFormat":1},{"version":"6a4da742485d5c2eb6bcb322ae96993999ffecbd5660b0219a5f5678d8225bb0","impliedFormat":1},{"version":"c65ca21d7002bdb431f9ab3c7a6e765a489aa5196e7e0ef00aed55b1294df599","impliedFormat":1},{"version":"c8fc655c2c4bafc155ceee01c84ab3d6c03192ced5d3f2de82e20f3d1bd7f9fa","impliedFormat":1},{"version":"be5a7ff3b47f7e553565e9483bdcadb0ca2040ac9e5ec7b81c7e115a81059882","impliedFormat":1},{"version":"1a93f36ecdb60a95e3a3621b561763e2952da81962fae217ab5441ac1d77ffc5","impliedFormat":1},{"version":"2a771d907aebf9391ac1f50e4ad37952943515eeea0dcc7e78aa08f508294668","impliedFormat":1},{"version":"0146fd6262c3fd3da51cb0254bb6b9a4e42931eb2f56329edd4c199cb9aaf804","impliedFormat":1},{"version":"183f480885db5caa5a8acb833c2be04f98056bdcc5fb29e969ff86e07efe57ab","impliedFormat":99},{"version":"960bd764c62ac43edc24eaa2af958a4b4f1fa5d27df5237e176d0143b36a39c6","affectsGlobalScope":true,"impliedFormat":1},{"version":"3fd8a5aefd8c3feb3936ca66f5aa89dff7bf6e6537b4158dbd0f6e0d65ed3b9e","impliedFormat":1},{"version":"a18642ddf216f162052a16cba0944892c4c4c977d3306a87cb673d46abbb0cbf","impliedFormat":1},{"version":"509f8efdfc5f9f6b52284170e8d7413552f02d79518d1db691ee15acc0088676","impliedFormat":1},{"version":"4ec16d7a4e366c06a4573d299e15fe6207fc080f41beac5da06f4af33ea9761e","impliedFormat":1},{"version":"59f8dc89b9e724a6a667f52cdf4b90b6816ae6c9842ce176d38fcc973669009e","affectsGlobalScope":true,"impliedFormat":1},{"version":"e4af494f7a14b226bbe732e9c130d8811f8c7025911d7c58dd97121a85519715","impliedFormat":1},{"version":"47416e41b1af81e53e8c3cc5bf909d47ff632a7b6eddfe7ff43d187b4dcca047","impliedFormat":99},{"version":"45cec9a1ba6549060552eead8959d47226048e0b71c7d0702ae58b7e16a28912","impliedFormat":99},{"version":"6907b09850f86610e7a528348c15484c1e1c09a18a9c1e98861399dfe4b18b46","impliedFormat":99},{"version":"12deea8eaa7a4fc1a2908e67da99831e5c5a6b46ad4f4f948fd4759314ea2b80","impliedFormat":99},{"version":"f0a8b376568a18f9a4976ecb0855187672b16b96c4df1c183a7e52dc1b5d98e8","impliedFormat":99},{"version":"8124828a11be7db984fcdab052fd4ff756b18edcfa8d71118b55388176210923","impliedFormat":99},{"version":"092944a8c05f9b96579161e88c6f211d5304a76bd2c47f8d4c30053269146bc8","impliedFormat":99},{"version":"b34b5f6b506abb206b1ea73c6a332b9ee9c8c98be0f6d17cdbda9430ecc1efab","impliedFormat":99},{"version":"75d4c746c3d16af0df61e7b0afe9606475a23335d9f34fcc525d388c21e9058b","impliedFormat":99},{"version":"fa959bf357232201c32566f45d97e70538c75a093c940af594865d12f31d4912","impliedFormat":99},{"version":"d2c52abd76259fc39a30dfae70a2e5ce77fd23144457a7ff1b64b03de6e3aec7","impliedFormat":99},{"version":"e6233e1c976265e85aa8ad76c3881febe6264cb06ae3136f0257e1eab4a6cc5a","impliedFormat":99},{"version":"f73e2335e568014e279927321770da6fe26facd4ac96cdc22a56687f1ecbb58e","impliedFormat":99},{"version":"317878f156f976d487e21fd1d58ad0461ee0a09185d5b0a43eedf2a56eb7e4ea","impliedFormat":99},{"version":"324ac98294dab54fbd580c7d0e707d94506d7b2c3d5efe981a8495f02cf9ad96","impliedFormat":99},{"version":"9ec72eb493ff209b470467e24264116b6a8616484bca438091433a545dfba17e","impliedFormat":99},{"version":"d6ee22aba183d5fc0c7b8617f77ee82ecadc2c14359cc51271c135e23f6ed51f","impliedFormat":99},{"version":"49747416f08b3ba50500a215e7a55d75268b84e31e896a40313c8053e8dec908","impliedFormat":99},{"version":"81e634f1c5e1ca309e7e3dc69e2732eea932ef07b8b34517d452e5a3e9a36fa3","impliedFormat":99},{"version":"34f39f75f2b5aa9c84a9f8157abbf8322e6831430e402badeaf58dd284f9b9a6","impliedFormat":99},{"version":"427fe2004642504828c1476d0af4270e6ad4db6de78c0b5da3e4c5ca95052a99","impliedFormat":1},{"version":"2eeffcee5c1661ddca53353929558037b8cf305ffb86a803512982f99bcab50d","impliedFormat":99},{"version":"9afb4cb864d297e4092a79ee2871b5d3143ea14153f62ef0bb04ede25f432030","affectsGlobalScope":true,"impliedFormat":99},{"version":"891694d3694abd66f0b8872997b85fd8e52bc51632ce0f8128c96962b443189f","impliedFormat":99},{"version":"69bf2422313487956e4dacf049f30cb91b34968912058d244cb19e4baa24da97","impliedFormat":99},{"version":"971a2c327ff166c770c5fb35699575ba2d13bba1f6d2757309c9be4b30036c8e","impliedFormat":99},{"version":"4f45e8effab83434a78d17123b01124259fbd1e335732135c213955d85222234","impliedFormat":99},{"version":"7bd51996fb7717941cbe094b05adc0d80b9503b350a77b789bbb0fc786f28053","impliedFormat":99},{"version":"b62006bbc815fe8190c7aee262aad6bff993e3f9ade70d7057dfceab6de79d2f","impliedFormat":99},{"version":"13497c0d73306e27f70634c424cd2f3b472187164f36140b504b3756b0ff476d","impliedFormat":99},{"version":"a23a08b626aa4d4a1924957bd8c4d38a7ffc032e21407bbd2c97413e1d8c3dbd","impliedFormat":99},{"version":"c320fe76361c53cad266b46986aac4e68d644acda1629f64be29c95534463d28","impliedFormat":99},{"version":"7bbff6783e96c691a41a7cf12dd5486b8166a01b0c57d071dbcfca55c9525ec4","impliedFormat":99},{"version":"556ccd493ec36c7d7cb130d51be66e147b91cc1415be383d71da0f1e49f742a9","impliedFormat":1},{"version":"b6d03c9cfe2cf0ba4c673c209fcd7c46c815b2619fd2aad59fc4229aaef2ed43","impliedFormat":1},{"version":"95aba78013d782537cc5e23868e736bec5d377b918990e28ed56110e3ae8b958","impliedFormat":1},{"version":"670a76db379b27c8ff42f1ba927828a22862e2ab0b0908e38b671f0e912cc5ed","impliedFormat":1},{"version":"13b77ab19ef7aadd86a1e54f2f08ea23a6d74e102909e3c00d31f231ed040f62","impliedFormat":1},{"version":"069bebfee29864e3955378107e243508b163e77ab10de6a5ee03ae06939f0bb9","impliedFormat":1},{"version":"26e0ffceb2198feb1ef460d5d14111c69ad07d44c5a67fd4bfeb74c969aa9afb","impliedFormat":99},{"version":"00edc702aac9916e62c9697557358bfc3264c8f95283cd2dfe7313c292f554ab","signature":"4b96dd19fd2949d28ce80e913412b0026dc421e5bf6c31d87c7b5eb11b5753b4"},{"version":"8a67a70c5776c96249752c3586e39908641761f663918e6bfb0dca2dd9bd4b04","signature":"d3bb46ba5321b57e9f6e971b6e9086444143eb287921c7ca45f3238c44937d48"},{"version":"bf7a2d0f6d9e72d59044079d61000c38da50328ccdff28c47528a1a139c610ec","impliedFormat":99},{"version":"e58c0b5226aff07b63be6ac6e1bec9d55bc3d2bda3b11b9b68cccea8c24ae839","affectsGlobalScope":true,"impliedFormat":99},{"version":"5a88655bf852c8cc007d6bc874ab61d1d63fba97063020458177173c454e9b4a","impliedFormat":99},{"version":"7e4dfae2da12ec71ffd9f55f4641a6e05610ce0d6784838659490e259e4eb13c","impliedFormat":99},{"version":"c30a41267fc04c6518b17e55dcb2b810f267af4314b0b6d7df1c33a76ce1b330","impliedFormat":1},{"version":"72422d0bac4076912385d0c10911b82e4694fc106e2d70added091f88f0824ba","impliedFormat":1},{"version":"da251b82c25bee1d93f9fd80c5a61d945da4f708ca21285541d7aff83ecb8200","impliedFormat":1},{"version":"64db14db2bf37ac089766fdb3c7e1160fabc10e9929bc2deeede7237e4419fc8","impliedFormat":1},{"version":"98b94085c9f78eba36d3d2314affe973e8994f99864b8708122750788825c771","impliedFormat":1},{"version":"13573a613314e40482386fe9c7934f9d86f3e06f19b840466c75391fb833b99b","impliedFormat":99},{"version":"c57b441e0c0a9cbdfa7d850dae1f8a387d6f81cbffbc3cd0465d530084c2417d","impliedFormat":99},{"version":"8658354b90861a76abc7b3c04ece2124295c7da0cc4c4d31c2c78d8607188d03","impliedFormat":1},{"version":"4acbc7165a8d54738ff62b51414e772c08fe78434e524e6d8770180d3ba2925f","signature":"512960c0e955a2324b34354dac25e3e4d431a1af4cd33077935eda5e95c8b7e1"},{"version":"946559ebc0469d5bc5cc0d466279241d43dd0046c1d4fe09773748af2a6fe687","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"2ce4b6c3c37463bdc5481781b43503e6885182b0f1f0a07e94804d29918dccd8","impliedFormat":99},{"version":"19ca0b242512d24542e3ce986dbe7216b9a79552213bda7af75dda4e15d1cb97","impliedFormat":99},{"version":"c1a2e05eb6d7ca8d7e4a7f4c93ccf0c2857e842a64c98eaee4d85841ee9855e6","impliedFormat":1},{"version":"835fb2909ce458740fb4a49fc61709896c6864f5ce3db7f0a88f06c720d74d02","impliedFormat":1},{"version":"6e5857f38aa297a859cab4ec891408659218a5a2610cd317b6dcbef9979459cc","impliedFormat":1},{"version":"ead8e39c2e11891f286b06ae2aa71f208b1802661fcdb2425cffa4f494a68854","impliedFormat":1},{"version":"82919acbb38870fcf5786ec1292f0f5afe490f9b3060123e48675831bd947192","impliedFormat":1},{"version":"e222701788ec77bd57c28facbbd142eadf5c749a74d586bc2f317db7e33544b1","impliedFormat":1},{"version":"09154713fae0ed7befacdad783e5bd1970c06fc41a5f866f7f933b96312ce764","impliedFormat":1},{"version":"8d67b13da77316a8a2fabc21d340866ddf8a4b99e76a6c951cc45189142df652","impliedFormat":1},{"version":"a91c8d28d10fee7fe717ddf3743f287b68770c813c98f796b6e38d5d164bd459","impliedFormat":1},{"version":"68add36d9632bc096d7245d24d6b0b8ad5f125183016102a3dad4c9c2438ccb0","impliedFormat":1},{"version":"3a819c2928ee06bbcc84e2797fd3558ae2ebb7e0ed8d87f71732fb2e2acc87b4","impliedFormat":1},{"version":"f6f827cd43e92685f194002d6b52a9408309cda1cec46fb7ca8489a95cbd2fd4","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"a270a1a893d1aee5a3c1c8c276cd2778aa970a2741ee2ccf29cc3210d7da80f5","impliedFormat":1},{"version":"add0ce7b77ba5b308492fa68f77f24d1ed1d9148534bdf05ac17c30763fc1a79","impliedFormat":1},{"version":"8926594ee895917e90701d8cbb5fdf77fc238b266ac540f929c7253f8ad6233d","impliedFormat":1},{"version":"2f67911e4bf4e0717dc2ded248ce2d5e4398d945ee13889a6852c1233ea41508","impliedFormat":1},{"version":"d8430c275b0f59417ea8e173cfb888a4477b430ec35b595bf734f3ec7a7d729f","impliedFormat":1},{"version":"69364df1c776372d7df1fb46a6cb3a6bf7f55e700f533a104e3f9d70a32bec18","impliedFormat":1},{"version":"6042774c61ece4ba77b3bf375f15942eb054675b7957882a00c22c0e4fe5865c","impliedFormat":1},{"version":"5a3bd57ed7a9d9afef74c75f77fce79ba3c786401af9810cdf45907c4e93f30e","impliedFormat":1},{"version":"ed8763205f02fb65e84eff7432155258df7f93b7d938f01785cb447d043d53f3","impliedFormat":1},{"version":"30db853bb2e60170ba11e39ab48bacecb32d06d4def89eedf17e58ebab762a65","impliedFormat":1},{"version":"e27451b24234dfed45f6cf22112a04955183a99c42a2691fb4936d63cfe42761","impliedFormat":1},{"version":"2316301dd223d31962d917999acf8e543e0119c5d24ec984c9f22cb23247160c","impliedFormat":1},{"version":"58d65a2803c3b6629b0e18c8bf1bc883a686fcf0333230dd0151ab6e85b74307","impliedFormat":1},{"version":"e818471014c77c103330aee11f00a7a00b37b35500b53ea6f337aefacd6174c9","impliedFormat":1},{"version":"d4a5b1d2ff02c37643e18db302488cd64c342b00e2786e65caac4e12bda9219b","impliedFormat":1},{"version":"29f823cbe0166e10e7176a94afe609a24b9e5af3858628c541ff8ce1727023cd","impliedFormat":1},{"version":"469121354c88f9bcc57322407eb5d0d5b8a96cfeb9192494e8b46b2688126e2a","impliedFormat":99},{"version":"ef52b983c108a10854a26ee467a86c9b5f87024563d48defe3b0e8f4a1af4a51","impliedFormat":99},{"version":"a380cd0a371b5b344c2f679a932593f02445571f9de0014bdf013dddf2a77376","impliedFormat":99},{"version":"dbbcd13911daafc1554acc17dad18ab92f91b5b8f084c6c4370cb8c60520c3b6","impliedFormat":99},{"version":"9c06dd902f40b340b062fff14d3ef579b67c65007fbaba56497422a21e2e5911","impliedFormat":99},{"version":"b026daf5c00c8f2abdb49008322a7d51fbadcd7b200a99ee7a4452dbd40f0420","impliedFormat":99},{"version":"e130a73d7e1e34953b1964c17c218fd14fccd1df6f15f111352b0d53291311bb","impliedFormat":99},{"version":"4ddecad872558e2b3df434ef0b01114d245e7a18a86afa6e7b5c68e75f9b8f76","impliedFormat":99},{"version":"924e513606180beab310a21ece1fe85dc3f1cc159bd894861b01bbe46764d7ca","impliedFormat":99},{"version":"270ceb915b1304c042b6799de28ff212cfa4baf06900d3a8bc4b79f62f00c8a7","impliedFormat":99},{"version":"1b3174ea6e3b4ae157c88eb28bf8e6d67f044edc9c552daf5488628fd8e5be97","impliedFormat":99},{"version":"6564db88fa4cf3bae5c8e0de01c701c6228eaeef1118b4ad6a49a8aaf8556350","impliedFormat":99},{"version":"9c5a4a21ed5686b2ea080557488b966c3aeea641ef1aa8975a10e5fc59dd569f","impliedFormat":99},{"version":"5585ed538922e2e58655218652dcb262f08afa902f26f490cdec4967887ac31a","impliedFormat":99},{"version":"b46de7238d9d2243b27a21797e4772ba91465caae9c31f21dc43748dc9de9cd0","impliedFormat":99},{"version":"625fdbce788630c62f793cb6c80e0072ce0b8bf1d4d0a9922430671164371e0b","impliedFormat":99},{"version":"b6790300d245377671c085e76e9ef359b3cbba6821b913d6ce6b2739d00b9fb1","impliedFormat":99},{"version":"c92c9dc7415bf7969931ac5339f21c65687909b32d05ac89789b411372e52991","impliedFormat":99},{"version":"a36c717362d06d76e7332d9c1d2744c2c5e4b4a5da6218ef7b4a299a62d23a6d","impliedFormat":99},{"version":"a61f8455fd21cec75a8288cd761f5bcc72441848841eb64aa09569e9d8929ff0","impliedFormat":99},{"version":"b135437aa8444e851e10cb514b4a73141813e0adcfcc06d702df6aa0fd922587","impliedFormat":99},{"version":"cc82fa360f22d73b4cc7f446d08ad52b11f5aba66aa04b1ed8feb11a509e8aff","impliedFormat":99},{"version":"466e7296272b827c55b53a7858502de733733558966e2e3a7cc78274e930210a","impliedFormat":99},{"version":"364a5c527037fdd7d494ab0a97f510d3ceda30b8a4bc598b490c135f959ff3c6","impliedFormat":99},{"version":"f198de1cd91b94acc7f4d72cbccc11abadb1570bedc4ede174810e1f6985e06e","impliedFormat":99},{"version":"83d2dab980f2d1a2fe333f0001de8f42c831a438159d47b77c686ae405891b7f","impliedFormat":99},{"version":"ca369bcbdafc423d1a9dccd69de98044534900ff8236d2dd970b52438afb5355","impliedFormat":99},{"version":"5b90280e84e8eba347caaefc18210de3ce6ac176f5e82705a28e7f497dcc8689","impliedFormat":99},{"version":"34e2f00467aa6f46c1d7955f8d57bffb48ccc6ad2bbc847d0b1ccef1d55a9c3c","impliedFormat":99},{"version":"f09dfae4ff5f84c1341d74208e9b442659c32d039e9d27c09f79a203755e953d","impliedFormat":99},{"version":"e7878d8cd1fd0d0f1c55dcd8f5539f4c22e44993852f588dd194bd666b230727","impliedFormat":99},{"version":"0d22b18cb407b03331edf3413b93e568da71130c906fd69911090df2abf55414","impliedFormat":99},{"version":"5695f9865a00f0a28f5da4fcc015bcc4f0810a52fc809b878b6a1bacf940de3a","impliedFormat":99},{"version":"131f084b3df26375be902d20448ba60dc3595a1c56b63ad88af92a7333dd2c17","impliedFormat":99},{"version":"bdd14f07b4eca0b4b5203b85b8dbc4d084c749fa590bee5ea613e1641dcd3b29","impliedFormat":99},{"version":"df09e59ace0cf7fd8e3c767b0b8f3d5b2212bd40d4e9dbf49a388526ead5e545","impliedFormat":99},{"version":"03fe713f6d3e69f47d4871545b2cd40e1f714b11e3945f6ab1e05361cad19192","impliedFormat":99},{"version":"25ea3ca113eb33c517ace8bd6555e8caf1c99d34dea7b3a48b074bdc5e7cc735","impliedFormat":99},{"version":"d5f83721da8ee61cd1620f0e4abc9d60453b4ef0b25945172bbd478ff6e3adcb","impliedFormat":99},{"version":"597536b4c8e7e309dd823f61206ff169ca90a3d68245343a5226a8d20f7a9ffd","impliedFormat":99},{"version":"cfed3c4118baa2ae69ec0da47b5fa722c49e5915c1cb7ffa8d5b53b678b641ca","impliedFormat":99},{"version":"3b5f9ed01add914f4bf2220544cdd4099583c2a72895b2ea495e9284be88b894","impliedFormat":99},{"version":"575425068684056c113b93ec316870eca50195835f04179630997e7b075164d4","impliedFormat":99},{"version":"aa0af7166f48f67765f96dc70c1d7f9f55ae264b96cadf5b6077b2bc0aa2b5dd","impliedFormat":99},{"version":"2fc9c7c6695b151ffd3ed667d6d793c2f656461978e840eff1d1350fc0bb1ebb","impliedFormat":99},{"version":"4d590f0e0b4abaf693f94d08b5c414928f2571aea5ac6efb97e4646e195dac48","impliedFormat":99},{"version":"bf1655c135bd654637f98f934f9a9eb4d6450194ca2f4968b79263608da59fdd","impliedFormat":99},{"version":"1ebe079cc9ed9ec4cd11d02c70f209caf16e9dd8e1e801a36648ce711bb3c404","impliedFormat":99},{"version":"b9a49ec04f7dac4bdcb928894d3c6bfc15a4ffee5f14d4b2bef69069de2b1d25","impliedFormat":99},{"version":"d2554dc921a526fc29600ef66da5d37577ce64557eaceebdb2b6170776051ffd","impliedFormat":99},{"version":"1fffc635777e6b7edc2caf5e8473fd161ba8fe5605ae84b64746a2a34045e6e3","impliedFormat":99},{"version":"f6f35852e407d4c04e578478e743c8101227037abd405ad71564e8430d4e4c1c","impliedFormat":99},{"version":"0e16f517285c960f284ff5367c239c24e20acfd3b3aced00d7842c7cd867898c","impliedFormat":99},{"version":"063929189f06ac3087123f98ce8736eea5c2a4cecbaa46c54b58118608fb8708","impliedFormat":99},{"version":"95e249a5d61382550bbf6341cb31a3114b0c10c232b0fbac97da74f83275dbab","impliedFormat":99},{"version":"34880c694bdb6f266bf484dbc60bd887890ab1c8d6807459fdf93f6ab0b0c792","impliedFormat":99},{"version":"d490c69a03b97298294b4d2159175f2f9b62a7dfcd81efc63ea3505c60fc0ac8","impliedFormat":99},{"version":"c0511c2a0a6ae726a66a0b25336fdc61c632c6c1505eb0bbbe1556055fd06919","impliedFormat":99},{"version":"bbd577f9d34a868d751e14a904401a6a026de322bd0f7cc7d51ecc585b57c6e6","impliedFormat":99},{"version":"e06f1dbc167fd37808d2f36aee8ef3bfae734d13fc4afcd9994072a30099df0b","impliedFormat":99},{"version":"7e0693b9604ff4fd358a2f21db90982fce11a4ff216eeae85e326f108d648d68","impliedFormat":99},{"version":"69d5a40440e664ec9493c61169414208472583f342346fb31dcbebad23c6a780","impliedFormat":99},{"version":"3d1efa91afa616c307864fa93f9e7777672bf90ac79c16936969efbc6629cbc1","impliedFormat":99},{"version":"722d99f854a33867a3397fe397924c0de326741e9d7830876481ccf87643a133","impliedFormat":99},{"version":"6ddebf5efb47d10d48d734f855b5cd13772de6d14b50779a17590afa30fcaefc","impliedFormat":99},{"version":"0c4e55d5ee917d3efca585b9eb138df9eb9cd38ec5a8ab258fc0e4fe8d54abd6","impliedFormat":99},{"version":"a41283ab6303ab1d21729da5723952e1b7d9d1bf379b9cce09132403f6f0f07d","impliedFormat":99},{"version":"1557f6fa35f1fc5d23911982761a7ddc4fbe9322eda575f6dadca8d5515e0cee","impliedFormat":99},{"version":"ded4768515ff723001ca99221ec8a7b751a4f90af8be95c885ec8a21efa548d4","impliedFormat":99},{"version":"86a6b6352a6a47fa8698f68119eb716ea951f541128d108382137e3d85900162","impliedFormat":99},{"version":"b9e6aa9de64cbd004d2c59ad79cff12a5d34406153456b869eae6b1d8f5bbb61","impliedFormat":99},{"version":"b864079910dbf273badc3367d21910e6f8887705defda6d51882084ef5b6ebb5","impliedFormat":99},{"version":"5e1fbca4c7648ff481cd7dda46ca8651239f4898bbed3d5066b8d6db0f60c555","impliedFormat":99},{"version":"0fd72d2cd43f9da04478aa6cbb922c27fda6b4a0ca7235aee8f6a933941bae92","impliedFormat":99},{"version":"28a5fc04797c6992303791a4b79ed99431bf2af90b77842948e3e8bc0f681d97","impliedFormat":99},{"version":"20a397ebeea68a193465caeb8f1b3225c49c6bdc4545a0ca6521fa684ef2fc5b","impliedFormat":99},{"version":"9edb51982e31faae66cef7076aacce409cab4637f0ec6e6851331fc87d9fa872","impliedFormat":99},{"version":"8a954a3b53672645d10a61e617272cd309bd7dc442f914427291ea8a2cb3c599","impliedFormat":99},{"version":"69e56ac933cbb0a62cbed3436a44068445460c3a246ae5b7b70e010dd3d8e0e5","impliedFormat":99},{"version":"dbafd3b17be2ca81493a6d6daf7afb6d04b83dd3b80c556ae5973e9a375aa6ff","impliedFormat":99},{"version":"8ea7264ce539f97f4720250a14695a1f82c3ac33ed66617991438cfb3d41947f","impliedFormat":99},{"version":"abf4fe7ebd8771a5c9d963754ae0c088c159e0e12ff77ed2e48f69d86ed50be5","impliedFormat":99},{"version":"050985cfd782bb62131bdc040cd444f65bbd35ca1b45e3eefde79ef713ddeb1b","impliedFormat":99},{"version":"cd935cd60191b79134684160cf08d5ab555512b7befd5f88b449681f7e037a3e","impliedFormat":99},{"version":"5e61341da5f93b211c8c11f6ca709a2dda33feded2cb3e1481d0b727aed23cd7","impliedFormat":99},{"version":"3df29fc79cceaa80012df2005f745c1b635a41dda0766ddd29ac8e078c4216f8","impliedFormat":99},{"version":"bb8aac29b972b3826d70b106373ed2600bfa8377ddd5672b0b5e256f361acfb9","impliedFormat":99},{"version":"721e984c6181cf2f1587226d11d2265f5bd1450da58e7598845ae15cee0465b4","impliedFormat":99},{"version":"bfa5dd71d432e277bbf3c44b3dd91db853fd833da21f43cc3a0a2dc324b7af47","impliedFormat":99},{"version":"987f95fafbf1296cd653459ac69b3a73cc4f7f37f38a1c769902bcaabd516452","impliedFormat":99},{"version":"5f3f4c3ea0ce78180d0482cfc808410092b441b727bee9a26d26ef09decb64c3","impliedFormat":99},{"version":"6b1c226b8c0d272c37948df86f81f100157b7cef9d97d2651f1d8e740a2be268","impliedFormat":99},{"version":"3e1e6a7a6e3d0615d046dd62062c557404c9e1c622dfbef4fa83d17c628e314a","impliedFormat":99},{"version":"ded6a76ae5fa6fc3f7f860a187f3b1c81b5bafb953be192501a937307dc739b9","impliedFormat":99},{"version":"8ee4717c4ad7d5976ab1bece799c68045b7b346e274d7774e86ff394cf867d47","impliedFormat":99},{"version":"a9e3299c6098d323bcd9787e2ac5e4d74457e5427c305ebd432e52ed13dd23c0","impliedFormat":99},{"version":"3b8ddc84907c11d89e5240f8299e87fe506a1c18764fb9d546b02f9e347f93e4","impliedFormat":99},{"version":"4b5186a238a3fbfeca1b14fe6b234b8bd5b93ac89a47984715f76f8919e29d96","impliedFormat":99},{"version":"dd693a36f441a1337e9a34b6da2cfdc53d7cd9dbf0d1cde334cab196c3e6f17a","impliedFormat":99},{"version":"e284b0d144003a25e3b7da92c55d80a085531c0c84a77a62f1a3e2bfe82454b1","impliedFormat":99},{"version":"e09a001b1588cde9f5e77560730c5ec6ea346ea09da2d65b3a02629e390d0923","impliedFormat":99},{"version":"77a38dc0e4afa289c6ceaf9121c7718fac9231904ff5f30c0c1201524fb25f23","impliedFormat":99},{"version":"2505ab6e616e35b2a63dcc8cafd3d6092c6e0109b206cec1be7d80cd450cfb7e","impliedFormat":99},{"version":"c2d66e86bd5f13ad098ddb98ab863bcf0d15b323cc9bce6ff56e20eb50648926","impliedFormat":99},{"version":"1959affb5ce54dd86a2bca9ba087da5a29fcd1849eb1710f1d6807512ac513d6","impliedFormat":99},{"version":"8ae1ca3c5186af2c3a6e979998c00c82a363d024ed26a8bcb84a6ef21878d4b4","impliedFormat":99},{"version":"05ec4ee3055f601ad3f932832a0b7fb5842fafa6d3a4f29b200c49e0c8d36bc4","impliedFormat":99},{"version":"cf0430d48488f45abbb7184e36b580c1933cc8078581c038583e16cdfa80863d","impliedFormat":99},{"version":"aeb0806490c71f371a75629556f469419997367aafa673ae2e86705652f39227","impliedFormat":99},{"version":"b445ce66b11750fb2172525591647d30b75ec8d003a93ee3efc12954ffb8d5ec","impliedFormat":99},{"version":"a36860808f7994a6ce2c965e11e7a971ae9b438422ffefe9471ed4f3ba3ef3f6","impliedFormat":99},{"version":"6335dfc1f7c285b25ca643890becb12d22fd24079624d91b660f31a3ef130f8a","impliedFormat":99},{"version":"e0e3a4eb638ceb6583ebfa8a83fb27d5ca98ba93ce00d396dd09d41630834a68","impliedFormat":99},{"version":"54927a5dc7fa2c1d7b8232c756d658d051f2c0620533c4048343e671d18c7983","impliedFormat":99},{"version":"8ff6d24bddad8f2bb8ac0ae129760dd1df427765f4f6199390347c0009ff9b48","impliedFormat":99},{"version":"25a0403b5a28416593fc09c3e5150e981c742afedf0b6e423f8a94f1351352c8","impliedFormat":99},{"version":"0db51b9c351d7c2313296e5879fbad8f20af8b9061885c8590ae0216ff6154a2","impliedFormat":99},{"version":"1c6454d7f733067337f1685a06c4981a78d1925ae0381bcd09f2c43b73755aaf","impliedFormat":99},{"version":"fa7cfbc437c87d93860a4a1304a12e8fa9a28a24695e1f4c36d266b4cbdf4e7b","impliedFormat":99},{"version":"4afe4410e572d10448fb1f7f254bc2eca329e00180e75529be8b22465718b2c4","impliedFormat":99},{"version":"6d57f0ab1e858b12895e1eca5e6f407a835c13038fadd5f85134740e6e32b613","impliedFormat":99},{"version":"5d6ef65ccf14b0d51af503adffccdbaa846848cf0fe82310816cf82eb364d107","impliedFormat":99},{"version":"397a17567b445fbeed01f58163c2b9667638ff815881f349cffec5ad30844905","impliedFormat":99},{"version":"4bbac0cdef9e2f41b2d70826633298df274436caf011a093bfc1bd57dd2269c1","impliedFormat":99},{"version":"38bc1e63328558fecd8e2c3f9159ded06a2fd86059b0a91e93f11aeebeb1f177","impliedFormat":99},{"version":"e4756baf25dba2f6660043ca4fc6e36ab8d31a0c34d507624d8a12cbe6ab9b30","impliedFormat":99},{"version":"4be799bfee1766047c11b3b5d371ca9e3993526d50c3e276e7cdb3943dd680a6","impliedFormat":99},{"version":"513f887178e2df3ea70340c20bffc633827c2f0a4e1340a4176eecb6d3c5a4e7","impliedFormat":99},{"version":"7b6ae8994d485350989d50cae27221f2d9929d60677b8c5de4ceb81baf480d3e","impliedFormat":99},{"version":"7adc87c8c1d3fdf85652694a636c6e032b7ea76335de7a110ffb215970d9b1f0","impliedFormat":99},{"version":"27f60ec60daf015ed0510587fd37d65818c085d47f320f03e2178e80ae1b96d2","impliedFormat":99},{"version":"69f868104a0f83fc97451cb143d1fdee65d6133442e585048983a8e27c6dd4be","impliedFormat":99},{"version":"a4fd1c983504d251988ad2e8629dc110228a591e1bc9f85e57b35895e8141cf3","impliedFormat":99},{"version":"8e82daa0bb799f366cfc646fcd65e507d3db4921082426dc45b78cedcb60f71c","impliedFormat":99},{"version":"a2f99636b48361b7e10c232cdeeb3aede976279f950b7f84e8b970471a0dc606","impliedFormat":99},{"version":"e31bcde9cdc47ff503a45bb8d68c38fd39039b06567c8017021f9116e31ecde2","impliedFormat":99},{"version":"bddecda3271cc5aaf904e94c2b65c23cb7528e27567ef31d1302bc8845374e56","impliedFormat":99},{"version":"23306c0e57b32fdf724bb0aba128d0023fd57b856490b1cd69bdc0de2acc334a","impliedFormat":99},{"version":"4df175087aed418f42fd5cf507c1f57f0972484cadbe0f6c38cabd0c6b3576ce","impliedFormat":99},{"version":"df51e368f1e65529fd132dd67c8312f21b644063ce7950e8b820905d70b28eb7","impliedFormat":99},{"version":"74d10836d7259d3a664ed517a3c8547003e1de056d85b8e324a11dbca522503e","impliedFormat":99},{"version":"b020142c9cb2c061e119c6ebc1712f2e66a68968657f4867332789688c706189","impliedFormat":99},{"version":"df08a61b7eb2b11b4e9c771cc3b538f3fc4260c170f8fd89110843323fac2ba2","impliedFormat":99},{"version":"acc1e28219b83d788ef0e28b8d7ff1f3a8fc7df6a49ec141402e044badc84108","impliedFormat":99},{"version":"3552e9ab64219d9d980f9406c354e620f04ca17944459d4b23c62d472d9be2dc","impliedFormat":99},{"version":"e9f94a086b52c2f522f2bc9ecf7539d7bffc390578cc41db9547005b93df5d88","impliedFormat":99},{"version":"a8f5b86c67a9c2774ccdd1db31968ad888fc41ad166a5d5d066dbe86637b2f66","impliedFormat":99},{"version":"5c25d35c4bbeabb961925d2b114602191800afb4d4f164e45979dd2c83f965c2","impliedFormat":99},{"version":"8b989bf267ff6ef7a00f318e95794bcefd06cda44f3cffde905ca579d17acad5","impliedFormat":99},{"version":"f3983ffdad35bf9234e36a691bf959934b723134c070fa5dffccffe046009e2f","impliedFormat":99},{"version":"2d8c69bb71790264bc61c5858afcfd00d5bd7bca6c9c38185f07896661053790","impliedFormat":99},{"version":"0396db572d4384fab79c5ad3b2cf330f167496da87da0e61a3f55e803f0fcc4b","impliedFormat":99},{"version":"9eb195a59362d107cf8f1d92d704fcd034bd92796f72cf031ad0525d88e36d4f","impliedFormat":99},{"version":"b60a1aeffa207842414020d16c86854f99bebff51832478b00451c1770fc9708","impliedFormat":99},{"version":"178ae1eaa5cd24618fec31c62ee6b66f5f57d76b075d9d8b34cc0db5543c0fec","impliedFormat":99},{"version":"4f31b5dbde1dcb81687ef4e06c2636809f6a0517615876bc937fa266f42e87b4","impliedFormat":99},{"version":"33d7dde5b3614d1f000ab11f9be2cb0f032615b726ca8537afc272db0b522a7e","impliedFormat":99},{"version":"97b8ea7292ec9f0828af2d58952ea17497a73943eaa0a2dd3046a4e07a530c61","impliedFormat":99},{"version":"ebba07507741f7d53d05cbb59a8dea0b3b75aba278810b4d2696776f95b779e1","impliedFormat":99},{"version":"5c840682cf2d211808e4f0dc5cd32da409352e8b3d11d7e9ba25c92796932cdf","impliedFormat":99},{"version":"f278958ac0fde187482abb825e61be120427e8aecb42a9155f0144767a29a358","impliedFormat":99},{"version":"cf35b9aa3b45b2098ec7033db87d004913ac7bf1ce52c9c8154fa86477e9046e","impliedFormat":99},{"version":"8002100726ad65ae695ef88b091b9c8cb73e024eaf23b31d228a5a8ce19af31f","impliedFormat":99},{"version":"f7a7233cef5a86a5c2c5e4dab11b46e0688707bd066a80aa5249e6cd6e0211f6","impliedFormat":99},{"version":"354126b46c623665e6aac86b6deb693dc43499dbd71bf655aa5f6bcd7753dae0","impliedFormat":99},{"version":"1f1d4396e7a118ba9e1f49f290b29d0aa946e91fc8180909b1d64b2998b08953","impliedFormat":99},{"version":"534f6fde91eb366097dbf65174356c88c2726d513c55f0f60b2098fc3f6e87ab","impliedFormat":99},{"version":"bc8d8ff31066bbfb937d223a528d545abfba45a0a646b141e2a15dd1948026e9","impliedFormat":99},{"version":"8a03c390eab5e99798e3d24c1d86a9b0ee851d315c0cb7480b42f6a49338d694","impliedFormat":99},{"version":"46b25c26bc3816d779c0353b3c1f6b83eeda1030b99401472a4341a9ab94138f","impliedFormat":99},{"version":"0ba4da683fe4d459827bca4e9c2befc46b9fe589353a08d874440dc6b1119df9","impliedFormat":99},{"version":"a5ed548aea7fdd435b68149641d20d0c823ae4341afc4c5c027d246a321e358b","impliedFormat":99},{"version":"c831a507ce1fa56d927c77b0296eaebbe63208dc2e10bea30ee19c19d3832ac9","impliedFormat":99},{"version":"0e0775f99d5750b8ea2409b6d5783ecb7465552176022512c4ab695e2cc07b25","impliedFormat":99},{"version":"998b22c2762b4c5dda982144f4273439478216601e1dbf607f8da50f90028302","impliedFormat":99},{"version":"de07059049dbb4d7b800fad4f5919c62c0c572d021f2cde9b4cb92d9d312464b","impliedFormat":99},{"version":"b006db5c3868f18e051c60c815dd8d18b42f0bd1f2a4732e8baab08e56443fa4","impliedFormat":99},{"version":"f6162b05c0a5b26d3446503c022652af632a803010319ff6c65ddb425c88c1da","impliedFormat":99},{"version":"ce99d9af9d4091b04b4c2266c06f38d7f39e5614616973e0d17f01a36212c516","impliedFormat":99},{"version":"d78d9cf92e8957b87ff73a5029aabd2f591a40f4b915af5566122824a328d451","impliedFormat":99},{"version":"afbf6dde412faa5825df13ab00b8eabe1358558603d6e4c34b4ff83c06128500","impliedFormat":99},{"version":"9468d74878264e4ed6214c0127326482d3d81d8b39c2ffb3ef0887348cfc116c","impliedFormat":99},{"version":"5d761b75b6780d20af311198f88e4a894243753acf28338ce7cc0cb1d5e3bfca","impliedFormat":99},{"version":"4c02021950d7f559417399582f74b4f23e7acf96bf4abfc8511ca9f349e7b090","impliedFormat":99},{"version":"f05da64b51a564bd57764011df409a699928b2b9e018a9692e06d5a3e761a8ae","impliedFormat":99},{"version":"448a1d960c3243442ffb6ddec7087a5dbd062a8b2fdbbc39f6ced3f5b7dd1cef","impliedFormat":99},{"version":"c01a88ada696e9f65a4dd8248bd9a568a3f1ce0c2eaa5e7f8696a2c3b3573654","impliedFormat":99},{"version":"6ca73337f9333cbe5e31c1e03fee42dfbdb119e7fdf991e8aa96767f4696d0b3","impliedFormat":99},{"version":"9235105279d1e63c87e3ea34fb6b20eb4968d7696c4783236a2d8ab5e924807f","impliedFormat":99},{"version":"fb3a41f5d7c41e4195119f98b0df0018e7e04a1b025d7b10ed82741f65c0493d","impliedFormat":99},{"version":"bf21257fb910b2a765ad8529cb457d0d9eb99d8d14ef01836bf04422c185f230","impliedFormat":99},{"version":"9dfbe916e48a8172cc0db07e20248214755205bbd16cd5bc0672dc2cbd80a429","impliedFormat":99},{"version":"cfb85bf0a694c3e0630400fdb2c1f135132b500c152aee6b9ae9d842637378f8","impliedFormat":99},{"version":"2067e20e971aec9f9c3b7a80aa3f2ce908fa690d29614956ab939d4137527d46","impliedFormat":99},{"version":"469bd9ff94e8ee2180eaa7be310e626022f4b97990e01fdee2cb681eadfca444","impliedFormat":99},{"version":"9199cfe666c63b59bfc7a0215ad7b834165e2c8678769aa29b6b15d4035dd874","impliedFormat":99},{"version":"75c20bb61d4944a90fd9fc4d79be814af84552497a30059d1f4a5979e338b576","impliedFormat":99},{"version":"e36d57187446a9b265d011815e80c5ac2d31cdd839e5dfed3cadbade9d63084d","impliedFormat":99},{"version":"ff94c04aacb366b85fa01b058ce27e3f2a26305e87a512b6472013f3951a7639","impliedFormat":99},{"version":"f28c4909885c804c93aabb9561ef520ff620576369eb310195a7a6bbb8d9e587","impliedFormat":99},{"version":"e971398a29ade533ddc2730c360a22672144389e077633fc950660f4c4d9d046","impliedFormat":99},{"version":"52677e8175f66b1d6b684e8249f7b12af8932267f0b2f363ab973fb94ee4d319","impliedFormat":99},{"version":"d1e84e4b4b53354c6333f50ae4337b96f1004f28875d3d7b3800cdf79b0ffd4c","impliedFormat":99},{"version":"a9f319a6a5287c95b72c37b461e0f70f490324cc4a55d71378e2a37f1ca67adc","impliedFormat":99},{"version":"df7c9a0919ac54bb69647b916261beffb40d84494f9cc3e68fc7927a79ccb64f","impliedFormat":99},{"version":"30a24fccfdf6a40249949b222a11c755421b9479bd68a96ee97413540443216b","impliedFormat":99},{"version":"da0ed328391d742978219a5ab07decbdcd353bbdbc87708a2176afa971056a3d","impliedFormat":99},{"version":"14a5746786128a83561f1d719290db89ed9b225e42959bbe0023112035a6e0a0","impliedFormat":99},{"version":"71db39385fc6c5eddb6cc70b1b68920b2aa06cd85ca4a95b1de585e127984881","impliedFormat":99},{"version":"c9f95e2f5326df254b2c867de54f7264763065fa4d29f5f9d10960d97352afcf","impliedFormat":99},{"version":"59e6446d76c9c7a1cf516435f942c5e122b3fa9c80d4962c4eeae63f3bb605af","impliedFormat":99},{"version":"ee28654c6c98fe6b359d34465dbe1f9798d1e7a6ed5ece29daf19de11cb8323e","impliedFormat":99},{"version":"68d524e37e75f230102cd0444befe3e17a8c85438060a552322e7e400519f2c3","impliedFormat":99},{"version":"282d6f2f2150a26e8c5cce93eaf68e829a8683171ba13e92ad7dc8b28a12c623","impliedFormat":99},{"version":"34b95fa727e92d0a2fbe45e37352127297aedd9af64e56dfb324ff1280517f3c","impliedFormat":99},{"version":"4d37c6842a01d7310940ed2d39cfd4a8d63e7676d1113070b3cd725131347844","impliedFormat":99},{"version":"38ccba9a0d7f301e4b590f7a52de8a8fb12e9edb1de6d7ede6a8843176abfd54","impliedFormat":99},{"version":"db4e72e734c0d11d2051dea52f678270eb423be4541e3c39ede40bd29e733484","impliedFormat":99},{"version":"b6fa5f1295afc4b3a9bbae107ea00d1fc37956f25b846338916cbb195515a4e2","impliedFormat":99},{"version":"4b3e07d081541bd9f0418c1963a44b02a65923b6de04d6ef7bfaab8e8b1087d7","impliedFormat":99},{"version":"438659c94886ae81435567673c83b61937048729da03385738a023174cbff051","impliedFormat":99},{"version":"63310e90fe40fb7a431b9ff640d54b70ef30d31b23a634890799569521cc2a02","impliedFormat":99},{"version":"911e8affa1bea9b54a8926ce39295e190ba3e5e36182c7808c3d657fbd77d705","impliedFormat":99},{"version":"02353129e38fd07cc487b5f822ac710ec117e43e479e9f9f8039418ed3291ff5","impliedFormat":99},{"version":"54bd44d1d220488406919d2ddbdb92cef690c8ebfe41d2cdc61a8aaf26d6396c","impliedFormat":99},{"version":"790d0cef4abbfedbde0ff29c9a1865d5ed8364e9e251e25bb13794d30c13ac4b","impliedFormat":99},{"version":"88f2b0ad065d1ff42736c1efeb0e14061b3091d9376c272672be3f27d167a152","impliedFormat":99},{"version":"81de941dc5851bd7ce1e8f81d4d31db1e035de774e571947f8d03b351fe9f764","impliedFormat":99},{"version":"fdc68f982f0c7b074e3787534a5137c3f9d746edc323efddde286931ceb9c954","impliedFormat":99},{"version":"be922b6a92064b78554dfbf46decbddf5a0b023f49a656a7865e17ab0bf710c8","impliedFormat":99},{"version":"609d27139ad9aa20641c466c993b2d8f8c413296ee814b1afd79f48bd809a0f6","impliedFormat":99},{"version":"176b071fba5783d15078411e7c0753d2a874dc0ba0bf334c402e358b59e78f54","affectsGlobalScope":true,"impliedFormat":99},{"version":"774d51ea5facd44ed191c2e420f2a0ab4da76a41905e8c1c3aa2a532ec340d97","impliedFormat":99},{"version":"2be23228f8822815f04418af4b3616f6c12d2e8310d3536537ca59c791fd71bd","impliedFormat":99},{"version":"3e9c9a37943e0f4c86e33e47c598a43f25117acf8fdf177e6ff5e0476e6d0cee","impliedFormat":99},{"version":"2c0b6ecefb1757ad6ce6d2414b3c268cb9092cff307f6794c75e27f7b1b3b358","impliedFormat":99},{"version":"10f2d3d9c642a1e734adad62f07866c3217b1f5f89f9f3f47d3fd6a295bef8d9","impliedFormat":99},{"version":"4894b371550ff623685722b8fc3064eec2a1353d0a4f7a4f46707b446d3cd607","impliedFormat":99},{"version":"1306e750b3d9089eddb926279035e88119bff73ba6d12bcd1ac3907eef2bc235","impliedFormat":99},{"version":"f97a6ead0f9c40bd2bf83cdae4aa47655aea300282afd44998180d9cf62b7d76","impliedFormat":99},{"version":"a5d1b10c57d14126c7a312e2bb28763c745a87c4f5c005ec6b9ad79aa16850ae","impliedFormat":99},{"version":"33b25938d78614b92778d270bde2c971ecd7f369ef6c990d13e247eb2c7882ad","impliedFormat":99},{"version":"ef325176a8c255a9a55bec7c23d6289c98b00ebfd67112bd4b915c679d721b1d","impliedFormat":99},{"version":"81c53ecba335a74d626d838f842eaa7cf84289776b413356bcd61560f07c9e51","impliedFormat":99},{"version":"47a102af679f68d61d7754dd8f133fab95c3cf7c2dc6674e70efd1b7b7c815ce","impliedFormat":99},{"version":"41931aa72d208139935cd9537c83679c6ca91fe69fd1bd8ec88bbe8e93fe2a2e","impliedFormat":99},{"version":"793014c8196d3044e2d425d7de6339e130a8f81136c5876e2e88e1b8279dbea5","impliedFormat":99},{"version":"7cfcb8c758cb502085d9128ba3ff999084cafd64b9b7c317f87fc85170d1282c","impliedFormat":99},{"version":"6d0b4092bc1fdd4843d9a4313b470b6b7773b5fb712545d6174fd4d703265ae3","impliedFormat":99},{"version":"b6e63e92b837071df07652d3f5632727214b713881c8416a133f7afa977d6e44","impliedFormat":99},{"version":"b09eefc95f09a9a9c61e4f2ed3c1e22069c703493f8e231bc76d3c6cf7ab1422","impliedFormat":99},{"version":"1b08cc33d8dedfa20adf4a779020ec36d494ab7ea503395c658c5e286a3b50e1","impliedFormat":99},{"version":"2c94d2217244dd31275ca5e404560c5c2105b5f06f8985d0f039f39caa1e9e30","impliedFormat":99},{"version":"e77d73e81f5824767db0df8bdb7b7c72cb1741d5fd74e099bfaa6369b8716491","impliedFormat":99},{"version":"077f88e83a13ea89300c26c39ca8ec3708bfd09a15464c71e2fd762708fbecea","impliedFormat":99},{"version":"4f023892bf3e27c71473a12d3b838cbab4350e1108a47194d570627664beb5d8","impliedFormat":99},{"version":"774a6eb661aad32b5f9b73bf9d08af7f9204a4bc67a583494caf43fa09fb2af9","impliedFormat":99},{"version":"0c3d92e5fac4a662f12b04c12ca741b4f34a1bf2824a470414322ddb61b350bb","impliedFormat":99},{"version":"b2035f5bb429bbd282a7c947e80bd344ee948a4f7042a019271d3bd114d09afa","impliedFormat":99},{"version":"a4c05674bf833557741ebbcc3fa4a25ddd052e1c762a91037db94a2d7688ebbe","impliedFormat":99},{"version":"97006e8ef367bc2388ea292d7eb6cf471bd2b53d266642ef8284b66afe6d01bf","impliedFormat":99},{"version":"927c282fb88ca5c95a9aaea00175b56b0a6dc8728b246c9e0ec455de40d54fe9","impliedFormat":99},{"version":"7dac0babb2b88108fc5a5410aaf6fe6e59ef1e158e3b5283a990ea503ac3ea07","impliedFormat":99},{"version":"2f4620eeb98e884074a0ba924445a69b29654da70dcff2e3f84f58092741e6f7","impliedFormat":99},{"version":"669f1bc764b5fd840e483e123909aefdab8dc82c9aeadae194d75129fbba0b53","impliedFormat":99},{"version":"23769d3f0549de671a5ec795a8c2c6c4fd80c22af92348daa349073b65355fe8","impliedFormat":99},{"version":"774182677ec80bd5e58d287833ec21e02bcfccfdd20247780375691f201a0263","impliedFormat":99},{"version":"66bc333acb797d6c079d8830ef73bd4a34c4e1709e6a9d40bc20d5b92141d50d","impliedFormat":99},{"version":"92fe8e78ad5d9f9eca627b40cbc1fcfc095a230aba0911101d1c74f3ef77c32c","impliedFormat":99},{"version":"78dc76bd9afff09e5cea823d477657d25be9b0e1da7582df7df6e713abc6b7e0","impliedFormat":99},{"version":"651be876b03c705ac06a8cddd6ea90f635855d6312702a441e37b710d4291387","impliedFormat":99},{"version":"ae2d7f7735a249142233a5b9624baf7d1076c1b8e30bf6f9ed1f1f96641d368c","impliedFormat":99},{"version":"667514a0b45b9137a724df446646e49c6c5ff8e6c52b51faf7e7d97c07876339","impliedFormat":99},{"version":"d9b1e95de78d5ed6313c1f5514d71dae8e2dfd758df656912f2e40ffae72fdc3","impliedFormat":99},{"version":"24e34d276c6b1d5b38adc1a02ebca9d211154478cf875a3d175c12bd2473180d","impliedFormat":99},{"version":"2e7a903e7bad7e1053fd16172349f653b8e1f04b118fa6a0c94f03a05ce66ee8","impliedFormat":99},{"version":"a2b7e8befa2bec65d655a9205fe6ba2c6c313e8af050e0ec6878d667368b0370","impliedFormat":99},{"version":"1fdae95c93d7a258da7b02e50e7c4f4eb2041c4e8c86819c6bab35f1d3b33825","impliedFormat":99},{"version":"8c1eacab9cdc1a87e6142c96994b4679c81c9445557e14fdf3210352b7586209","impliedFormat":99},{"version":"05c811914dd75723518d9e11ab4e406bf49ea23b21ca4b0c014f529630cd6bfc","impliedFormat":99},{"version":"cfb373d580586808b221e2ec5555e381569bbcd65ed91abf6467235796e4011f","impliedFormat":99},{"version":"c01126bfe2cf99a27503a39cb9bd923760f43179322d9ee06640c2e329e00916","impliedFormat":99},{"version":"2b6cf5f7e4b87a9d212aa0b043a4e0203f75aa7a505457838c5c12ef3c5cccf8","impliedFormat":99},{"version":"e9214291673a507e06de72638d08cb77a5a83946ff371fe3118231fd14b66148","impliedFormat":99},{"version":"09949a01affc32445e16e0360269d2a7c3f925c2e67789934fbbaf5658669765","impliedFormat":99},{"version":"ddf55f92812e0c95b45ad70bb3b594c23a9741c3c805e916747b8b4d74682763","impliedFormat":99},{"version":"41ca00bb070d836497914df6c9f3b51618ae5c1bb64dfb874c63d0daaec894c5","impliedFormat":99},{"version":"450c3dc5526f8e73bba30f955e9e35e42076f82559e4f3ca733e30a99f608fb6","impliedFormat":99},{"version":"840457a9dca7071b074b79ec4bbb07e26daa4899b1939b3bfdffadca62fb157f","impliedFormat":99},{"version":"0bb96d1b7886f8348ee457c22db99c258f563e6e4371410c8c0137c54f8b6332","impliedFormat":99},{"version":"107dec9919e26cd898658841caac2186b3b10ca2e81ba0ecc9407ac989b0b860","impliedFormat":99},{"version":"3732b7dedf61d16e6b95aff55a5d3d4975df12806c1a8c6931e02baeef6d96ea","impliedFormat":99},{"version":"8560d14dc193327f1792881dc467e70e73a74c0623d68adab861f0848619e6ea","impliedFormat":99},{"version":"469827f7ebcc9bea7ea42913b61d3570de20b823081cfa369e37f32f9b6578ce","impliedFormat":99},{"version":"11a76b4313a4d63d9029f0a3ef1e0aa8528aad877e8ce4603f0efe0100bf90a4","impliedFormat":99},{"version":"ee10a6b8d4948616a923e953b40dd564d87f4c6c960353a4ab40f9ac5953508a","impliedFormat":99},{"version":"616f4301604d5263a177d9d378a417940ee51f4661dc970c446265139b3dc2d7","impliedFormat":99},{"version":"cc8621f4a86f09a9d63af2008516e3284fa8dee2da7ac3e010a7a344267e9fb9","impliedFormat":99},{"version":"318a5c102f218073bb58800a24742df255fef6b4b8b3ad82a0ce2169983331b4","impliedFormat":99},{"version":"466a87487e3ee80702edb8c493b87810fe84d8f0f2d15c7e3ea2885f62d7c31d","impliedFormat":99},{"version":"a86229dee59f68ee7f97b00827c35c3a97d2cbde428b0b8749b42784368895a0","impliedFormat":99},{"version":"b804208e46dffb0210e1bf1b5fec9dbecb116bf5614b67ddfb7b05233ef09a67","impliedFormat":99},{"version":"8a1af08bb4feea4d197fc9a122eea0fcce3aeb317676d55444e4e39792818d16","impliedFormat":99},{"version":"d61cdac7a7e1aedbe5963e270516a9fe8e7dab5f7d9421fe62315a042657fc54","impliedFormat":99},{"version":"4504027d521a810f190f5a1fb6b6235db3e4fcfe4e383361e849157fd4017cc3","impliedFormat":99},{"version":"6cc22fc095dd4bfc296a2abddacf950b999c5ea21032c147d992c1e3bc9f2151","impliedFormat":99},{"version":"107fe9df1e4aa36cdb51032b4f51fe26eacbed9f9452c05b0ed145afb91dafbc","impliedFormat":99},{"version":"6f912d1d946525532c3537fecc0bffe9b2b25fc6b95087d00191b56403c64b02","impliedFormat":99},{"version":"d8d5640bc8ce5f5352324ebf9772c8052948e993f26b41267f78bb0570090367","impliedFormat":99},{"version":"399194d25a36f88cf475f80ae64aaab76f3c404055b582538aeb7888fbfb7aaf","impliedFormat":99},{"version":"351b3fe6ba6bbb4d7460cae2a87fc9a1c6a836b79ab217c7c5278f970db08b95","impliedFormat":99},{"version":"ab6dd1e3fdcc478cb81caef96c7047c2ec0811480f86f71be363baad015e4cd5","impliedFormat":99},{"version":"3c684018070559cd0d19fbe2b3e46c7ce256e19a7c84933609af3d75290232a7","impliedFormat":99},{"version":"dbfa5e96e7827fcd26ad524c28d62238de9e58cadc28f347038aed618fdc7a7b","impliedFormat":99},{"version":"d0dfec3c7c406c6ed7cc1fc353d4dd19018f9349b202cd3e509eb9122082b8bf","impliedFormat":99},{"version":"6dc03a531b230155ba0306cb70d983986a5f8a0a894867069d0aa6324db08a5d","impliedFormat":99},{"version":"e1ee6eaef7fb5f2aeaecec5af531fde8e953f1e38b808a31edb1ed667433504a","impliedFormat":99},{"version":"5ee7350ef93ccadb9f50d4faff03ca3287a20daf94457baa7a06b1caccf9895e","impliedFormat":99},{"version":"9b91ddd6972f05bc0f1392aa0fa90a506e29af1afcc7752e475c55c4fde18d31","impliedFormat":99},{"version":"df204cf9d8ba5717e85b68e9d69e46382b32d24e10dddcf2f5fc45a936710fdd","impliedFormat":99},{"version":"03163b5b25c54b0fc355c1d2488a3c29a4af3e9ba831c92c2c6e621cfd4fd095","impliedFormat":99},{"version":"50fbf58008cab964a975271c0e68411400c40c99cb7e876a74d1cb141438e1f2","impliedFormat":99},{"version":"c82d5c2d416329c5b62eec644d3fa8098e841b93433b5c11d4c39efe9abe9d3b","impliedFormat":99},{"version":"636ffd024108675c95771750865a80ca53a35f0a078573866da04e08785e7bb6","impliedFormat":99},{"version":"97ccd146c31ad8368aacc94fc324782291bb7d581204521bb47ac672ce8ebfcd","impliedFormat":99},{"version":"4adcf1c77d54af6f042abe98dfce5f4c1709e50e9dbc1642926192354487c131","impliedFormat":99},{"version":"d4632d7bb32a4998ba103556645ef1150a0da8f9658f6e6ecd21204cf6fbd286","impliedFormat":99},{"version":"4504e3fd0bf3ec94b942b333e8653f3a386333b7715d2ec0b3e120f254f91f6b","impliedFormat":99},{"version":"70bf05d4425056e5a47cfd50cdef2afc619d90c0f4549d96a4de0c15bf4de606","impliedFormat":99},{"version":"a82f209e863830631f1fcbab13b560b82a16fb3544bae7b9a5dca175836a5515","impliedFormat":99},{"version":"3344cd5944b7e64104654321143a8ac9942a33c2a40e6e69dafa7eb3649a57a4","impliedFormat":99},{"version":"d7200878e154ae172ad87b3d83efc4fb5999a32a0ebfbdced330ab7e4de21ebf","impliedFormat":99},{"version":"b22dc469e2465a5642bfc1952395e727841c6ab822d6f4a03e85f6735991a590","impliedFormat":99},{"version":"9c03b9e695d6abb1a68c91be56ce74a0a27b327408ce1e6b14276148ccf75917","impliedFormat":99},{"version":"756890d4dce748298f1531ee5647d15d6ef599bf3ab82f331bd6944809f237fa","impliedFormat":99},{"version":"fa341cc5c5cc0e220554c8bbbbe8a20737219738e6dc29d328ee7b351934e8c6","impliedFormat":99},{"version":"db2ab0896701b2cd55281af7132029104263bee659904d65685c33f436bb1bbf","impliedFormat":99},{"version":"357484e7b33f0366b4d918e5623ea38c42e1b79093cf57b37fdd129f08f747b6","impliedFormat":99},{"version":"6be8d34aec0411146f330ae122c920c5615c67423e4d6626a6790ee48060c7b7","impliedFormat":99},{"version":"5adfe7cda513ac8ab76c9a42f5fe7dbfcc5f162ad8c0a65275f9dd6c8ed51e3b","impliedFormat":99},{"version":"df75e076d5e167de6a985cc2487779bf5e551430dcdf3b43aa7168391c42e7d3","impliedFormat":99},{"version":"3b794c3c657b91712aef51da5d1f1fa8e96278b7e0068b67c1e4e32dd39052e2","impliedFormat":99},{"version":"e5d521e00e91df030e7ef2db79294f97c3258f213cebac04fb1d7e545e036c92","impliedFormat":99},{"version":"a9c2beeda1479ab211a437d27da7170170f00c080dc0534a234e0f0bfd80d0e4","impliedFormat":99},{"version":"fb6a4344cb6276e3d0ef8bb9eb23d3a417ec11af540ebbd02e3dcb3bff739351","impliedFormat":99},{"version":"1e2a65e4cd60e1e6ee34f5d4cb30a0efb74c8e5e77b51fdf0eb6668607c71e5e","impliedFormat":99},{"version":"44bce55aaf52d5b55fd0221a159717679b2b8a1965a31cbb282068c088fc14ec","impliedFormat":99},{"version":"a2577da4ebf625ac5e8d015e1b85a534f324aa42073e5de539b526c1b6ac9368","impliedFormat":99},{"version":"d57044aa13f2e0132986607dd7eb623ceeb6bd80c9be75088c97895a3c0d9b21","impliedFormat":99},{"version":"f13a0aad613324ade17df982376b78e0807cce490ddde44098e64a86be7408f0","impliedFormat":99},{"version":"55af2e7ea5c20ea6b77c6798aab8e6a6ba1af8f03b3ad5699f73e3432904473a","impliedFormat":99},{"version":"f6eb6bbdd4c84b7b28db181354739c17e4b63375d0a3c050a14191b91757a10c","impliedFormat":99},{"version":"11d819e69caa33068ad0ddb9424d7afc1c39abb48d342e3e1df7700bbffb8b88","impliedFormat":99},{"version":"d8bc0c5487582c6d887c32c92d8b4ffb23310146fcb1d82adf4b15c77f57c4ac","impliedFormat":1},{"version":"8cb31102790372bebfd78dd56d6752913b0f3e2cefbeb08375acd9f5ba737155","impliedFormat":1},{"version":"fa8458b71b7df6803405f28c9acbf18d1d829f220121fbffac29b646bcfb16e3","impliedFormat":99},{"version":"bff60ab507d4474aa92eb841de8244fcf39d703f38bb4e9138d78beefdbad256","impliedFormat":99},{"version":"8a1384d5e590eb606dd259cfbb907220b08760599b5e8919fe4c1affd9faadb5","impliedFormat":99},{"version":"f1a02030d97c91ec42cbdd6d4dbbcbb24eb8ecc903250915833861ab832b20a2","impliedFormat":99},{"version":"692cde0c7748503ddebb0b0d96145e09f980d4743260610451800587d3613e66","impliedFormat":99},{"version":"88eda9f9a2a6ec310dffcb550ac43fd3723baeef3f2c98b246bc0692e3579789","impliedFormat":99},{"version":"a2f203e5fa650764bd31f9eba12f8b98abf8404011d29aae9d4b2e5c228c284a","impliedFormat":99},{"version":"1a7df8199bb866dd3a711c0434789921de6e82ab4474750e7d6cefd1d8249f49","impliedFormat":99},{"version":"5eda06983696de02ea6e45726f1cdf422909f8f9dbbacb5ec0ab776c820db266","impliedFormat":99},{"version":"cdeff9cb3d3ca460facffb66af8bdedeb5b6f3d198be0cb8b0b0f643944a6075","impliedFormat":99},{"version":"81847f20dc95fed0dac298c66e89478b5e9ffba2482aa09e9a16a0d9df8e71e5","impliedFormat":99},{"version":"7b356b8a056303f3cf88fd1a8a8f0a3295c9716a9626a0177a00aceab0c6554c","impliedFormat":99},{"version":"98530d6dbfab4a03e0e5f0c79649316e27475a01a71e9b333681440fac50f1b3","impliedFormat":99},{"version":"461d11fb11f2010286ec1d8a511f5c5057220b685b6c2e4a0f750cd01308d273","impliedFormat":99},{"version":"334b20b45f83a94ac5f662c38ca2f17bfb9f74af78960bb7e5d6227cfc819904","impliedFormat":99},{"version":"abbc5183796af20947b662cb14619c1f3149c76b691a84262b23fb498db2e534","impliedFormat":99},{"version":"66dd9263a1bec966089004268e6bcb181783b5ed19957616b8ccd4c11e3cb44a","impliedFormat":99},{"version":"96c46615ae6c124e516e385a745ad25ee7aaa5d0b6084808aa0f1c072de2cca1","impliedFormat":99},{"version":"5ba0c52988d96a7a970fd08b67239360de53ea30ca10cf728d2ff8fa307d2182","impliedFormat":99},{"version":"e998053b352c3f4034036305a7cea2ca2e29bfb13813cca4ab0c3894d820e986","impliedFormat":99},{"version":"435dbcf1cffa4eaf52bbf0f1c907b6a0093fcdcdd76ee5408ab056c2fe826482","impliedFormat":99},{"version":"d6d905a95ac75d7334b5511ff699dbea35ff2947dd9a05291577f339121d129e","impliedFormat":99},{"version":"f8c10dc8890e45463791ec4c1b62e098e630deb9aba122df7e044bf7042521a9","impliedFormat":99},{"version":"7946f76065c80d2874ee28e35d711476461966f1c9fdd4fab147374702bd8b7f","impliedFormat":99},{"version":"1496a38d43f4136a4ca8f808afe7e06533dd3ab3bbc7f9e36607955b87fa90f4","impliedFormat":99},{"version":"56405ea0e82d2da19af64fba30b5bf3efa6554b18c23b1d7bd6985aa599da01d","impliedFormat":99},{"version":"c1205637e6511bbed98cfea122034424451ecbfb46d423adaf3307cd02714698","impliedFormat":99},{"version":"5dc18c6ab14c03b86b7154185ade2399f4c2a39f9aebd1e123af29beff9baab7","impliedFormat":99},{"version":"96bca4c28fc100d661f1a096bfd4fb5c06cd3c4896e7ae790a924f806a81ac32","impliedFormat":99},{"version":"62de4754bf98e3e768e33f62bbeb2f95342cde33352670bde1608ddeefd7b8ca","impliedFormat":99},{"version":"a1235859ede93645b5bacc6b3371bc0e17881f89a5e11d814eeee20a7653913e","impliedFormat":99},{"version":"60f98a7b1e753a585302728e01e654ead78b68608c40a23d8ad232b40775055c","impliedFormat":99},{"version":"74940d9a9c7ad539ea413e8281a1950dbc4f5d8302ddaec12f90f4d9e1734aa3","impliedFormat":99},{"version":"1a4cbde5e70ca1533e3f946b964f6937e222269a46bd40bdc9c404b5123d3b9f","impliedFormat":99},{"version":"f72ab0d05d5d21dc6b0fa818f95c5a51d1b287093660e44441412da385587d68","impliedFormat":99},{"version":"7e153ed0bf5443b76f042e706f07c60135e9bb37a3793aab6e0230ec90690b6b","impliedFormat":99},{"version":"e76d31fc62d25639085b615394bdda429798e28401fcb33c2eb07843b1b9a7e3","impliedFormat":99},{"version":"7fdfee42a4cd1d0153ae518c41fcea2578152f0405fbeaefe02a746c8228dabd","impliedFormat":99},{"version":"857294d6ba9cd46b29ff32b900879549426ae1b49ba7c6efdc15168b06238821","impliedFormat":99},{"version":"a0e6719c7d3b5f35af34377203595cef01730c679def9a5ceec9cb49d09ac72f","impliedFormat":99},{"version":"e0059ef4d4ca58e4e4d32b32ea986c127596c2aa4520fc1ccd9ae389dbf846ab","impliedFormat":99},{"version":"e7a05a14fdb873e49bbda1ac654af65ea1b9fec0385a4e4cd8d6313796eaee0c","impliedFormat":99},{"version":"c496ca4722a912620c2331293fcf6f84546a9c6ac09a0820906d160913f02ed9","impliedFormat":99},{"version":"d8fe1ed406db122e8f2eab4c9dc9824c4613dfdf69346e87882569517cee821e","impliedFormat":99},{"version":"3293d5bc69195774b372a24ec6ad7ffadaac8bfd390231d45ed0b94ae3b3c4d7","impliedFormat":99},{"version":"a86504576e459a8cc30809d89d3ec8f9a400565be2ec0db5f158c518e54335c3","impliedFormat":99},{"version":"ba37f76d1634fecbf5b592020e8a96e8de01147639136902f545460352d9396f","impliedFormat":99},{"version":"0e8c93ee3b7dc2842717c86122675daad3502c251a1ef6887263d8e2855765d0","impliedFormat":99},{"version":"01a6ad70ef0f183bb60358cd2100611f69a2ee3f49cafdf67bfe3dc5b858fdbe","impliedFormat":99},{"version":"39e1b8b953372d4f3389b5c57e9ec118e8b4a20547850f54b151503004839d01","impliedFormat":99},{"version":"9a15758298fc9272c9158321f1700e770688dd79c186a21081efa57a49b0839a","impliedFormat":99},{"version":"025286bf8e272eabdeb5127bb410474766bd60b10a7a07bdaeab477044e95ce3","impliedFormat":99},{"version":"928e854f69af1c8b53aff348cc3d5e2a2d42cce4ff0719fe83bee70600722f7c","impliedFormat":99},{"version":"c84da58eee58a01b000133f4da2dc400cd2770d0a0f0426a5dc788676d15b7ae","impliedFormat":99},{"version":"741767fe6325793c4a23cfd9b43a7ea197e6e718aaa4d28cc31ffe3af10dade7","impliedFormat":99},{"version":"caf2c9200969c6f408376782998f26f37213002c219d6411b76d97c1b5a4d70a","impliedFormat":99},{"version":"de5ef7da5d9b5c32fe52a7e60cd97fad9277f290f47fa7687b9b2261826f5c09","impliedFormat":99},{"version":"5ee4b6ddc7ccc7678904092974eefd890de5f513d51bf4821ee087e8da8213c4","impliedFormat":99},{"version":"73c74ed17ec920606ac88c41b4e77fc25dea1a8043406287416b38329b58e1bb","impliedFormat":99},{"version":"a52d67c2bbcf7105298058cd177fca6c7d3ca2dadb52581550741c0995968c68","impliedFormat":99},{"version":"33a715a5a3028a179aedcae37154fb3d79528f405d73db96deb793514f1163b1","impliedFormat":99},{"version":"0bacd7f1e29617138de6f84892fa8c6969d9a75d287597688e84273cf6faf492","impliedFormat":99},{"version":"3a923f02ca826e533b1d1a496df58079f5b0083389d53d3556fc3e659c0dfe70","impliedFormat":99},{"version":"4edf7f7e331bf21b0072617376e053973f6e0fdd68af37f761523180318fc5ea","impliedFormat":99},{"version":"0bea705c1c0eb8b60cc562dfba6ad3ec50236260902de5f83630c084dd1edb65","impliedFormat":99},{"version":"3556733d37eaaa18ec9f504e763b64f38f99bb0a0d8d9639d57a9010f8d88edb","impliedFormat":99},{"version":"6b0fa06657099a3b2e642a11f6018f8f2bcc709d1c049a5aab49aef4e3669ef7","impliedFormat":99},{"version":"f4edc3715e3c51b3124823b08580de89eb1c4339ad291ee3062f1a085b7e469f","impliedFormat":99},{"version":"2de2849334940279ec5be891c4faeac3416f8aadaa137363b5a38a946707056c","impliedFormat":99},{"version":"ac9f808b7698dc146259635b8681088f25462dfb334981d36c1a3d90408d8a8f","impliedFormat":99},{"version":"89a487530f77e90ebda6862d139b3a31568a95506b64d18146a49ad2124370bf","impliedFormat":99},{"version":"4ae50767fabf2357711a40e3bf203f0974092f5d4dab621933268aab341c61bf","impliedFormat":99},{"version":"80a2fe6a30a17b941f7099ef2c7db2bd22aba170d2a389a6fff57fc51275fba3","impliedFormat":99},{"version":"0a930282a8b7be3b81b3ce08fe09d5fc2f42eac8b2b8cefc0621993758d3896d","impliedFormat":99},{"version":"d11cd50233aacdf5f8d6cf6d754b2f53cf890b6caea635fbeaf7b422e8e46747","impliedFormat":99},{"version":"ff0bde0ebffc647d76aefcee860d2cf1f84478e3d3fb49639a277c7bc3857c2d","impliedFormat":99},{"version":"7cb03e180533c6ec674455a4cb9ae83f0e246e6c0c81011807016069ccae4744","impliedFormat":99},{"version":"bd0229886d86b50ce6e3fa37965236538b43ebb46694364232eb57052a295c98","impliedFormat":99},{"version":"3c02c2a42cd34e807481159870e0555e040d891c6f20c44d0ae695a6954af811","impliedFormat":99},{"version":"f2a7e51e031846ae9f91d8325d220aa3c37102cfc1c321a8c3e854a998d04fa4","impliedFormat":99},{"version":"8c59c788c3308a62d2cdecdf15dc83f592f9504d7156d7c1506c42be0c5711c1","impliedFormat":99},{"version":"436fe5899e5f6da71b86f3bbfa1aac3ebea39230b85ac30b0b83e06844eb9527","impliedFormat":99},{"version":"eaf850353d9e369261a0a92fc75e1b5ae9fb322462df029e431d761a60adacad","impliedFormat":99},{"version":"b7f8eda6d783c94b867c463cee7b1a33132b9e5e5dfd732b08650d7c22b93c68","impliedFormat":99},{"version":"21247c958d397091ec30e63b27294baa1d1434c333da4fda697743190311dc62","impliedFormat":1},{"version":"431ca76e6333ddbf31098cf807472f656e542f574044260431ac523fce8ae255","impliedFormat":1},{"version":"d5eb5865d4cbaa9985cc3cfb920b230cdcf3363f1e70903a08dc4baab80b0ce1","impliedFormat":1},{"version":"51ebca098538b252953b1ef83c165f25b52271bfb6049cd09d197dddd4cd43c5","impliedFormat":1},{"version":"c9bcbf26e98c7d4c33feb0b36edeca0665ba5b3c68b279c9f1c8d8c0f1b70172","signature":"3ab81520355d2a34099ab42335f2671cea23abc623597b4c61d97f66023b60b0"},{"version":"40d3ba4c2e8f26cbc38b139341cd9c8c8913458d35769253ea1993d528d09910","signature":"e8a5eaa361f3fdfb309906d8e0d64cd004005c487e0080ff684f706075c61344"},{"version":"1e2485462666e4717326cebcbf47b2c6a260fca17804591ab07bc23c05f36a56","impliedFormat":99},{"version":"7bcaab2848e4cef5c989b2d661ee391b972318623d4c674dc7ac7d5630111158","signature":"7299a9e4db73436f03cf92a218703c2b721239cbb33e05b62ed75ecfa6253782"},{"version":"07fcc9be98e12bd2f0f71a501a9bfbe2e53d38c50e8a5e84223fdd05bd8749c5","impliedFormat":99},{"version":"b887a4575db46263f82d7bde681bdc14526e4a2618a1172fef4206c467752d8f","impliedFormat":99},{"version":"d023fe632a1c391446acf767819bc573eea28b9682cb861a75f84ef51a8764a4","signature":"f67413fe3cd48b7f3a33839ba8beb0bb4768b4798c848a4cecb0eb0d22ee1de1"},{"version":"d986b0763d9a8d30fe744c13fb350008fec521312405c450a5c326545c1fe16a","signature":"4fa55d3d836d8baba3fffd6f5420230b105b8bdd71d50a78b7877550a34aa8f7"},{"version":"3b5b43f0f3d7c3bb65a7851aa53a8ef129fd747905e092b926d69e6a65784c29","signature":"6bbb58084db9a9527e2f15f883412a46e8d5da8431233fc1f79a2cd163d2bb8f"},{"version":"c90329106b276336b4252e659bbc26e9f62edb5ebfe8a99e84cafbbf748ab4d8","signature":"2560f99818ff745c83d564b8ea2a795156f2e1e30f09be1ddae29fdd255950ce"},{"version":"a4fc03cfa3ba73313f65b0633fd12071dd1375e6c4abccbe92592000f8a8f751","signature":"4776d7397b5995f8b9f37f09ec1cee07184f37bc9bb538e5123975f46bcab86b"},{"version":"3e8c93f6d2e2e801718df0c37df0bca729a02f9b91b56dcc0f513c34d9edc687","signature":"4b93e3bab2c10e7499b47093a526e526a116f6b4275b1304320e46dca5c37da1"},"81d020d29e12c75fd61fe96a7c59940bd9e820344e8962e5c8cf3e502a957eb9",{"version":"38d41e008a795cd17529fddc2623e063d32cf7ec976a441fda720f2d20c2f88a","impliedFormat":99},{"version":"8cf75ebe85e99e7302e3fb49389954d95c124840082bfe18e9b9c5d78b9b8db0","impliedFormat":99},{"version":"911b008258238f891dad150b37027c44c9c57b0c39d263dc9352a4db8da6214c","impliedFormat":99},{"version":"0973f4ba17ed08909be55d4ab5016f37ea4499a5376975e87f147069c4032bb2","impliedFormat":99},{"version":"bbaa51cf04d497aa74dd06b955deecdecead633e40b20ddb51dff23fdef3bca1","impliedFormat":99},{"version":"d2487c18d2304527d79d2361a4b16f9600958dcdb6fb8db267e21584c357256d","impliedFormat":99},{"version":"14aa97ab79e325a486598093ce6e0a08d06b36eea74fbff2e650d5bd67ece12e","impliedFormat":99},{"version":"8012ce91dd686fd1996f3f9cf28739940ead96538832bb4f474b399dd249120d","impliedFormat":99},{"version":"d24a52a58cad88721060d59b88efab2db769c6a281cdb46b0cad2661cb433eaa","impliedFormat":99},{"version":"25d0315fc8cd8d63e81497db7a75a2eacaad7c21150065ce5261906a85915c4a","impliedFormat":99},{"version":"4a734a2c549ded334e7595e33de7901a066eb0bfee6e2f2ba374cc061ae2d816","impliedFormat":99},{"version":"39e30f43f08e2eb34fcaf4a224cf6d0b356eb87eb147333314f86620a66eebe7","impliedFormat":99},{"version":"f67ec943efa2ccec3223b9e1c8a9bed99e41a1a464cedde4f3b2c349a64d8f3b","impliedFormat":99},{"version":"f7cd37dbcafc36baa07f5eec3a9506f1f4210c0a5ea7be6716b46d73310303e2","impliedFormat":99},{"version":"aa2fb2bdc77478597d9d3ac1d2b129463b5b972f7a4426f90d5c6f1d112768ad","impliedFormat":99},{"version":"2273783a77f707605449a8b165be1b658ef7dab39062958a0ac780aa6f4438ca","affectsGlobalScope":true,"impliedFormat":99},{"version":"463a25bd31085d7ab0f985568986fb942b4be5b9132b121eb51f367849b5c807","impliedFormat":99},{"version":"bffe8cc55e12d802d844e4a8f8c3cd946ad9ac3276d426fe4442a98d0335bdee","impliedFormat":99},{"version":"67b56c524e1b5cfb8a7786ac5da75a2d115d9ce9cc8c6d22e30f45ccfdb88b74","impliedFormat":99},{"version":"f3fd42dea8b76ab303ac3de0c08262e0fcaab0f67a7352e3af7b52000b3d1581","impliedFormat":99},{"version":"e4b43e54b6e1d56c7c280dcb4b584bfe4a81a0b71b2f6e8b9010255d3b37321d","impliedFormat":99},{"version":"291ea569734f43f8196bfe8f4111646c203825373c9a1336c00368330a985d0c","impliedFormat":99},{"version":"2bf00afae02e410626f1b9ae0479e4f33c1754b0fe2ab410c852c964b99d63ff","impliedFormat":99},{"version":"eedd60cc40ef45f5767f2aa03d6140095bd7347fa6cb707c1d4623e9305b353c","impliedFormat":99},{"version":"edf0ca68521f6b6717fb4ebf44e27180a5f0ced783b1cdbbb2377caaeb39c1f7","signature":"35d232af4976d7eb7a408223a51a536826279d1b4cba175d7c6753ff3e2f6e71"},{"version":"4182c839229f60e930ee0de0d951febca16aab0c37ae3d97c6310fe947e4b9ca","signature":"9b394150e7da3f4e2ccd2b7390db710c22ed3add498475947c9d171a76341488"},{"version":"fe93c474ab38ac02e30e3af073412b4f92b740152cf3a751fdaee8cbea982341","impliedFormat":1},{"version":"476e83e2c9e398265eed2c38773ae9081932b08ea5597b579a7d2e0c690ead56","impliedFormat":1},{"version":"1e00b8bf9e3766c958218cd6144ffe08418286f89ff44ba5a2cc830c03dd22c7","impliedFormat":1},{"version":"6aa2859da46f726a22040725e684ea964d7469a6b26f1c0a6634bb65e79062b0","impliedFormat":99},{"version":"f442b258d40b3cff3cb0eac117886e70680e37c77f20afee08646c1ace6f6ed8","signature":"bf8805d1c9460e86c8913319136ff824429f96aaaec7bc38e43c5671532e8b31"},{"version":"dbdfd4ce41d7ba5d6dffa1e29fc09f73484b9b756a1c30c40b4636c54613166d","signature":"360d41a5be9153ef7b79ce96a4b1aacd718fd818e016a04615627333f0955336"},{"version":"ee95aa560e292c45a2bec24a753621b17cc227b802b39e07723f85ba31a6a89b","signature":"3f3412156504c9713c6755cdfec72ed707600a589fdb3f26ef2cc502dcc8c635"},{"version":"cc9b225182c665bd541a149ce167c0d09ad431ba6346559e397cb2ffe2876cf5","signature":"01a977ade994fe0de990222140f158a0dc3b03529994c449aa39333d0facac02"},{"version":"ceffa7b26340d13fc766a7182fea76f9193f2cd34942037a73c9d3a13edaab19","signature":"f5b5d4d2565e15fa4ea35249f6dfac49afe8d18383b09d6f2732010ea11ff387"},{"version":"a346701ad6dcdaa58e388fe0995fc5304c09c395b8cba68ed872780f8c102004","impliedFormat":99},{"version":"2fbe402f0ee5aa8ab55367f88030f79d46211c0a0f342becaa9f648bf8534e9d","impliedFormat":1},{"version":"b94258ef37e67474ac5522e9c519489a55dcb3d4a8f645e335fc68ea2215fe88","impliedFormat":1},{"version":"71959927c9fc54cd910a5a5998e2dc4c87720305fb3c5759e83e00f90b2e2427","signature":"f28686ca1340b1b485fcf38f4da3aaea094d8ea74689f1d805211351370244ef"},{"version":"2324eaa31cf477112158d5d2d76c48b810e5c05a879652f5345b4a25022df983","signature":"8da31acf55cd3aedcb0285267b0823f8295d3cefe8ef377101ccffc4b0070a0a"},{"version":"3f6475e77093e1d01f4e6bfc131eaeac9880259cd76ac431f42d9f51da15dffc","signature":"8fc67ddd42c820c7ce9d330fd429fbf2da5362b5424f80c2a5f3244f5f50f6c5"},{"version":"e6029614f3aeb25bb63302a9f5b3ce473d481f4b932e5c0c91ff30efd95d63f7","signature":"d9f172cb3bcaf3b28c0d47e0ff5704100f5f00c4ec78c705ae29cd67e614edb3"},{"version":"3369eab97286d546b15ea25f3be22a642669388d4266899641ba4c5480fcddcf","signature":"0e1a01e31948d9dff3699bc0ed40cbbc514b38e6c577102f07486de8556fb431"},{"version":"6717dad91e44ad22d68f1fc0db74e5eb5398c2c06a2943bf06d3a168e8b1ba45","impliedFormat":99},{"version":"a9373d52584b48809ffd61d74f5b3dfd127da846e3c4ee3c415560386df3994b","impliedFormat":99},{"version":"caf4af98bf464ad3e10c46cf7d340556f89197aab0f87f032c7b84eb8ddb24d9","impliedFormat":99},{"version":"7ec047b73f621c526468517fea779fec2007dd05baa880989def59126c98ef79","impliedFormat":99},{"version":"8dd450de6d756cee0761f277c6dc58b0b5a66b8c274b980949318b8cad26d712","impliedFormat":99},{"version":"6b5f886fe41e2e767168e491fe6048398ed6439d44e006d9f51cc31265f08978","impliedFormat":99},{"version":"56a87e37f91f5625eb7d5f8394904f3f1e2a90fb08f347161dc94f1ae586bdd0","impliedFormat":99},{"version":"6b863463764ae572b9ada405bf77aac37b5e5089a3ab420d0862e4471051393b","impliedFormat":99},{"version":"904d6ad970b6bd825449480488a73d9b98432357ab38cf8d31ffd651ae376ff5","impliedFormat":99},{"version":"68b6a7501a56babd7bcd840e0d638ee7ec582f1e70b3c36ebf32e5e5836913c8","impliedFormat":99},{"version":"89783bd45ab35df55203b522f8271500189c3526976af533a599a86caaf31362","impliedFormat":99},{"version":"26e6c521a290630ea31f0205a46a87cab35faac96e2b30606f37bae7bcda4f9d","impliedFormat":99},{"version":"d41d03c2686001b1b6d6d55180e9c667177b8dc955cefeb1542a0bdd7f9998b4","signature":"00e3df429b6777bfbe88ed24c7ce2700f096784bad25fd35a40a1ded854a7246"},{"version":"5295ce90ae1f708d622dd49302a01b8752926fdfcfbe7234b3c088a673ae1c24","signature":"032e21d89cb4aefdf511982fbb001814a4aafb1f8bd4b3b393a8e4cd9100391b"},{"version":"dfcf16e716338e9fe8cf790ac7756f61c85b83b699861df970661e97bf482692","impliedFormat":99},{"version":"53db1175da032d45a7befea771a68fa72d496045cb7342ec0fdc9667009f620e","signature":"4c79714c1e88b8b2acf634bfd51c307598a7bd578361ba0218cd4ba6b2c3a4a1"},{"version":"0d3720c027479fbeb5bd175fb24aeef3505c931bae3eb2403c08399e229a03e5","signature":"73522cd0f60ca6e448fea1e136bbccb79c61df337b6fd39bde0959fbb74e810a"},{"version":"3e7b1911170b1110f25a08194c7ad56d51970c144dc97fcdf7ff3035bcb4e694","signature":"af31a45f488f25ae7b71cde04089f556c984f497aed67a5c642501b7dc0d2825"},"bc85299ca2db2ffc918933afb4f54a163224e1d036668db554396e36020eec19","a033b08a4f1d447a8c6ee028698630cd57a43f5c26ab10c094ee0a04b6a89b20","5842f088ce320da36e8e327ffcf4d9e19293d322b3e567f27da9f08c403fd038",{"version":"248c1fe48d3af06e85d6e173d458df8d493b427ad6595ae6847143ac90aa664b","signature":"04d9be0926c2fe8e191ca2ea604fad0ea05c1b0bfb4cdc4aae92a1458e4e2145"},{"version":"89121c1bf2990f5219bfd802a3e7fc557de447c62058d6af68d6b6348d64499a","impliedFormat":1},{"version":"79b4369233a12c6fa4a07301ecb7085802c98f3a77cf9ab97eee27e1656f82e6","impliedFormat":1},{"version":"2b37ba54ec067598bf912d56fcb81f6d8ad86a045c757e79440bdef97b52fe1b","impliedFormat":99},{"version":"1bc9dd465634109668661f998485a32da369755d9f32b5a55ed64a525566c94b","impliedFormat":99},{"version":"5702b3c2f5d248290ed99419d77ca1cc3e6c29db5847172377659c50e6303768","impliedFormat":99},{"version":"9764b2eb5b4fc0b8951468fb3dbd6cd922d7752343ef5fbf1a7cd3dfcd54a75e","impliedFormat":99},{"version":"1fc2d3fe8f31c52c802c4dee6c0157c5a1d1f6be44ece83c49174e316cf931ad","impliedFormat":99},{"version":"dc4aae103a0c812121d9db1f7a5ea98231801ed405bf577d1c9c46a893177e36","impliedFormat":99},{"version":"106d3f40907ba68d2ad8ce143a68358bad476e1cc4a5c710c11c7dbaac878308","impliedFormat":99},{"version":"42ad582d92b058b88570d5be95393cf0a6c09a29ba9aa44609465b41d39d2534","impliedFormat":99},{"version":"36e051a1e0d2f2a808dbb164d846be09b5d98e8b782b37922a3b75f57ee66698","impliedFormat":99},{"version":"d4a22007b481fe2a2e6bfd3a42c00cd62d41edb36d30fc4697df2692e9891fc8","impliedFormat":1},{"version":"9d62e577adb05f5aafed137e747b3a1b26f8dce7b20f350d22f6fb3255a3c0ed","impliedFormat":99},{"version":"7ed92bcef308af6e3925b3b61c83ad6157a03ff15c7412cf325f24042fe5d363","impliedFormat":99},{"version":"3da9062d0c762c002b7ab88187d72e1978c0224db61832221edc8f4eb0b54414","impliedFormat":99},{"version":"84dbf6af43b0b5ad42c01e332fddf4c690038248140d7c4ccb74a424e9226d4d","impliedFormat":99},{"version":"00884fc0ea3731a9ffecffcde8b32e181b20e1039977a8ae93ae5bce3ab3d245","impliedFormat":99},{"version":"0bd8b6493d9bf244afe133ccb52d32d293de8d08d15437cca2089beed5f5a6b5","impliedFormat":99},{"version":"7fc3099c95752c6e7b0ea215915464c7203e835fcd6878210f2ce4f0dcbbfe67","impliedFormat":99},{"version":"83b5499dbc74ee1add93aef162f7d44b769dcef3a74afb5f80c70f9a5ce77cc0","impliedFormat":99},{"version":"8bf8b772b38fc4da471248320f49a2219c363a9669938c720e0e0a5a2531eabf","impliedFormat":99},{"version":"7da6e8c98eacf084c961e039255f7ebb9d97a43377e7eee2695cb77fec640c66","impliedFormat":99},{"version":"0b5b064c5145a48cd3e2a5d9528c63f49bac55aa4bc5f5b4e68a160066401375","impliedFormat":99},{"version":"702ff40d28906c05d9d60b23e646c2577ad1cc7cd177d5c0791255a2eab13c07","impliedFormat":99},{"version":"49ff0f30d6e757d865ae0b422103f42737234e624815eee2b7f523240aa0c8f8","impliedFormat":99},{"version":"0389aacf0ffd49a877a46814a21a4770f33fc33e99951a1584de866c8e971993","impliedFormat":99},{"version":"5cb7a51cf151c1056b61f078cf80b811e19787d1f29a33a2a6e4bf00334bbc10","impliedFormat":99},{"version":"215aa8915d707f97ad511b7abbf7eda51d3a7048e9a656955cf0dda767ae7db0","impliedFormat":99},{"version":"0d689a717fbef83da07ab4de33f83db5cbcec9bc4e3b04edb106c538a50a0210","impliedFormat":99},{"version":"d00bc73e8d1f4137f2f6238bb3aa2bbdad8573658cc95920e2cdfa7ad491a8d8","impliedFormat":99},{"version":"e3667aa9f5245d1a99fb4a2a1ac48daf1429040c29cc0d262e3843f9ae3b9d65","impliedFormat":99},{"version":"08c0f3222b50ec2b534be1a59392660102549129246425d33ec43f35aa051dc6","impliedFormat":99},{"version":"612fb780f312e6bb3c40f3cb2b827ea7455b922198f651c799d844fdd44cf2e9","impliedFormat":99},{"version":"bcd98e8f44bc76e4fcb41e4b1a8bab648161a942653a3d1f261775a891d258de","impliedFormat":99},{"version":"5abaa19aa91bb4f63ea58154ada5d021e33b1f39aa026ca56eb95f13b12c497a","impliedFormat":99},{"version":"356a18b0c50f297fee148f4a2c64b0affd352cbd6f21c7b6bfa569d30622c693","impliedFormat":99},{"version":"5876027679fd5257b92eb55d62efee634358012b9f25c5711ad02b918e52c837","impliedFormat":99},{"version":"f5622423ee5642dcf2b92d71b37967b458e8df3cf90b468675ff9fddaa532a0f","impliedFormat":99},{"version":"70265bc75baf24ec0d61f12517b91ea711732b9c349fceef71a446c4ff4a247a","impliedFormat":99},{"version":"41a4b2454b2d3a13b4fc4ec57d6a0a639127369f87da8f28037943019705d619","impliedFormat":99},{"version":"e9b82ac7186490d18dffaafda695f5d975dfee549096c0bf883387a8b6c3ab5a","impliedFormat":99},{"version":"eed9b5f5a6998abe0b408db4b8847a46eb401c9924ddc5b24b1cede3ebf4ee8c","impliedFormat":99},{"version":"af85fde8986fdad68e96e871ae2d5278adaf2922d9879043b9313b18fae920b1","impliedFormat":99},{"version":"8a1f5d2f7cf4bf851cc9baae82056c3316d3c6d29561df28aff525556095554b","impliedFormat":99},{"version":"6bd987ccf12886137d96b81e48f65a7a6fa940085753c4e212c91f51555f13e5","impliedFormat":1},{"version":"18eabf10649320878e8725e19ae58f81f44bbbe657099cad5b409850ba3dded9","impliedFormat":99},{"version":"00396c9acf2fbca72816a96ed121c623cdbfe3d55c6f965ea885317c03817336","impliedFormat":99},{"version":"00396c9acf2fbca72816a96ed121c623cdbfe3d55c6f965ea885317c03817336","impliedFormat":99},{"version":"6272df11367d44128113bdf90e9f497ccd315b6c640c271355bdc0a02a01c3ef","impliedFormat":99},{"version":"fc2070279db448f03271d0da3215252946b86330139b85af61c54099d79e922b","impliedFormat":99},{"version":"15ec7a0b94628e74974c04379e20de119398638b3c70f0fa0c76ab92956be77c","impliedFormat":99},{"version":"a5dbd4c9941b614526619bad31047ddd5f504ec4cdad88d6117b549faef34dd3","impliedFormat":99},{"version":"e87873f06fa094e76ac439c7756b264f3c76a41deb8bc7d39c1d30e0f03ef547","impliedFormat":99},{"version":"488861dc4f870c77c2f2f72c1f27a63fa2e81106f308e3fc345581938928f925","impliedFormat":99},{"version":"eff73acfacda1d3e62bb3cb5bc7200bb0257ea0c8857ce45b3fee5bfec38ad12","impliedFormat":99},{"version":"aff4ac6e11917a051b91edbb9a18735fe56bcfd8b1802ea9dbfb394ad8f6ce8e","impliedFormat":99},{"version":"1f68aed2648740ac69c6634c112fcaae4252fbae11379d6eabee09c0fbf00286","impliedFormat":99},{"version":"5e7c2eff249b4a86fb31e6b15e4353c3ddd5c8aefc253f4c3e4d9caeb4a739d4","impliedFormat":99},{"version":"14c8d1819e24a0ccb0aa64f85c61a6436c403eaf44c0e733cdaf1780fed5ec9f","impliedFormat":99},{"version":"d36518bd617ff673c7d9f372706f241932a43f27673187f2a8472e93c40041c6","impliedFormat":99},{"version":"f8eb2909590ec619643841ead2fc4b4b183fbd859848ef051295d35fef9d8469","impliedFormat":99},{"version":"fe784567dd721417e2c4c7c1d7306f4b8611a4f232f5b7ce734382cf34b417d2","impliedFormat":99},{"version":"45d1e8fb4fd3e265b15f5a77866a8e21870eae4c69c473c33289a4b971e93704","impliedFormat":99},{"version":"cd40919f70c875ca07ecc5431cc740e366c008bcbe08ba14b8c78353fb4680df","impliedFormat":99},{"version":"ddfd9196f1f83997873bbe958ce99123f11b062f8309fc09d9c9667b2c284391","impliedFormat":99},{"version":"2999ba314a310f6a333199848166d008d088c6e36d090cbdcc69db67d8ae3154","impliedFormat":99},{"version":"62c1e573cd595d3204dfc02b96eba623020b181d2aa3ce6a33e030bc83bebb41","impliedFormat":99},{"version":"ca1616999d6ded0160fea978088a57df492b6c3f8c457a5879837a7e68d69033","impliedFormat":99},{"version":"835e3d95251bbc48918bb874768c13b8986b87ea60471ad8eceb6e38ddd8845e","impliedFormat":99},{"version":"de54e18f04dbcc892a4b4241b9e4c233cfce9be02ac5f43a631bbc25f479cd84","impliedFormat":99},{"version":"453fb9934e71eb8b52347e581b36c01d7751121a75a5cd1a96e3237e3fd9fc7e","impliedFormat":99},{"version":"bc1a1d0eba489e3eb5c2a4aa8cd986c700692b07a76a60b73a3c31e52c7ef983","impliedFormat":99},{"version":"4098e612efd242b5e203c5c0b9afbf7473209905ab2830598be5c7b3942643d0","impliedFormat":99},{"version":"28410cfb9a798bd7d0327fbf0afd4c4038799b1d6a3f86116dc972e31156b6d2","impliedFormat":99},{"version":"514ae9be6724e2164eb38f2a903ef56cf1d0e6ddb62d0d40f155f32d1317c116","impliedFormat":99},{"version":"970e5e94a9071fd5b5c41e2710c0ef7d73e7f7732911681592669e3f7bd06308","impliedFormat":99},{"version":"491fb8b0e0aef777cec1339cb8f5a1a599ed4973ee22a2f02812dd0f48bd78c1","impliedFormat":99},{"version":"6acf0b3018881977d2cfe4382ac3e3db7e103904c4b634be908f1ade06eb302d","impliedFormat":99},{"version":"2dbb2e03b4b7f6524ad5683e7b5aa2e6aef9c83cab1678afd8467fde6d5a3a92","impliedFormat":99},{"version":"135b12824cd5e495ea0a8f7e29aba52e1adb4581bb1e279fb179304ba60c0a44","impliedFormat":99},{"version":"e4c784392051f4bbb80304d3a909da18c98bc58b093456a09b3e3a1b7b10937f","impliedFormat":99},{"version":"2e87c3480512f057f2e7f44f6498b7e3677196e84e0884618fc9e8b6d6228bed","impliedFormat":99},{"version":"66984309d771b6b085e3369227077da237b40e798570f0a2ddbfea383db39812","impliedFormat":99},{"version":"e41be8943835ad083a4f8a558bd2a89b7fe39619ed99f1880187c75e231d033e","impliedFormat":99},{"version":"260558fff7344e4985cfc78472ae58cbc2487e406d23c1ddaf4d484618ce4cfd","impliedFormat":99},{"version":"413d50bc66826f899c842524e5f50f42d45c8cb3b26fd478a62f26ac8da3d90e","impliedFormat":99},{"version":"d9083e10a491b6f8291c7265555ba0e9d599d1f76282812c399ab7639019f365","impliedFormat":99},{"version":"09de774ebab62974edad71cb3c7c6fa786a3fda2644e6473392bd4b600a9c79c","impliedFormat":99},{"version":"e8bcc823792be321f581fcdd8d0f2639d417894e67604d884c38b699284a1a2a","impliedFormat":99},{"version":"7c99839c518dcf5ab8a741a97c190f0703c0a71e30c6d44f0b7921b0deec9f67","impliedFormat":99},{"version":"44c14e4da99cd71f9fe4e415756585cec74b9e7dc47478a837d5bedfb7db1e04","impliedFormat":99},{"version":"1f46ee2b76d9ae1159deb43d14279d04bcebcb9b75de4012b14b1f7486e36f82","impliedFormat":99},{"version":"2838028b54b421306639f4419606306b940a5c5fcc5bc485954cbb0ab84d90f4","impliedFormat":99},{"version":"7116e0399952e03afe9749a77ceaca29b0e1950989375066a9ddc9cb0b7dd252","impliedFormat":99},{"version":"41567dfdceefafaf62b863ac58f8f671bc8cdbe12fea0feab8b03cd101bcb212","signature":"291d5be0f56e1acf3a8a538e8ae3e68c791c10712284a2599cc6863d70b53480"},"d9fb7bbbdad1a3936d375b6604f98eb5fdc7c74852f7822c2ae0c4bf0c6274ba",{"version":"9c3d9311fc120f70fe9485b28979a8f0e2ebddd767e6e1f3c8fbcd13714f0ca9","signature":"b435316f6e8278cce21440891061ffe84a27d5936dc07fdcff4fbf23403e3959"},{"version":"ba278de4cbeab695f764138964b4ff284bc3ea09b3d3294ec035f3545a485bbf","signature":"727c29e192a5dda5f3b4fd3709eb9885470b8bb695aa695d319ac76faed1ec95"},{"version":"56208c500dcb5f42be7e18e8cb578f257a1a89b94b3280c506818fed06391805","impliedFormat":1},{"version":"0c94c2e497e1b9bcfda66aea239d5d36cd980d12a6d9d59e66f4be1fa3da5d5a","impliedFormat":1},{"version":"eb9271b3c585ea9dc7b19b906a921bf93f30f22330408ffec6df6a22057f3296","impliedFormat":1},{"version":"aa4a927d0c7239dff845a64e676c71aeed2bbda89a7fb486baab22eb7688ba1d","impliedFormat":1},{"version":"340a990742a00862049b378aaa482b5bb8323d443c799dded51ce711f4f8eb51","impliedFormat":1},{"version":"89eeeebbc612a079c6e7ebe0bde08e06fbc46cfeaebf6157ea3051ed55967b10","impliedFormat":1},{"version":"4c72f66622e266b542fb097f4d1fe88eb858b88b98414a13ef3dd901109e03a1","impliedFormat":1},{"version":"23a933d83f3a8d595b35f3827c5e68239fb4f6eb44e96389269d183fe7ff09ba","impliedFormat":1},{"version":"2acad3ae616a9fb5a8c3d4d7bb5edb11d1d0102372ee939e7fc64359fec4046e","impliedFormat":1},{"version":"c812eabb7d2e13c8e72e216208448f92341a4094dd107cbb0bdb2cb23d1a83e7","impliedFormat":1},{"version":"f734b58ea162765ff4d4a36f671ee06da898921e985a2064510f4925ec1ed062","affectsGlobalScope":true,"impliedFormat":1},{"version":"55c0569d0b70dbc0bb9a811469a1e2a7b8e2bab2d70c013f2e40dfb2d2803d05","impliedFormat":1},{"version":"37f96daaddc2dd96712b2e86f3901f477ac01a5c2539b1bc07fd609d62039ee1","impliedFormat":1},{"version":"9c5c84c449a3d74e417343410ba9f1bd8bfeb32abd16945a1b3d0592ded31bc8","impliedFormat":1},{"version":"a7f09d2aaf994dbfd872eda4f2411d619217b04dbe0916202304e7a3d4b0f5f8","impliedFormat":1},{"version":"a66ebe9a1302d167b34d302dd6719a83697897f3104d255fe02ff65c47c5814e","impliedFormat":99},{"version":"a7f23fecdccf1504dae27c359db676d0a1fbaaeb400b55959078924e4c3a4992","impliedFormat":1},{"version":"bee66a62aa1da254412bb2c3c8c1a0dd12efea0722d35cc6ea7b5fdaa6778fd1","impliedFormat":1},{"version":"05d80364872e31465f8a1eaf2697e4fc418f78aa336f4cea68620a23f1379f6f","impliedFormat":1},{"version":"7345ba3b9eb2182d8cdc4c961b62847c3c9918985179ddefd5ca58a80d8b9e6a","impliedFormat":1},{"version":"81c4a0e6de3d5674ec3a721e04b3eb3244180bda86a22c4185ecac0e3f051cd8","impliedFormat":1},{"version":"39975a01d837394bcac2559639e88ecdc4cfd22433327b46ea6f78eb2c584813","impliedFormat":1},{"version":"7261cabedede09ebfd50e135af40be34f76fb9dbc617e129eaec21b00161ae86","impliedFormat":1},{"version":"ea554794a0d4136c5c6ea8f59ae894c3c0848b17848468a63ed5d3a307e148ae","impliedFormat":1},{"version":"2c378d9368abcd2eba8c29b294d40909845f68557bc0b38117e4f04fc56e5f9c","impliedFormat":1},{"version":"9b048390bcffe88c023a4cd742a720b41d4cd7df83bc9270e6f2339bf38de278","affectsGlobalScope":true,"impliedFormat":1},{"version":"c60b14c297cc569c648ddaea70bc1540903b7f4da416edd46687e88a543515a1","impliedFormat":1},{"version":"acfa00e5599216bcb8c9f3095e5fec4aeddfcc65aabe0eac7e8dbc51e33691c9","impliedFormat":1},{"version":"922d8f0f46dbe9fb80def96f7bcd9d5c1a6c0022d71023afa9eb7b45189d61f2","impliedFormat":1},{"version":"90588fb5ef85f4a8a4234e8062eb97bd3c8114dfb86a0c67f62685969222da8b","impliedFormat":1},{"version":"6ce50ada4bc9d2ad69927dce35cead36da337a618de0a2daaaeeafe38c692597","impliedFormat":1},{"version":"13b8d0a9b0493191f15d11a5452e7c523f811583a983852c1c8539ab2cfdae7c","impliedFormat":1},{"version":"8932771f941e3f8f153a950c65707d0611f30f577256aa59d4b92eda1c3d8f32","impliedFormat":1},{"version":"df6251bd4b5fad52759bfe96e8ab8f2ce625d0b6739b825209b263729a9c321e","impliedFormat":1},{"version":"846068dbe466864be6e2cae9993a4e3ac492a5cb05a36d5ce36e98690fde41f4","impliedFormat":1},{"version":"94c8c60f751015c8f38923e0d1ae32dd4780b572660123fa087b0cf9884a68a8","impliedFormat":1},{"version":"db8747c785df161ef65237bac36a7716168e5ebf18976ab16fd2fff69cf9c6ce","impliedFormat":1},{"version":"3085abdf921a6d225ad037c89eb2ba26a4c3b2c262f842dd3061949d1969b784","impliedFormat":1},{"version":"8e8f7b36675be31c4e9538529c30a552538c42ff866ba59fe70f23ba18479c5a","impliedFormat":1},{"version":"f4f7fbf0e5bf2097ddee2c998cca04b063f6f9cdcb255e728c0e85967119f9e5","impliedFormat":1},{"version":"c5b47653a15ec7c0bde956e77e5ca103ddc180d40eb4b311e4a024ef7c668fb0","impliedFormat":1},{"version":"223709d7c096b4e2bb00390775e43481426c370ac8e270de7e4c36d355fc8bc9","impliedFormat":1},{"version":"0528a80462b04f2f2ad8bee604fe9db235db6a359d1208f370a236e23fc0b1e0","impliedFormat":1},{"version":"17fb3716df78592be07500e9a90bd8c9424dd70c6201226886a8e71b9d2af396","impliedFormat":1},{"version":"82ef7d775e89b200380d8a14dc6af6d985a45868478773d98850ea2449f1be56","impliedFormat":1},{"version":"b86720947f763bbb869c2b183f8e58bca9fa089ed8f9c5a1574b2bea18cfbc02","impliedFormat":1},{"version":"fb7e20b94d23d989fa7c7d20fccebef31c1ef2d3d9ca179cadba6516e4e918ad","impliedFormat":1},{"version":"8326f735a1f0d2b4ad20539cda4e0d2e7c5fc0b534e3c0d503d5ed20a5711009","impliedFormat":1},{"version":"8d720cd4ee809af1d81f4ce88f02168568d5fded574d89875afd8fe7afd9549e","impliedFormat":1},{"version":"df87c2628c5567fd71dc0b765c845b0cbfef61e7c2e56961ac527bfb615ea639","impliedFormat":1},{"version":"659a83f1dd901de4198c9c2aa70e4a46a9bd0c41ce8a42ee26f2dbff5e86b1f3","impliedFormat":1},{"version":"1db5c2491eebd894eb9be03408601cddfe1b08357d021aeb86c3fb6c329a7843","impliedFormat":1},{"version":"224f85b48786de61fb0b018fbea89620ebec6289179daa78ed33c0f83014fc75","impliedFormat":1},{"version":"05fbfcb5c5c247a8b8a1d97dd8557c78ead2fff524f0b6380b4ac9d3e35249fb","impliedFormat":1},{"version":"322f70408b4e1f550ecc411869707764d8b28da3608e4422587630b366daf9de","impliedFormat":1},{"version":"acb93abc527fa52eb2adc5602a7c3c0949861f8e4317a187bb5c3372f872eff4","impliedFormat":1},{"version":"c4ef9e9e0fcb14b52c97ce847fb26a446b7d668d9db98a7de915a22c46f44c37","impliedFormat":1},{"version":"0e447b14e81b5b3e5d83cbea58b734850f78fb883f810e46d3dedba1a5124658","impliedFormat":1},{"version":"045f36d3a830b5ae1b7586492e1a2368d0e4b4209fa656f529fd6f6bb9ac7ced","impliedFormat":1},{"version":"929939785efdef0b6781b7d3a7098238ea3af41be010f18d6627fd061b6c9edf","impliedFormat":1},{"version":"fca68ac3b92725dbf3dac3f9fbc80775b66d2a9c642e75595a4a11a2095b3c9a","impliedFormat":1},{"version":"245d13141d7f9ec6edd36b14844b247e0680950c1c3289774d431cbbd47e714e","impliedFormat":1},{"version":"4326dc453ff5bf36ad778e93b7021cdd9abcfc4efe75a5c04032324f404af558","impliedFormat":1},{"version":"27b47fbd2f2d0d3cd44b8c7231c800f8528949cc56f421093e2b829d6976f173","impliedFormat":1},{"version":"0795a213434963328e8b60e65a9d03a88efc138ae171bbcca39d9000c040e7a4","impliedFormat":1},{"version":"fc745bebefc96e2a518a2d559af6850626cada22a75f794fd40a17aae11e2d54","impliedFormat":1},{"version":"2b0fe9ba00d0d593fb475d4204214a0f604ad8a56f22a5f05c378b52205ef36b","impliedFormat":1},{"version":"3d94a259051acf8acd2108cee57ad58fee7f7b278de76a7a5746f0656eecbff6","impliedFormat":1},{"version":"46097d076be332463ea64865c41d232865614cf358a11af75095dd9cef2871cc","impliedFormat":1},{"version":"6e18a70a7c64e6fe578a8f3ecc1dd562cd0bf6843bbf8e65fde37cf63b9a8ea8","impliedFormat":1},{"version":"3f3526aea8d29f0c53f8fb99201c770c87c357b5e87349aca8494bfd0c145c26","impliedFormat":1},{"version":"6ee92d844e5a1c0eb562d110676a3a17f00d2cd2ea2aaaff0a98d7881b9a4041","impliedFormat":1},{"version":"b9dc36d1f7c5c2350feafb55c090127104e59b7d2a20729b286dab00d70e283d","impliedFormat":1},{"version":"45d3f1d53fa99783a5e3c29debb065d6060d0db650a6a1055308a8619bd6b263","impliedFormat":1},{"version":"a14febaf38fd75a88620a0808732cf9841afc403da2dc3de7a6fc9a49d36bdbc","impliedFormat":1},{"version":"6052522a593f094cfee0e99c76312a229cf2d49ac2e75095af83813ec9f4b109","impliedFormat":1},{"version":"a0ceb6ce93981581494bae078b971b17e36b67502a36a056966940377517091d","impliedFormat":1},{"version":"a63ce903dd08c662702e33700a3d28ca66ed21ac0591e1dbf4a0b309ae80e690","impliedFormat":1},{"version":"2b63d2725550866e0f2b56b2394ce001ebf1145cb4b04dc9daa29d73867b878c","impliedFormat":1},{"version":"e885933b92f26fa3204403999eddc61651cd3109faf8bffa4f6b6e558b0ab2fa","impliedFormat":1},{"version":"bd834465d4395ac3d8d55e94bf2a39c1f5e9be719c99340957b3b6a3a85ec66a","impliedFormat":1},{"version":"0b1238c0e3536321ae822c84216614bad2f3a7bd3f1de5c6ec8a85b26d900e6b","impliedFormat":1},{"version":"6e2d2b63c278fd1c8dd54da2328622c964f50afa62978ed1a73ccd85e99a4fc7","impliedFormat":1},{"version":"e151e41c82004cf09b7ea863f591348c9035e0f7a69d4189cbac89cc9611b89d","impliedFormat":1},{"version":"74d62eb5f24ae3e1fa7374380fa6ef354449757293c7434d00b702b1c7f87249","impliedFormat":1},{"version":"b83ffe71adbac91c5596133251e5ec0c9e6664017ee5b776841effe93de8f466","impliedFormat":1},{"version":"61ecf051972c69e7c992bab9cf74c511ecba51b273c4e1590574d97a542bd4ea","impliedFormat":1},{"version":"068f5afbae92a20a5fcd9cfce76f7b90de2c59a952396b5da225b61f95a1d60a","impliedFormat":1},{"version":"bdf5e07a22e661de2c7115e8364b98ef399c24c9fe62035dc1ac945a9dd3372a","impliedFormat":1},{"version":"4e024e2530feda4719448af6bdd0c0c7cfa28d1a4887900f4886bec70cd48fea","impliedFormat":1},{"version":"99c88ea4f93e883d10c04961dbf37c403c4f3c8444948b86effec0bf52176d0e","impliedFormat":1},{"version":"e88f3729fcc3d38d2a1b3cdcbd773d13d72ea3bdf4d0c0c784818e3bfbe7998d","impliedFormat":1},{"version":"f25b1264b694a647593b0a9a044a267098aaf249d646981a7f0503b8bb185352","impliedFormat":1},{"version":"964d0862660f8e46675c83793f42ab2af336f3d6106dee966a4053d5dc433063","impliedFormat":1},{"version":"292ad4203c181f33beb9eb8fe7c6aaae29f62163793278a7ffc2fcc0d0dbed19","impliedFormat":1},{"version":"4e04e6263670ad377f2f6bcd477def099ac3634d760ee8a7cca74a6f39d70a48","impliedFormat":1},{"version":"f1a4ca3688d951daa2d7740da5a0827fa34d4a7709eed7b8225215986ee87108","impliedFormat":1},{"version":"7879a9ca9f953587b6d1471d5b9c7ed0d9852f1a30e9c5b6a7227a7bb7a0894d","impliedFormat":1},{"version":"f8453a3fe0fe49ab718357120bec2b8205e15eb91ff62eada60a4780458fa91e","impliedFormat":1},{"version":"06f186bb9a6408ef8563dbf17d53cbe23e68422518b49b96afac732844ddbaa1","impliedFormat":1},{"version":"525f9c06245b5b43b1237cfd757396fd7fd8090e5d6a4ded758c7ce17a04bf42","impliedFormat":1},{"version":"04bc74b8fa987f140989e9f4d6dc37f04a307417af3e0a3767baa1eef4964e10","impliedFormat":1},{"version":"6a9d3aa58228faa62ec3d9e305f472a24441f22a8d028234577beb592ec295b2","impliedFormat":1},{"version":"683e2d454f64394931d233740b762dabc379e3ce5c4c4ad4747cdbd6d5fd8e8d","impliedFormat":1},{"version":"18594ddc7900f3e477645819bce4d824989ad296e3d70bdcdce13cabc5d97335","impliedFormat":1},{"version":"9376cce4d849f1d6ad2cb0048807c77cfeb78cee6e29b61dcfe74c7ab2980e18","impliedFormat":1},{"version":"2698935791615907eb632186119dfc307363d6a163f26017084009e44ea261f2","impliedFormat":1},{"version":"4edfc4848068bf58016856dfeb27341c15679884575e1a501e2389a1fea5c579","impliedFormat":1},{"version":"0c3d7a094ef401b3c36c8e3d88382a7e7a8b1e4f702769eba861d03db559876b","impliedFormat":1},{"version":"d3c3280f081f28e846239d27c2f77a41417e6a19f39267d20a282fd07ef36b96","impliedFormat":1},{"version":"7e3a4800683a39375bc99f0d53b21328b0a0377ab7cbb732c564ca7ca04d9b37","impliedFormat":1},{"version":"c777b498a93261d6caa5dbd1187090b79f0263a03526c64ea4f844a679e8299e","impliedFormat":1},{"version":"b4677e9d8802a82455a0f03a211b85f5d4b04cfbc89fc9aa691695b8e70df326","impliedFormat":1},{"version":"7cb0d946957daea11f78a31b85de435e00bcd8964eba66d3e8056ba9d14b9c55","impliedFormat":1},{"version":"b3e441cdb9d9e55e6e120052fe8bf2a8b5e5a46287f21d5bc39561594574e1a9","impliedFormat":1},{"version":"0870e8eb0527c044e844a1d83127f020aa7f79048218a62b2875e818355f8cb2","impliedFormat":1},{"version":"6b7446f89f9e5d47835117416e6d7656bac2bf700513d330254ae979260ce99f","impliedFormat":1},{"version":"9750752db342b88df1b860958a20fac9fd6a507f67c5cfb6bd5cfa8759338b1e","impliedFormat":1},{"version":"946de511c5e04659d9dfaf5ef83770122846d26d3ffe30e636d3339482bbf35a","impliedFormat":1},{"version":"fbcc201a8fc377a92714567491e3f81e204750b612d51a1720af452f1a254760","impliedFormat":1},{"version":"6dd704b0ba0131eb9e707aeedc39be6a224b4669544e518217a75eb7f5dd65c2","impliedFormat":1},{"version":"6effa89f483e5c83c0e0063df5f1d8b006d9d0f1de7eed2233886642424dc8fb","impliedFormat":1},{"version":"84a8c844f9562da8994c07b44dd2777178a147e06020c62a7f6e349e695e7149","impliedFormat":1},{"version":"d43130c35762a80da2299f8b59a4321b6e64acfb0b11a36183379b4c7b83314b","impliedFormat":1},{"version":"6bf44b890824799af8e20c0387ffa987e890fac5c5954a3a7352351eefe55d5d","impliedFormat":1},{"version":"892b19153694b7a3c9a69bcedb54e1c8ad3b9fa370076db4d3522838afd2cd60","impliedFormat":1},{"version":"5461fca70947a4d8fa272d3dda4c729317cec825141313352adf33bc94de142a","impliedFormat":1},{"version":"f83afa274e0f11860c6609198ecca220f5df60690923b990ca06cae21771016e","impliedFormat":1},{"version":"af31f37264ea5d5349eec50786ceca75c572ed3be91bdd7cb428fdd8cd14b17c","impliedFormat":1},{"version":"85e4673ec8507aef18afd4a9acfae0294bdfaac29458ede0b8b56f5a63738486","impliedFormat":1},{"version":"40683566071340b03c74d0a4ffa84d49fedb181a691ce04c97e11b231a7deee4","impliedFormat":1},{"version":"81c8ab81daa2286241ad27468d6fc7ad3ecc62da04b18b77ce9b9b437f6b0863","impliedFormat":1},{"version":"f158721f7427976b5510660c8e53389d5033c915496c028558c66caaf3d1db1c","impliedFormat":1},{"version":"8e56db8febfe127a9142435940c9a5a1ad17ddb2b2a6d8e9e8984785a76db1fd","impliedFormat":1},{"version":"6113c2f172a875db117357f0aa35aa7c1b6316516e813977ef98dc3b4b8baf2a","impliedFormat":1},{"version":"f25c9802b1316afbf667dd8fa6db4ed23aa5e7acc076a1054ca45d7bc9c8e811","impliedFormat":1},{"version":"e99285f74c22ad823c0b9fac55316b84144e15eb91830034badd9eb0fafe71bf","impliedFormat":1},"cc2a3159300fb027659a6bf19592571aea2dce3472407f5677d2bfd49955253f",{"version":"7a14bf21ae8a29d64c42173c08f026928daf418bed1b97b37ac4bb2aa197b89b","impliedFormat":99},{"version":"200618fafbcc83451e104d34e229abb1ae23d75d98d831055d4ed93515f3a6d5","signature":"eb7569396fa4507aa7a9c288ea9065bae3df13ff8f9022f3230ad2e6b1c631f9"},"68a3aec9c27057a1f1fba43e913a9155b4638ae457c1a72c1e55aadd0ad229a2",{"version":"1179ef8174e0e4a09d35576199df04803b1db17c0fb35b9326442884bc0b0cce","impliedFormat":99},{"version":"889ffc6e209e8a91f5a36c1977c8893b7289c2fb75fa8565df6e75c919cfd12d","signature":"ecf00309316e77304248c7c9777a2e3f5ea561181d893ce9f9e1ffacfe6561e2"},{"version":"0dadc78cf9d24f322708c0958e650283ea55fea5fdebea71f923171b1309bc7c","signature":"3a8523bfa20e149df671c3166d3c2e0c8e5b9f015b121a6855deedf209096b5e"},{"version":"676054fece6642b17febeea14194592b869abe24c7aaed24a6dc9dcbfaa3e421","signature":"9eb645389308a367856c9885955ccc9768ad1835054c3f6bed7d20fac533b1ac"},{"version":"ffe089f7ed5c30e179e2fc477a758a3f99e0d399fc7d7e5d00e92c94c5e12654","signature":"062164282e3c080676b1bc0c2610254073c40e7004d6e2f7d4c3df5c4b6cf14e"},{"version":"233267a4a036c64aee95f66a0d31e3e0ef048cccc57dd66f9cf87582b38691e4","impliedFormat":99},{"version":"8115381da5e1a8ca8737d2187aa44318823fde35b58844743356d42c6f279805","signature":"fc55c712db00df87b9302b6935a93f2889f9b4d8c28cca6484900a042d5b806f"},{"version":"1408b625f28d76d41104ec514b3e1e3239b52d337848af6301c99414ecbcd146","signature":"cfd4e748db53c9cb83a523d606b79f332c67ec857d78ce35cb67c94d5774d12f"},"1c9b63adf7939c8cdd4fd7c807588922ebcf18dc7f0566bb714dbdc7d93506cb",{"version":"a9373d52584b48809ffd61d74f5b3dfd127da846e3c4ee3c415560386df3994b","impliedFormat":99},{"version":"caf4af98bf464ad3e10c46cf7d340556f89197aab0f87f032c7b84eb8ddb24d9","impliedFormat":99},{"version":"8085954ba165e611c6230596078063627f3656fed3fb68ad1e36a414c4d7599a","impliedFormat":99},{"version":"4d6be6b5cbc8ab78d03df9525e2e530525a92ddcee9d1cd3e6d41edbb13ebe9b","signature":"6e72a040282749eebb1972333714e2e67fd323a7106914e52c592888b076370d"},"2552a31fad45a9ed1bde87e51b038dc0e786cd364b597162263abbf57018949b","e5aff8592b1b4aee301aa04c37e2b3e9a9d6c0776a121bccae27eb21ff290626",{"version":"578c6c63826b7fd74a44578413e4fb0b2e5993af2185f57914c72911ab709fda","signature":"89b0f68f8f0b901f9dfff2b9e7255520283a783d6af7f2bc2953d771232317a2"},{"version":"d922c7839dab5c0f6032bdd9fe5a7b585df0efd7a67cb0e0becefba94d1b3626","signature":"89b0f68f8f0b901f9dfff2b9e7255520283a783d6af7f2bc2953d771232317a2"},{"version":"f30a84146380a6c2d1a5482c66057eb8b2f13723a324e6c2f46fe5d571f7fe95","signature":"89b0f68f8f0b901f9dfff2b9e7255520283a783d6af7f2bc2953d771232317a2"},{"version":"2f9fa88569546796e854584f4a96b68f77724c76bc9cde8d64da5412332a9308","signature":"89b0f68f8f0b901f9dfff2b9e7255520283a783d6af7f2bc2953d771232317a2"},{"version":"c8ecd00073b6990bc3588d80b87a097f1bb4ef30b03bfc4b061285e93e28e501","signature":"89b0f68f8f0b901f9dfff2b9e7255520283a783d6af7f2bc2953d771232317a2"},{"version":"092289e7d51313d59b7608d5cdd8a8d6f35d4a28cefd8bf3e379ce0322b9362c","signature":"89b0f68f8f0b901f9dfff2b9e7255520283a783d6af7f2bc2953d771232317a2"},{"version":"133c805e07ab783fdd5877467f903642adee90e65ef81493a5a9a3295b8a1060","signature":"89b0f68f8f0b901f9dfff2b9e7255520283a783d6af7f2bc2953d771232317a2"},{"version":"822bb1ef691615028fe661b26c83a244848d38d6dd4ada96ae3e2f845a03622e","signature":"89b0f68f8f0b901f9dfff2b9e7255520283a783d6af7f2bc2953d771232317a2"},{"version":"83ae447971ee79ac1bdff484c464e3ab8e2bcaa2d325bb187da239ce8e24f21f","signature":"89b0f68f8f0b901f9dfff2b9e7255520283a783d6af7f2bc2953d771232317a2"},{"version":"c873b71f6b83f58896e3f61bf2ee528b75e8d8b67f1bf5d4ef8193b9b00431fc","signature":"89b0f68f8f0b901f9dfff2b9e7255520283a783d6af7f2bc2953d771232317a2"},"2578798f4302e5178562b5f3021a0d86a298a1f1f59a956b38b7d7e401757160","54ccdebfeb03da1eefac67c47b12e4596c573314f3ad23b03140df576b8eb7f1",{"version":"a3e6f5e47814f6170c003af6e76eba034e04b5119cc80c926b61592cbe8e4437","signature":"89b0f68f8f0b901f9dfff2b9e7255520283a783d6af7f2bc2953d771232317a2"},{"version":"b1538a92b9bae8d230267210c5db38c2eb6bdb352128a3ce3aa8c6acf9fc9622","impliedFormat":1},{"version":"6fc1a4f64372593767a9b7b774e9b3b92bf04e8785c3f9ea98973aa9f4bbe490","impliedFormat":1},{"version":"ff09b6fbdcf74d8af4e131b8866925c5e18d225540b9b19ce9485ca93e574d84","impliedFormat":1},{"version":"d5895252efa27a50f134a9b580aa61f7def5ab73d0a8071f9b5bf9a317c01c2d","impliedFormat":1},{"version":"1f366bde16e0513fa7b64f87f86689c4d36efd85afce7eb24753e9c99b91c319","impliedFormat":1},{"version":"fb893a0dfc3c9fb0f9ca93d0648694dd95f33cbad2c0f2c629f842981dfd4e2e","impliedFormat":1},{"version":"3eb11dbf3489064a47a2e1cf9d261b1f100ef0b3b50ffca6c44dd99d6dd81ac1","impliedFormat":1},{"version":"5d08a179b846f5ee674624b349ebebe2121c455e3a265dc93da4e8d9e89722b4","impliedFormat":1},{"version":"f3d8c757e148ad968f0d98697987db363070abada5f503da3c06aefd9d4248c1","impliedFormat":1},{"version":"96d14f21b7652903852eef49379d04dbda28c16ed36468f8c9fa08f7c14c9538","impliedFormat":1},{"version":"7fa8d75d229eeaee235a801758d9c694e94405013fe77d5d1dd8e3201fc414f1","impliedFormat":1}],"root":[83,501,502,504,592,593,606,607,1130,1131,1133,[1136,1142],1167,1168,[1173,1177],[1181,1185],1198,1199,[1201,1207],[1302,1305],1443,1445,1446,[1448,1451],[1453,1455],[1459,1474]],"options":{"allowJs":true,"esModuleInterop":true,"jsx":1,"module":99,"skipLibCheck":true,"strict":true,"target":4},"referencedMap":[[1464,1],[1465,2],[1466,3],[1467,4],[1468,5],[1469,6],[1470,7],[1471,8],[1462,9],[1463,10],[1473,11],[1474,12],[1472,13],[1460,14],[83,15],[1461,16],[501,17],[502,18],[1128,19],[1127,20],[587,21],[585,15],[1020,22],[1037,23],[1038,24],[990,22],[988,22],[997,25],[1022,15],[609,15],[986,26],[987,22],[1007,22],[1035,15],[1039,27],[687,15],[248,15],[1129,28],[1126,15],[1191,29],[1458,30],[1456,31],[1457,31],[1187,31],[1200,32],[1189,29],[1197,33],[1190,29],[1196,34],[1193,35],[1194,29],[1188,31],[1195,36],[1447,37],[1178,38],[1444,39],[1452,40],[1192,15],[1321,41],[1320,15],[1317,15],[721,15],[590,42],[586,21],[588,43],[589,21],[574,44],[1475,15],[1476,15],[1477,15],[1478,45],[1330,15],[1307,46],[1331,47],[1306,15],[1479,15],[1481,48],[572,15],[1482,49],[518,15],[1209,50],[503,51],[1483,15],[1484,15],[1219,50],[1480,15],[145,52],[146,52],[147,23],[100,53],[148,54],[149,55],[150,56],[95,15],[98,57],[96,15],[97,15],[151,58],[152,59],[153,60],[154,61],[155,62],[156,63],[157,63],[158,64],[159,65],[160,66],[161,67],[101,15],[99,15],[162,68],[163,69],[164,70],[198,71],[165,72],[166,15],[167,73],[168,74],[120,75],[130,76],[119,75],[140,77],[111,78],[110,79],[139,80],[133,81],[138,82],[113,83],[127,84],[112,85],[136,86],[108,87],[107,80],[137,88],[109,89],[114,90],[115,15],[118,90],[105,15],[141,91],[131,92],[122,93],[123,94],[125,95],[121,96],[124,97],[134,80],[116,98],[117,99],[126,100],[106,101],[129,92],[128,90],[132,15],[135,102],[169,103],[170,104],[171,105],[172,106],[173,107],[174,108],[175,109],[176,109],[177,110],[178,15],[179,111],[180,112],[182,113],[181,114],[183,115],[184,116],[185,117],[186,118],[187,119],[188,120],[189,121],[190,122],[191,123],[192,124],[193,125],[194,126],[195,127],[102,15],[103,15],[104,15],[142,128],[143,15],[144,15],[196,129],[197,130],[202,131],[358,31],[203,132],[201,133],[360,134],[359,135],[199,136],[356,15],[200,137],[84,15],[86,138],[355,31],[266,31],[1208,15],[1485,15],[591,139],[514,140],[561,141],[559,15],[560,15],[506,15],[556,142],[553,143],[554,144],[575,145],[566,15],[569,146],[568,147],[580,147],[567,148],[505,15],[513,149],[555,149],[508,150],[511,151],[562,150],[512,152],[507,15],[573,15],[1135,153],[1134,15],[994,15],[1125,154],[1124,155],[1021,156],[1006,157],[1004,15],[1005,158],[1008,159],[1009,160],[1010,161],[1011,162],[1019,163],[1012,162],[1013,160],[1014,164],[1015,161],[1016,162],[1017,161],[1018,161],[1031,165],[1032,166],[1029,167],[1166,168],[1165,169],[1144,170],[1143,171],[1030,172],[991,155],[992,155],[993,173],[989,174],[995,175],[996,27],[1028,176],[998,177],[1025,178],[1026,179],[1027,180],[1042,181],[1132,158],[1033,169],[1043,182],[1044,183],[1145,27],[1047,184],[1146,185],[1048,186],[1045,15],[1046,187],[1147,188],[1051,189],[1049,15],[1050,190],[1148,191],[1054,192],[1052,173],[1053,193],[1055,158],[1056,15],[1058,194],[1057,195],[1149,196],[1059,161],[1150,197],[1061,198],[1151,199],[1063,200],[1062,169],[1152,201],[1072,202],[1073,203],[1065,203],[1071,204],[1066,203],[1067,203],[1068,203],[1069,203],[1070,203],[1064,205],[1074,169],[1123,206],[1153,207],[1080,208],[1075,15],[1077,209],[1076,210],[1078,211],[1079,212],[1154,15],[1081,158],[1155,213],[1082,214],[1086,215],[1156,216],[1087,217],[1088,214],[1157,218],[1085,219],[1083,220],[1084,221],[1158,222],[1089,160],[1159,223],[1090,161],[1091,224],[1092,225],[1116,226],[1110,227],[1113,228],[1161,229],[1114,15],[1117,230],[1122,231],[1160,232],[1115,233],[1118,234],[1119,235],[1120,234],[1121,235],[1111,236],[1112,237],[1162,238],[1095,239],[1093,15],[1094,240],[1163,241],[1098,242],[1096,15],[1097,15],[1099,160],[1106,243],[1104,15],[1105,244],[1103,245],[1100,15],[1101,246],[1102,247],[1164,248],[1107,15],[1109,249],[1108,173],[1001,250],[999,251],[1023,252],[608,15],[1002,253],[1024,254],[1000,255],[1003,169],[1034,15],[1036,256],[1060,15],[720,257],[719,15],[1180,258],[1179,259],[604,15],[85,15],[1436,15],[523,15],[600,260],[602,261],[601,262],[599,263],[598,15],[1252,264],[1361,15],[718,265],[689,266],[698,266],[690,266],[699,266],[691,266],[692,266],[706,266],[705,266],[707,266],[708,266],[700,266],[693,266],[701,266],[694,266],[702,266],[695,266],[697,266],[704,266],[703,266],[709,266],[696,266],[710,266],[715,266],[716,266],[711,266],[688,15],[717,15],[713,266],[712,266],[714,266],[813,15],[935,267],[814,268],[815,269],[954,270],[955,271],[956,272],[957,273],[958,274],[959,275],[947,276],[942,277],[943,278],[944,279],[946,274],[945,280],[941,276],[948,277],[950,281],[949,282],[940,274],[939,283],[953,276],[936,277],[937,284],[938,285],[952,274],[951,286],[816,277],[811,287],[932,288],[812,289],[934,290],[933,291],[839,292],[836,293],[896,294],[874,295],[853,296],[781,297],[972,298],[918,299],[961,300],[960,268],[738,301],[747,302],[751,303],[860,304],[771,305],[742,306],[753,307],[850,305],[830,305],[865,308],[929,305],[724,309],[768,309],[737,310],[725,309],[798,305],[776,311],[777,312],[746,313],[755,314],[756,309],[757,315],[759,316],[789,317],[822,305],[924,305],[726,305],[805,318],[739,319],[748,309],[750,320],[790,309],[791,321],[792,322],[793,322],[783,323],[786,324],[743,325],[760,305],[926,305],[727,305],[761,305],[762,326],[763,305],[723,305],[802,327],[765,328],[869,329],[867,305],[868,330],[870,331],[766,305],[923,305],[928,305],[797,332],[749,301],[767,305],[799,333],[800,334],[764,305],[780,305],[968,335],[930,336],[722,15],[831,305],[801,305],[851,305],[769,337],[770,338],[794,305],[859,339],[852,305],[857,340],[858,341],[744,342],[897,305],[806,343],[741,305],[773,344],[736,345],[807,322],[740,319],[752,309],[795,346],[728,309],[772,305],[779,305],[788,347],[775,348],[784,305],[774,349],[729,322],[787,305],[927,305],[925,305],[745,342],[803,350],[804,305],[758,305],[785,305],[898,351],[796,305],[754,305],[778,352],[834,353],[856,354],[841,15],[823,355],[820,356],[910,357],[875,358],[844,359],[899,360],[838,361],[913,362],[843,363],[861,364],[876,365],[901,366],[916,367],[873,368],[840,369],[848,370],[837,371],[872,372],[971,373],[911,374],[900,375],[832,376],[909,377],[962,378],[963,378],[967,379],[966,380],[817,381],[965,378],[964,378],[863,382],[866,383],[908,384],[907,385],[731,15],[864,386],[847,387],[905,388],[730,15],[835,389],[871,390],[912,391],[734,15],[846,392],[903,393],[854,394],[842,395],[904,396],[862,397],[902,398],[829,399],[855,400],[906,401],[732,15],[845,402],[809,403],[931,404],[810,405],[914,406],[921,407],[922,408],[920,409],[888,410],[818,411],[889,412],[919,413],[825,414],[827,415],[877,416],[881,417],[828,418],[826,418],[880,419],[821,420],[882,421],[883,422],[884,423],[892,424],[890,425],[885,426],[886,427],[887,428],[893,429],[891,430],[824,431],[879,432],[894,433],[895,434],[878,435],[833,436],[819,287],[782,437],[969,438],[970,15],[915,439],[917,291],[808,15],[849,15],[733,15],[735,440],[546,15],[548,441],[547,15],[1256,442],[1254,264],[1255,264],[1253,443],[1186,31],[1295,15],[1269,444],[1268,445],[1267,446],[1294,447],[1293,448],[1297,449],[1296,450],[1299,451],[1298,452],[1247,453],[1221,454],[1222,455],[1223,455],[1224,455],[1225,455],[1226,455],[1227,455],[1228,455],[1229,455],[1230,455],[1231,455],[1245,456],[1232,455],[1233,455],[1234,455],[1235,455],[1236,455],[1237,455],[1238,455],[1239,455],[1241,455],[1242,455],[1240,455],[1243,455],[1244,455],[1246,455],[1220,457],[1292,458],[1272,459],[1273,459],[1274,459],[1275,459],[1276,459],[1277,459],[1278,460],[1280,459],[1279,459],[1291,461],[1281,459],[1283,459],[1282,459],[1285,459],[1284,459],[1286,459],[1287,459],[1288,459],[1289,459],[1290,459],[1271,459],[1270,462],[1262,463],[1260,464],[1261,464],[1265,465],[1263,464],[1264,464],[1266,464],[1259,15],[973,15],[976,466],[978,467],[980,468],[979,469],[981,470],[985,471],[982,466],[983,469],[984,469],[975,469],[974,472],[977,15],[93,473],[447,474],[452,14],[454,475],[224,476],[252,477],[430,478],[247,479],[235,15],[216,15],[222,15],[420,480],[283,481],[223,15],[389,482],[257,483],[258,484],[354,485],[417,486],[372,487],[424,488],[425,489],[423,490],[422,15],[421,491],[254,492],[225,493],[304,15],[305,494],[220,15],[236,495],[226,496],[288,495],[285,495],[209,495],[250,497],[249,15],[429,498],[439,15],[215,15],[330,499],[331,500],[325,31],[475,15],[333,15],[334,501],[326,502],[481,503],[479,504],[474,15],[416,505],[415,15],[473,506],[327,31],[368,507],[366,508],[476,15],[480,15],[478,509],[477,15],[367,510],[468,511],[471,512],[295,513],[294,514],[293,515],[484,31],[292,516],[277,15],[487,15],[1170,517],[1169,15],[490,15],[489,31],[491,518],[205,15],[426,519],[427,520],[428,521],[238,15],[214,522],[204,15],[346,31],[207,523],[345,524],[344,525],[335,15],[336,15],[343,15],[338,15],[341,526],[337,15],[339,527],[342,528],[340,527],[221,15],[212,15],[213,495],[267,529],[268,530],[265,531],[263,532],[264,533],[260,15],[352,501],[374,501],[446,534],[455,535],[459,536],[433,537],[432,15],[280,15],[492,538],[442,539],[328,540],[329,541],[320,542],[310,15],[351,543],[311,544],[353,545],[348,546],[347,15],[349,15],[365,547],[434,548],[435,549],[313,550],[317,551],[308,552],[412,553],[441,554],[287,555],[390,556],[210,557],[440,558],[206,479],[261,15],[269,559],[401,560],[259,15],[400,561],[94,15],[395,562],[237,15],[306,563],[391,15],[211,15],[270,15],[399,564],[219,15],[275,565],[316,566],[431,567],[315,15],[398,15],[262,15],[403,568],[404,569],[217,15],[406,570],[408,571],[407,572],[240,15],[397,557],[410,573],[396,574],[402,575],[228,15],[231,15],[229,15],[233,15],[230,15],[232,15],[234,576],[227,15],[382,577],[381,15],[387,578],[383,579],[386,580],[385,580],[388,578],[384,579],[274,581],[375,582],[438,583],[494,15],[463,584],[465,585],[312,15],[464,586],[436,548],[493,587],[332,548],[218,15],[314,588],[271,589],[272,590],[273,591],[303,592],[411,592],[289,592],[376,593],[290,593],[256,594],[255,15],[380,595],[379,596],[378,597],[377,598],[437,599],[324,600],[362,601],[323,602],[357,603],[361,604],[419,605],[418,606],[414,607],[371,608],[373,609],[370,610],[409,611],[364,15],[451,15],[363,612],[413,15],[276,613],[309,519],[307,614],[278,615],[281,616],[488,15],[279,617],[282,617],[449,15],[448,15],[450,15],[486,15],[284,618],[322,31],[92,15],[369,619],[253,15],[242,620],[318,15],[457,31],[467,621],[302,31],[461,501],[301,622],[444,623],[300,621],[208,15],[469,624],[298,31],[299,31],[291,15],[241,15],[297,625],[296,626],[239,627],[319,108],[286,108],[405,15],[393,628],[392,15],[453,15],[350,629],[321,31],[445,630],[87,31],[90,631],[91,632],[88,31],[89,15],[251,633],[246,634],[245,15],[244,635],[243,15],[443,636],[456,637],[458,638],[460,639],[1171,640],[462,641],[466,642],[500,643],[470,643],[499,644],[472,645],[482,646],[483,647],[485,648],[495,649],[498,522],[497,15],[496,80],[541,650],[539,651],[540,652],[528,653],[529,651],[536,654],[527,655],[532,656],[542,15],[533,657],[538,658],[544,659],[543,660],[526,661],[534,662],[535,663],[530,664],[537,650],[531,665],[1251,666],[1250,667],[1347,15],[1345,668],[1349,669],[1416,670],[1411,671],[1314,672],[1382,673],[1375,674],[1432,675],[1312,676],[1381,677],[1370,678],[1415,679],[1412,680],[1364,681],[1374,682],[1417,683],[1418,683],[1419,684],[1427,685],[1421,685],[1429,685],[1433,685],[1420,685],[1422,685],[1425,685],[1428,685],[1424,686],[1426,685],[1430,687],[1423,688],[1324,689],[1396,31],[1393,690],[1397,31],[1335,685],[1325,685],[1388,691],[1313,692],[1334,693],[1338,694],[1395,685],[1310,31],[1394,695],[1392,31],[1391,685],[1326,31],[1438,696],[1406,688],[1386,697],[1442,698],[1404,15],[1402,15],[1407,699],[1405,700],[1401,701],[1403,702],[1408,703],[1410,704],[1400,31],[1333,705],[1309,685],[1399,685],[1348,706],[1398,31],[1373,705],[1431,685],[1366,707],[1322,708],[1327,709],[1376,710],[1378,707],[1357,711],[1360,707],[1339,712],[1359,713],[1368,714],[1369,715],[1365,716],[1379,717],[1367,718],[1344,719],[1387,720],[1383,721],[1384,722],[1380,723],[1358,724],[1346,725],[1351,726],[1328,727],[1355,728],[1356,729],[1352,730],[1329,731],[1340,732],[1377,715],[1323,733],[1385,15],[1350,734],[1343,735],[1371,15],[1440,736],[1441,737],[1413,15],[1439,738],[1434,15],[1362,15],[1336,15],[1409,739],[1363,15],[1315,738],[1437,740],[1342,741],[1372,742],[1341,743],[1414,744],[1353,15],[1389,15],[1390,745],[1337,15],[1354,15],[1435,15],[1311,31],[1319,746],[1316,15],[1258,747],[1257,748],[1301,749],[1300,750],[1249,751],[1248,752],[1318,15],[520,753],[519,49],[394,754],[1172,31],[525,15],[605,15],[576,15],[509,15],[510,755],[1216,756],[1215,15],[81,15],[82,15],[13,15],[14,15],[16,15],[15,15],[2,15],[17,15],[18,15],[19,15],[20,15],[21,15],[22,15],[23,15],[24,15],[3,15],[25,15],[26,15],[4,15],[27,15],[31,15],[28,15],[29,15],[30,15],[32,15],[33,15],[34,15],[5,15],[35,15],[36,15],[37,15],[38,15],[6,15],[42,15],[39,15],[40,15],[41,15],[43,15],[7,15],[44,15],[49,15],[50,15],[45,15],[46,15],[47,15],[48,15],[8,15],[54,15],[51,15],[52,15],[53,15],[55,15],[9,15],[56,15],[57,15],[58,15],[60,15],[59,15],[61,15],[62,15],[10,15],[63,15],[64,15],[65,15],[11,15],[66,15],[67,15],[68,15],[69,15],[70,15],[1,15],[71,15],[72,15],[12,15],[76,15],[74,15],[79,15],[78,15],[73,15],[77,15],[75,15],[80,15],[1218,757],[1214,15],[1217,758],[1211,759],[1210,50],[1213,760],[1212,761],[1308,762],[1332,763],[578,764],[564,765],[565,764],[563,15],[516,766],[552,767],[522,768],[517,766],[515,15],[521,769],[550,15],[545,15],[549,770],[524,15],[551,771],[584,772],[577,773],[570,774],[579,775],[558,776],[595,777],[596,778],[581,779],[597,780],[582,781],[571,782],[594,783],[583,784],[603,785],[557,15],[686,786],[680,787],[684,788],[681,788],[677,787],[685,789],[682,790],[1040,786],[683,788],[678,791],[679,792],[673,793],[617,794],[619,795],[672,15],[618,796],[676,797],[675,798],[674,799],[610,15],[620,794],[621,15],[612,800],[616,801],[611,15],[613,802],[614,803],[615,15],[1041,804],[622,805],[623,805],[624,805],[625,805],[626,805],[627,805],[628,805],[629,805],[630,805],[631,805],[632,805],[633,805],[634,805],[636,805],[635,805],[637,805],[638,805],[639,805],[640,805],[671,806],[641,805],[642,805],[643,805],[644,805],[645,805],[646,805],[647,805],[648,805],[649,805],[650,805],[651,805],[652,805],[653,805],[655,805],[654,805],[656,805],[657,805],[658,805],[659,805],[660,805],[661,805],[662,805],[663,805],[664,805],[665,805],[666,805],[667,805],[670,805],[668,805],[669,805],[504,807],[607,808],[1184,809],[1185,810],[1133,811],[1136,812],[1137,813],[1138,814],[1139,814],[1140,815],[1176,816],[1177,817],[1446,818],[1449,819],[1204,820],[1175,821],[1304,822],[1305,823],[1203,824],[1450,825],[1174,826],[1302,827],[1451,828],[1454,829],[1206,830],[1303,831],[1455,832],[1205,833],[1443,834],[1199,835],[1459,836],[1207,837],[1181,838],[1183,839],[1201,840],[1198,841],[1182,839],[1448,842],[1173,843],[1445,844],[1202,839],[1453,845],[1142,846],[1167,847],[1131,848],[1130,849],[1141,15],[1168,31],[606,850],[593,851],[592,852]],"affectedFilesPendingEmit":[1464,1465,1466,1467,1468,1469,1470,1471,1462,1463,1473,1474,1472,1461,502,504,607,1184,1185,1133,1136,1137,1138,1139,1140,1176,1177,1446,1449,1204,1175,1304,1305,1203,1450,1174,1302,1451,1454,1206,1303,1455,1205,1443,1199,1459,1207,1181,1183,1201,1198,1182,1448,1173,1445,1202,1453,1142,1167,1131,1130,1141,1168,606,593,592],"version":"5.9.3"}
\ No newline at end of file
diff --git a/frontend/vitest.config.ts b/frontend/vitest.config.ts
new file mode 100644
index 0000000..5b4e547
--- /dev/null
+++ b/frontend/vitest.config.ts
@@ -0,0 +1,15 @@
+import { defineConfig } from "vitest/config";
+import react from "@vitejs/plugin-react";
+import path from "path";
+
+export default defineConfig({
+ plugins: [react()],
+ resolve: {
+ alias: {
+ "@": path.resolve(__dirname, "./src"),
+ },
+ },
+ test: {
+ environment: "node",
+ },
+});
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
new file mode 100644
index 0000000..23318d5
--- /dev/null
+++ b/frontend/yarn.lock
@@ -0,0 +1,8632 @@
+# This file is generated by running "yarn install" inside your project.
+# Manual changes might be lost - proceed with caution!
+
+__metadata:
+ version: 8
+ cacheKey: 10c0
+
+"@alloc/quick-lru@npm:^5.2.0":
+ version: 5.2.0
+ resolution: "@alloc/quick-lru@npm:5.2.0"
+ checksum: 10c0/7b878c48b9d25277d0e1a9b8b2f2312a314af806b4129dc902f2bc29ab09b58236e53964689feec187b28c80d2203aff03829754773a707a8a5987f1b7682d92
+ languageName: node
+ linkType: hard
+
+"@babel/code-frame@npm:^7.28.6, @babel/code-frame@npm:^7.29.0":
+ version: 7.29.0
+ resolution: "@babel/code-frame@npm:7.29.0"
+ dependencies:
+ "@babel/helper-validator-identifier": "npm:^7.28.5"
+ js-tokens: "npm:^4.0.0"
+ picocolors: "npm:^1.1.1"
+ checksum: 10c0/d34cc504e7765dfb576a663d97067afb614525806b5cad1a5cc1a7183b916fec8ff57fa233585e3926fd5a9e6b31aae6df91aa81ae9775fb7a28f658d3346f0d
+ languageName: node
+ linkType: hard
+
+"@babel/compat-data@npm:^7.28.6":
+ version: 7.29.0
+ resolution: "@babel/compat-data@npm:7.29.0"
+ checksum: 10c0/08f348554989d23aa801bf1405aa34b15e841c0d52d79da7e524285c77a5f9d298e70e11d91cc578d8e2c9542efc586d50c5f5cf8e1915b254a9dcf786913a94
+ languageName: node
+ linkType: hard
+
+"@babel/core@npm:^7.28.0":
+ version: 7.29.0
+ resolution: "@babel/core@npm:7.29.0"
+ dependencies:
+ "@babel/code-frame": "npm:^7.29.0"
+ "@babel/generator": "npm:^7.29.0"
+ "@babel/helper-compilation-targets": "npm:^7.28.6"
+ "@babel/helper-module-transforms": "npm:^7.28.6"
+ "@babel/helpers": "npm:^7.28.6"
+ "@babel/parser": "npm:^7.29.0"
+ "@babel/template": "npm:^7.28.6"
+ "@babel/traverse": "npm:^7.29.0"
+ "@babel/types": "npm:^7.29.0"
+ "@jridgewell/remapping": "npm:^2.3.5"
+ convert-source-map: "npm:^2.0.0"
+ debug: "npm:^4.1.0"
+ gensync: "npm:^1.0.0-beta.2"
+ json5: "npm:^2.2.3"
+ semver: "npm:^6.3.1"
+ checksum: 10c0/5127d2e8e842ae409e11bcbb5c2dff9874abf5415e8026925af7308e903f4f43397341467a130490d1a39884f461bc2b67f3063bce0be44340db89687fd852aa
+ languageName: node
+ linkType: hard
+
+"@babel/generator@npm:^7.29.0":
+ version: 7.29.1
+ resolution: "@babel/generator@npm:7.29.1"
+ dependencies:
+ "@babel/parser": "npm:^7.29.0"
+ "@babel/types": "npm:^7.29.0"
+ "@jridgewell/gen-mapping": "npm:^0.3.12"
+ "@jridgewell/trace-mapping": "npm:^0.3.28"
+ jsesc: "npm:^3.0.2"
+ checksum: 10c0/349086e6876258ef3fb2823030fee0f6c0eb9c3ebe35fc572e16997f8c030d765f636ddc6299edae63e760ea6658f8ee9a2edfa6d6b24c9a80c917916b973551
+ languageName: node
+ linkType: hard
+
+"@babel/helper-compilation-targets@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/helper-compilation-targets@npm:7.28.6"
+ dependencies:
+ "@babel/compat-data": "npm:^7.28.6"
+ "@babel/helper-validator-option": "npm:^7.27.1"
+ browserslist: "npm:^4.24.0"
+ lru-cache: "npm:^5.1.1"
+ semver: "npm:^6.3.1"
+ checksum: 10c0/3fcdf3b1b857a1578e99d20508859dbd3f22f3c87b8a0f3dc540627b4be539bae7f6e61e49d931542fe5b557545347272bbdacd7f58a5c77025a18b745593a50
+ languageName: node
+ linkType: hard
+
+"@babel/helper-globals@npm:^7.28.0":
+ version: 7.28.0
+ resolution: "@babel/helper-globals@npm:7.28.0"
+ checksum: 10c0/5a0cd0c0e8c764b5f27f2095e4243e8af6fa145daea2b41b53c0c1414fe6ff139e3640f4e2207ae2b3d2153a1abd346f901c26c290ee7cb3881dd922d4ee9232
+ languageName: node
+ linkType: hard
+
+"@babel/helper-module-imports@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/helper-module-imports@npm:7.28.6"
+ dependencies:
+ "@babel/traverse": "npm:^7.28.6"
+ "@babel/types": "npm:^7.28.6"
+ checksum: 10c0/b49d8d8f204d9dbfd5ac70c54e533e5269afb3cea966a9d976722b13e9922cc773a653405f53c89acb247d5aebdae4681d631a3ae3df77ec046b58da76eda2ac
+ languageName: node
+ linkType: hard
+
+"@babel/helper-module-transforms@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/helper-module-transforms@npm:7.28.6"
+ dependencies:
+ "@babel/helper-module-imports": "npm:^7.28.6"
+ "@babel/helper-validator-identifier": "npm:^7.28.5"
+ "@babel/traverse": "npm:^7.28.6"
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: 10c0/6f03e14fc30b287ce0b839474b5f271e72837d0cafe6b172d759184d998fbee3903a035e81e07c2c596449e504f453463d58baa65b6f40a37ded5bec74620b2b
+ languageName: node
+ linkType: hard
+
+"@babel/helper-plugin-utils@npm:^7.27.1":
+ version: 7.28.6
+ resolution: "@babel/helper-plugin-utils@npm:7.28.6"
+ checksum: 10c0/3f5f8acc152fdbb69a84b8624145ff4f9b9f6e776cb989f9f968f8606eb7185c5c3cfcf3ba08534e37e1e0e1c118ac67080610333f56baa4f7376c99b5f1143d
+ languageName: node
+ linkType: hard
+
+"@babel/helper-string-parser@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/helper-string-parser@npm:7.27.1"
+ checksum: 10c0/8bda3448e07b5583727c103560bcf9c4c24b3c1051a4c516d4050ef69df37bb9a4734a585fe12725b8c2763de0a265aa1e909b485a4e3270b7cfd3e4dbe4b602
+ languageName: node
+ linkType: hard
+
+"@babel/helper-validator-identifier@npm:^7.28.5":
+ version: 7.28.5
+ resolution: "@babel/helper-validator-identifier@npm:7.28.5"
+ checksum: 10c0/42aaebed91f739a41f3d80b72752d1f95fd7c72394e8e4bd7cdd88817e0774d80a432451bcba17c2c642c257c483bf1d409dd4548883429ea9493a3bc4ab0847
+ languageName: node
+ linkType: hard
+
+"@babel/helper-validator-option@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/helper-validator-option@npm:7.27.1"
+ checksum: 10c0/6fec5f006eba40001a20f26b1ef5dbbda377b7b68c8ad518c05baa9af3f396e780bdfded24c4eef95d14bb7b8fd56192a6ed38d5d439b97d10efc5f1a191d148
+ languageName: node
+ linkType: hard
+
+"@babel/helpers@npm:^7.28.6":
+ version: 7.29.2
+ resolution: "@babel/helpers@npm:7.29.2"
+ dependencies:
+ "@babel/template": "npm:^7.28.6"
+ "@babel/types": "npm:^7.29.0"
+ checksum: 10c0/dab0e65b9318b2502a62c58bc0913572318595eec0482c31f0ad416b72636e6698a1d7c57cd2791d4528eb8c548bca88d338dc4d2a55a108dc1f6702f9bc5512
+ languageName: node
+ linkType: hard
+
+"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.28.6, @babel/parser@npm:^7.29.0":
+ version: 7.29.2
+ resolution: "@babel/parser@npm:7.29.2"
+ dependencies:
+ "@babel/types": "npm:^7.29.0"
+ bin:
+ parser: ./bin/babel-parser.js
+ checksum: 10c0/e5a4e69e3ac7acdde995f37cf299a68458cfe7009dff66bd0962fd04920bef287201169006af365af479c08ff216bfefbb595e331f87f6ae7283858aebbc3317
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-transform-react-jsx-self@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-transform-react-jsx-self@npm:7.27.1"
+ dependencies:
+ "@babel/helper-plugin-utils": "npm:^7.27.1"
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 10c0/00a4f917b70a608f9aca2fb39aabe04a60aa33165a7e0105fd44b3a8531630eb85bf5572e9f242f51e6ad2fa38c2e7e780902176c863556c58b5ba6f6e164031
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-transform-react-jsx-source@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-transform-react-jsx-source@npm:7.27.1"
+ dependencies:
+ "@babel/helper-plugin-utils": "npm:^7.27.1"
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 10c0/5e67b56c39c4d03e59e03ba80692b24c5a921472079b63af711b1d250fc37c1733a17069b63537f750f3e937ec44a42b1ee6a46cd23b1a0df5163b17f741f7f2
+ languageName: node
+ linkType: hard
+
+"@babel/template@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/template@npm:7.28.6"
+ dependencies:
+ "@babel/code-frame": "npm:^7.28.6"
+ "@babel/parser": "npm:^7.28.6"
+ "@babel/types": "npm:^7.28.6"
+ checksum: 10c0/66d87225ed0bc77f888181ae2d97845021838c619944877f7c4398c6748bcf611f216dfd6be74d39016af502bca876e6ce6873db3c49e4ac354c56d34d57e9f5
+ languageName: node
+ linkType: hard
+
+"@babel/traverse@npm:^7.28.6, @babel/traverse@npm:^7.29.0":
+ version: 7.29.0
+ resolution: "@babel/traverse@npm:7.29.0"
+ dependencies:
+ "@babel/code-frame": "npm:^7.29.0"
+ "@babel/generator": "npm:^7.29.0"
+ "@babel/helper-globals": "npm:^7.28.0"
+ "@babel/parser": "npm:^7.29.0"
+ "@babel/template": "npm:^7.28.6"
+ "@babel/types": "npm:^7.29.0"
+ debug: "npm:^4.3.1"
+ checksum: 10c0/f63ef6e58d02a9fbf3c0e2e5f1c877da3e0bc57f91a19d2223d53e356a76859cbaf51171c9211c71816d94a0e69efa2732fd27ffc0e1bbc84b636e60932333eb
+ languageName: node
+ linkType: hard
+
+"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.28.2, @babel/types@npm:^7.28.6, @babel/types@npm:^7.29.0":
+ version: 7.29.0
+ resolution: "@babel/types@npm:7.29.0"
+ dependencies:
+ "@babel/helper-string-parser": "npm:^7.27.1"
+ "@babel/helper-validator-identifier": "npm:^7.28.5"
+ checksum: 10c0/23cc3466e83bcbfab8b9bd0edaafdb5d4efdb88b82b3be6728bbade5ba2f0996f84f63b1c5f7a8c0d67efded28300898a5f930b171bb40b311bca2029c4e9b4f
+ languageName: node
+ linkType: hard
+
+"@better-auth/core@npm:1.4.7":
+ version: 1.4.7
+ resolution: "@better-auth/core@npm:1.4.7"
+ dependencies:
+ "@standard-schema/spec": "npm:^1.0.0"
+ zod: "npm:^4.1.12"
+ peerDependencies:
+ "@better-auth/utils": 0.3.0
+ "@better-fetch/fetch": 1.1.21
+ better-call: 1.1.5
+ jose: ^6.1.0
+ kysely: ^0.28.5
+ nanostores: ^1.0.1
+ checksum: 10c0/d4d5e54507d66d91b088effa78e7f8cffb3ba1f956bf03020bddf0b1a386c7c39f1fef09e583d493758ab5e23414f243e4f8da7bbc20303b240cec1de206c170
+ languageName: node
+ linkType: hard
+
+"@better-auth/telemetry@npm:1.4.7":
+ version: 1.4.7
+ resolution: "@better-auth/telemetry@npm:1.4.7"
+ dependencies:
+ "@better-auth/utils": "npm:0.3.0"
+ "@better-fetch/fetch": "npm:1.1.21"
+ peerDependencies:
+ "@better-auth/core": 1.4.7
+ checksum: 10c0/ae1b9b1c44f3442a5ee78c1f3ec9e1bf6c9546856e9a9ce016fc78237a53c29a5649c782596353f03609ddc6b5fea2931b3b27af56eb98c5b3022be6eaffad41
+ languageName: node
+ linkType: hard
+
+"@better-auth/utils@npm:0.3.0":
+ version: 0.3.0
+ resolution: "@better-auth/utils@npm:0.3.0"
+ checksum: 10c0/f0ab0c49e1f1e6e7b03dd86e0211ecd25026029378ee0008d5e6b156bcb4d198c4604615ad4242a89fc9290644d73adb485b3f8b3976796113db35c8f1a1953c
+ languageName: node
+ linkType: hard
+
+"@better-auth/utils@npm:^0.3.0":
+ version: 0.3.1
+ resolution: "@better-auth/utils@npm:0.3.1"
+ checksum: 10c0/cd3d36f28ab5a9afce5b582fbd8a52000c5ef43bef1b4d6586df6aa4c6d8b8757cb6b9b83370d5913713bce3a64c12694e8eb3b109e3ec34768e0e0904b3bf58
+ languageName: node
+ linkType: hard
+
+"@better-fetch/fetch@npm:1.1.21, @better-fetch/fetch@npm:^1.1.4":
+ version: 1.1.21
+ resolution: "@better-fetch/fetch@npm:1.1.21"
+ checksum: 10c0/b23355b9eb397a4e6d3b269b027f19c44e3348b42640fa8f133ea4ca9c07e1d289781d2b18477f56883040e7401fcc751c52a6f0b56ea619bdd3132fff3cbb43
+ languageName: node
+ linkType: hard
+
+"@emnapi/core@npm:^1.4.3, @emnapi/core@npm:^1.7.1, @emnapi/core@npm:^1.8.1":
+ version: 1.9.0
+ resolution: "@emnapi/core@npm:1.9.0"
+ dependencies:
+ "@emnapi/wasi-threads": "npm:1.2.0"
+ tslib: "npm:^2.4.0"
+ checksum: 10c0/defbfa5861aa5ff1346dbc6a19df50d727ae76ae276a31a97b178db8eecae0c5179976878087b43ac2441750e40e6c50e465280383256deb16dd2fb167dd515c
+ languageName: node
+ linkType: hard
+
+"@emnapi/runtime@npm:^1.4.3, @emnapi/runtime@npm:^1.7.0, @emnapi/runtime@npm:^1.7.1, @emnapi/runtime@npm:^1.8.1":
+ version: 1.9.0
+ resolution: "@emnapi/runtime@npm:1.9.0"
+ dependencies:
+ tslib: "npm:^2.4.0"
+ checksum: 10c0/f825e53b2d3f9d31fd880e669197d006bb5158c3a52ab25f0546f3d52ac58eb539a4bd1dcc378af6c10d202956fa064b28ab7b572a76de58972c0b8656a692ef
+ languageName: node
+ linkType: hard
+
+"@emnapi/wasi-threads@npm:1.2.0, @emnapi/wasi-threads@npm:^1.1.0":
+ version: 1.2.0
+ resolution: "@emnapi/wasi-threads@npm:1.2.0"
+ dependencies:
+ tslib: "npm:^2.4.0"
+ checksum: 10c0/1e3724b5814b06c14782fda87eee9b9aa68af01576c81ffeaefdf621ddb74386e419d5b3b1027b6a8172397729d95a92f814fc4b8d3c224376428faa07a6a01a
+ languageName: node
+ linkType: hard
+
+"@esbuild/aix-ppc64@npm:0.27.4":
+ version: 0.27.4
+ resolution: "@esbuild/aix-ppc64@npm:0.27.4"
+ conditions: os=aix & cpu=ppc64
+ languageName: node
+ linkType: hard
+
+"@esbuild/android-arm64@npm:0.27.4":
+ version: 0.27.4
+ resolution: "@esbuild/android-arm64@npm:0.27.4"
+ conditions: os=android & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/android-arm@npm:0.27.4":
+ version: 0.27.4
+ resolution: "@esbuild/android-arm@npm:0.27.4"
+ conditions: os=android & cpu=arm
+ languageName: node
+ linkType: hard
+
+"@esbuild/android-x64@npm:0.27.4":
+ version: 0.27.4
+ resolution: "@esbuild/android-x64@npm:0.27.4"
+ conditions: os=android & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/darwin-arm64@npm:0.27.4":
+ version: 0.27.4
+ resolution: "@esbuild/darwin-arm64@npm:0.27.4"
+ conditions: os=darwin & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/darwin-x64@npm:0.27.4":
+ version: 0.27.4
+ resolution: "@esbuild/darwin-x64@npm:0.27.4"
+ conditions: os=darwin & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/freebsd-arm64@npm:0.27.4":
+ version: 0.27.4
+ resolution: "@esbuild/freebsd-arm64@npm:0.27.4"
+ conditions: os=freebsd & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/freebsd-x64@npm:0.27.4":
+ version: 0.27.4
+ resolution: "@esbuild/freebsd-x64@npm:0.27.4"
+ conditions: os=freebsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-arm64@npm:0.27.4":
+ version: 0.27.4
+ resolution: "@esbuild/linux-arm64@npm:0.27.4"
+ conditions: os=linux & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-arm@npm:0.27.4":
+ version: 0.27.4
+ resolution: "@esbuild/linux-arm@npm:0.27.4"
+ conditions: os=linux & cpu=arm
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-ia32@npm:0.27.4":
+ version: 0.27.4
+ resolution: "@esbuild/linux-ia32@npm:0.27.4"
+ conditions: os=linux & cpu=ia32
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-loong64@npm:0.27.4":
+ version: 0.27.4
+ resolution: "@esbuild/linux-loong64@npm:0.27.4"
+ conditions: os=linux & cpu=loong64
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-mips64el@npm:0.27.4":
+ version: 0.27.4
+ resolution: "@esbuild/linux-mips64el@npm:0.27.4"
+ conditions: os=linux & cpu=mips64el
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-ppc64@npm:0.27.4":
+ version: 0.27.4
+ resolution: "@esbuild/linux-ppc64@npm:0.27.4"
+ conditions: os=linux & cpu=ppc64
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-riscv64@npm:0.27.4":
+ version: 0.27.4
+ resolution: "@esbuild/linux-riscv64@npm:0.27.4"
+ conditions: os=linux & cpu=riscv64
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-s390x@npm:0.27.4":
+ version: 0.27.4
+ resolution: "@esbuild/linux-s390x@npm:0.27.4"
+ conditions: os=linux & cpu=s390x
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-x64@npm:0.27.4":
+ version: 0.27.4
+ resolution: "@esbuild/linux-x64@npm:0.27.4"
+ conditions: os=linux & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/netbsd-arm64@npm:0.27.4":
+ version: 0.27.4
+ resolution: "@esbuild/netbsd-arm64@npm:0.27.4"
+ conditions: os=netbsd & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/netbsd-x64@npm:0.27.4":
+ version: 0.27.4
+ resolution: "@esbuild/netbsd-x64@npm:0.27.4"
+ conditions: os=netbsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/openbsd-arm64@npm:0.27.4":
+ version: 0.27.4
+ resolution: "@esbuild/openbsd-arm64@npm:0.27.4"
+ conditions: os=openbsd & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/openbsd-x64@npm:0.27.4":
+ version: 0.27.4
+ resolution: "@esbuild/openbsd-x64@npm:0.27.4"
+ conditions: os=openbsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/openharmony-arm64@npm:0.27.4":
+ version: 0.27.4
+ resolution: "@esbuild/openharmony-arm64@npm:0.27.4"
+ conditions: os=openharmony & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/sunos-x64@npm:0.27.4":
+ version: 0.27.4
+ resolution: "@esbuild/sunos-x64@npm:0.27.4"
+ conditions: os=sunos & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/win32-arm64@npm:0.27.4":
+ version: 0.27.4
+ resolution: "@esbuild/win32-arm64@npm:0.27.4"
+ conditions: os=win32 & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/win32-ia32@npm:0.27.4":
+ version: 0.27.4
+ resolution: "@esbuild/win32-ia32@npm:0.27.4"
+ conditions: os=win32 & cpu=ia32
+ languageName: node
+ linkType: hard
+
+"@esbuild/win32-x64@npm:0.27.4":
+ version: 0.27.4
+ resolution: "@esbuild/win32-x64@npm:0.27.4"
+ conditions: os=win32 & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@eslint-community/eslint-utils@npm:^4.8.0, @eslint-community/eslint-utils@npm:^4.9.1":
+ version: 4.9.1
+ resolution: "@eslint-community/eslint-utils@npm:4.9.1"
+ dependencies:
+ eslint-visitor-keys: "npm:^3.4.3"
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+ checksum: 10c0/dc4ab5e3e364ef27e33666b11f4b86e1a6c1d7cbf16f0c6ff87b1619b3562335e9201a3d6ce806221887ff780ec9d828962a290bb910759fd40a674686503f02
+ languageName: node
+ linkType: hard
+
+"@eslint-community/regexpp@npm:^4.12.1, @eslint-community/regexpp@npm:^4.12.2":
+ version: 4.12.2
+ resolution: "@eslint-community/regexpp@npm:4.12.2"
+ checksum: 10c0/fddcbc66851b308478d04e302a4d771d6917a0b3740dc351513c0da9ca2eab8a1adf99f5e0aa7ab8b13fa0df005c81adeee7e63a92f3effd7d367a163b721c2d
+ languageName: node
+ linkType: hard
+
+"@eslint/config-array@npm:^0.21.2":
+ version: 0.21.2
+ resolution: "@eslint/config-array@npm:0.21.2"
+ dependencies:
+ "@eslint/object-schema": "npm:^2.1.7"
+ debug: "npm:^4.3.1"
+ minimatch: "npm:^3.1.5"
+ checksum: 10c0/89dfe815d18456177c0a1f238daf4593107fd20298b3598e0103054360d3b8d09d967defd8318f031185d68df1f95cfa68becf1390a9c5c6887665f1475142e3
+ languageName: node
+ linkType: hard
+
+"@eslint/config-helpers@npm:^0.4.2":
+ version: 0.4.2
+ resolution: "@eslint/config-helpers@npm:0.4.2"
+ dependencies:
+ "@eslint/core": "npm:^0.17.0"
+ checksum: 10c0/92efd7a527b2d17eb1a148409d71d80f9ac160b565ac73ee092252e8bf08ecd08670699f46b306b94f13d22e88ac88a612120e7847570dd7cdc72f234d50dcb4
+ languageName: node
+ linkType: hard
+
+"@eslint/core@npm:^0.17.0":
+ version: 0.17.0
+ resolution: "@eslint/core@npm:0.17.0"
+ dependencies:
+ "@types/json-schema": "npm:^7.0.15"
+ checksum: 10c0/9a580f2246633bc752298e7440dd942ec421860d1946d0801f0423830e67887e4aeba10ab9a23d281727a978eb93d053d1922a587d502942a713607f40ed704e
+ languageName: node
+ linkType: hard
+
+"@eslint/eslintrc@npm:^3.3.5":
+ version: 3.3.5
+ resolution: "@eslint/eslintrc@npm:3.3.5"
+ dependencies:
+ ajv: "npm:^6.14.0"
+ debug: "npm:^4.3.2"
+ espree: "npm:^10.0.1"
+ globals: "npm:^14.0.0"
+ ignore: "npm:^5.2.0"
+ import-fresh: "npm:^3.2.1"
+ js-yaml: "npm:^4.1.1"
+ minimatch: "npm:^3.1.5"
+ strip-json-comments: "npm:^3.1.1"
+ checksum: 10c0/9fb9f1ca65e46d6173966e3aaa5bd353e3a65d7f1f582bebf77f578fab7d7960a399fac1ecfb1e7d52bd61f5cefd6531087ca52a3a3c388f2e1b4f1ebd3da8b7
+ languageName: node
+ linkType: hard
+
+"@eslint/js@npm:9.39.4":
+ version: 9.39.4
+ resolution: "@eslint/js@npm:9.39.4"
+ checksum: 10c0/5aa7dea2cbc5decf7f5e3b0c6f86a084ccee0f792d288ca8e839f8bc1b64e03e227068968e49b26096e6f71fd857ab6e42691d1b993826b9a3883f1bdd7a0e46
+ languageName: node
+ linkType: hard
+
+"@eslint/object-schema@npm:^2.1.7":
+ version: 2.1.7
+ resolution: "@eslint/object-schema@npm:2.1.7"
+ checksum: 10c0/936b6e499853d1335803f556d526c86f5fe2259ed241bc665000e1d6353828edd913feed43120d150adb75570cae162cf000b5b0dfc9596726761c36b82f4e87
+ languageName: node
+ linkType: hard
+
+"@eslint/plugin-kit@npm:^0.4.1":
+ version: 0.4.1
+ resolution: "@eslint/plugin-kit@npm:0.4.1"
+ dependencies:
+ "@eslint/core": "npm:^0.17.0"
+ levn: "npm:^0.4.1"
+ checksum: 10c0/51600f78b798f172a9915dffb295e2ffb44840d583427bc732baf12ecb963eb841b253300e657da91d890f4b323d10a1bd12934bf293e3018d8bb66fdce5217b
+ languageName: node
+ linkType: hard
+
+"@floating-ui/core@npm:^1.7.5":
+ version: 1.7.5
+ resolution: "@floating-ui/core@npm:1.7.5"
+ dependencies:
+ "@floating-ui/utils": "npm:^0.2.11"
+ checksum: 10c0/f9c52205e198b231d63a387b09c659aab08c46a1899e0b0bbe147b8b4f048b546f15ba17cb5d2a471da9534f1883d979425e13e5c4ceee67be63e4b0abd4db5d
+ languageName: node
+ linkType: hard
+
+"@floating-ui/dom@npm:^1.7.6":
+ version: 1.7.6
+ resolution: "@floating-ui/dom@npm:1.7.6"
+ dependencies:
+ "@floating-ui/core": "npm:^1.7.5"
+ "@floating-ui/utils": "npm:^0.2.11"
+ checksum: 10c0/5c098e0d7b58c9bc769f276cca1766994c2c9c70c92d091a61bba8b3e9be53c011e0a79a8457fc2fb2f3d91697a26eb52e0a4962ef936dc963b45f58613c212f
+ languageName: node
+ linkType: hard
+
+"@floating-ui/react-dom@npm:^2.0.0":
+ version: 2.1.8
+ resolution: "@floating-ui/react-dom@npm:2.1.8"
+ dependencies:
+ "@floating-ui/dom": "npm:^1.7.6"
+ peerDependencies:
+ react: ">=16.8.0"
+ react-dom: ">=16.8.0"
+ checksum: 10c0/26260ca4bb23b57c73b824062505abf977a008ce6e0463bdacca74f7e49853c4cd1d2bbf1a77c6caa17fa37dfffda2c6c4cd07a8737ebd7474aaff7818401d75
+ languageName: node
+ linkType: hard
+
+"@floating-ui/utils@npm:^0.2.11":
+ version: 0.2.11
+ resolution: "@floating-ui/utils@npm:0.2.11"
+ checksum: 10c0/f4bcea1559bdbb721ecc8e8ead423ac58d6a5b6e70b602cf0810ba6ad4ed1c77211b207faa88b278a9042f0c743133de08a203ed6741c1b6443423332884d5b3
+ languageName: node
+ linkType: hard
+
+"@gar/promise-retry@npm:^1.0.0":
+ version: 1.0.2
+ resolution: "@gar/promise-retry@npm:1.0.2"
+ dependencies:
+ retry: "npm:^0.13.1"
+ checksum: 10c0/748a84fb0ab962f7867966f21dc24d1872c53c1656dd3352320fe69ad3b2043f2dfdb3be024c7636ce4904c5ba1da22d0f3558e489c3de578f5bb520f062d0fd
+ languageName: node
+ linkType: hard
+
+"@humanfs/core@npm:^0.19.1":
+ version: 0.19.1
+ resolution: "@humanfs/core@npm:0.19.1"
+ checksum: 10c0/aa4e0152171c07879b458d0e8a704b8c3a89a8c0541726c6b65b81e84fd8b7564b5d6c633feadc6598307d34564bd53294b533491424e8e313d7ab6c7bc5dc67
+ languageName: node
+ linkType: hard
+
+"@humanfs/node@npm:^0.16.6":
+ version: 0.16.7
+ resolution: "@humanfs/node@npm:0.16.7"
+ dependencies:
+ "@humanfs/core": "npm:^0.19.1"
+ "@humanwhocodes/retry": "npm:^0.4.0"
+ checksum: 10c0/9f83d3cf2cfa37383e01e3cdaead11cd426208e04c44adcdd291aa983aaf72d7d3598844d2fe9ce54896bb1bf8bd4b56883376611c8905a19c44684642823f30
+ languageName: node
+ linkType: hard
+
+"@humanwhocodes/module-importer@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "@humanwhocodes/module-importer@npm:1.0.1"
+ checksum: 10c0/909b69c3b86d482c26b3359db16e46a32e0fb30bd306a3c176b8313b9e7313dba0f37f519de6aa8b0a1921349e505f259d19475e123182416a506d7f87e7f529
+ languageName: node
+ linkType: hard
+
+"@humanwhocodes/retry@npm:^0.4.0, @humanwhocodes/retry@npm:^0.4.2":
+ version: 0.4.3
+ resolution: "@humanwhocodes/retry@npm:0.4.3"
+ checksum: 10c0/3775bb30087d4440b3f7406d5a057777d90e4b9f435af488a4923ef249e93615fb78565a85f173a186a076c7706a81d0d57d563a2624e4de2c5c9c66c486ce42
+ languageName: node
+ linkType: hard
+
+"@img/colour@npm:^1.0.0":
+ version: 1.1.0
+ resolution: "@img/colour@npm:1.1.0"
+ checksum: 10c0/2ebea2c0bbaee73b99badcefa04e1e71d83f36e5369337d3121dca841f4569533c4e2faddda6d62dd247f0d5cca143711f9446c59bcce81e427ba433a7a94a17
+ languageName: node
+ linkType: hard
+
+"@img/sharp-darwin-arm64@npm:0.34.5":
+ version: 0.34.5
+ resolution: "@img/sharp-darwin-arm64@npm:0.34.5"
+ dependencies:
+ "@img/sharp-libvips-darwin-arm64": "npm:1.2.4"
+ dependenciesMeta:
+ "@img/sharp-libvips-darwin-arm64":
+ optional: true
+ conditions: os=darwin & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@img/sharp-darwin-x64@npm:0.34.5":
+ version: 0.34.5
+ resolution: "@img/sharp-darwin-x64@npm:0.34.5"
+ dependencies:
+ "@img/sharp-libvips-darwin-x64": "npm:1.2.4"
+ dependenciesMeta:
+ "@img/sharp-libvips-darwin-x64":
+ optional: true
+ conditions: os=darwin & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@img/sharp-libvips-darwin-arm64@npm:1.2.4":
+ version: 1.2.4
+ resolution: "@img/sharp-libvips-darwin-arm64@npm:1.2.4"
+ conditions: os=darwin & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@img/sharp-libvips-darwin-x64@npm:1.2.4":
+ version: 1.2.4
+ resolution: "@img/sharp-libvips-darwin-x64@npm:1.2.4"
+ conditions: os=darwin & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@img/sharp-libvips-linux-arm64@npm:1.2.4":
+ version: 1.2.4
+ resolution: "@img/sharp-libvips-linux-arm64@npm:1.2.4"
+ conditions: os=linux & cpu=arm64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@img/sharp-libvips-linux-arm@npm:1.2.4":
+ version: 1.2.4
+ resolution: "@img/sharp-libvips-linux-arm@npm:1.2.4"
+ conditions: os=linux & cpu=arm & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@img/sharp-libvips-linux-ppc64@npm:1.2.4":
+ version: 1.2.4
+ resolution: "@img/sharp-libvips-linux-ppc64@npm:1.2.4"
+ conditions: os=linux & cpu=ppc64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@img/sharp-libvips-linux-riscv64@npm:1.2.4":
+ version: 1.2.4
+ resolution: "@img/sharp-libvips-linux-riscv64@npm:1.2.4"
+ conditions: os=linux & cpu=riscv64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@img/sharp-libvips-linux-s390x@npm:1.2.4":
+ version: 1.2.4
+ resolution: "@img/sharp-libvips-linux-s390x@npm:1.2.4"
+ conditions: os=linux & cpu=s390x & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@img/sharp-libvips-linux-x64@npm:1.2.4":
+ version: 1.2.4
+ resolution: "@img/sharp-libvips-linux-x64@npm:1.2.4"
+ conditions: os=linux & cpu=x64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@img/sharp-libvips-linuxmusl-arm64@npm:1.2.4":
+ version: 1.2.4
+ resolution: "@img/sharp-libvips-linuxmusl-arm64@npm:1.2.4"
+ conditions: os=linux & cpu=arm64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@img/sharp-libvips-linuxmusl-x64@npm:1.2.4":
+ version: 1.2.4
+ resolution: "@img/sharp-libvips-linuxmusl-x64@npm:1.2.4"
+ conditions: os=linux & cpu=x64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@img/sharp-linux-arm64@npm:0.34.5":
+ version: 0.34.5
+ resolution: "@img/sharp-linux-arm64@npm:0.34.5"
+ dependencies:
+ "@img/sharp-libvips-linux-arm64": "npm:1.2.4"
+ dependenciesMeta:
+ "@img/sharp-libvips-linux-arm64":
+ optional: true
+ conditions: os=linux & cpu=arm64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@img/sharp-linux-arm@npm:0.34.5":
+ version: 0.34.5
+ resolution: "@img/sharp-linux-arm@npm:0.34.5"
+ dependencies:
+ "@img/sharp-libvips-linux-arm": "npm:1.2.4"
+ dependenciesMeta:
+ "@img/sharp-libvips-linux-arm":
+ optional: true
+ conditions: os=linux & cpu=arm & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@img/sharp-linux-ppc64@npm:0.34.5":
+ version: 0.34.5
+ resolution: "@img/sharp-linux-ppc64@npm:0.34.5"
+ dependencies:
+ "@img/sharp-libvips-linux-ppc64": "npm:1.2.4"
+ dependenciesMeta:
+ "@img/sharp-libvips-linux-ppc64":
+ optional: true
+ conditions: os=linux & cpu=ppc64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@img/sharp-linux-riscv64@npm:0.34.5":
+ version: 0.34.5
+ resolution: "@img/sharp-linux-riscv64@npm:0.34.5"
+ dependencies:
+ "@img/sharp-libvips-linux-riscv64": "npm:1.2.4"
+ dependenciesMeta:
+ "@img/sharp-libvips-linux-riscv64":
+ optional: true
+ conditions: os=linux & cpu=riscv64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@img/sharp-linux-s390x@npm:0.34.5":
+ version: 0.34.5
+ resolution: "@img/sharp-linux-s390x@npm:0.34.5"
+ dependencies:
+ "@img/sharp-libvips-linux-s390x": "npm:1.2.4"
+ dependenciesMeta:
+ "@img/sharp-libvips-linux-s390x":
+ optional: true
+ conditions: os=linux & cpu=s390x & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@img/sharp-linux-x64@npm:0.34.5":
+ version: 0.34.5
+ resolution: "@img/sharp-linux-x64@npm:0.34.5"
+ dependencies:
+ "@img/sharp-libvips-linux-x64": "npm:1.2.4"
+ dependenciesMeta:
+ "@img/sharp-libvips-linux-x64":
+ optional: true
+ conditions: os=linux & cpu=x64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@img/sharp-linuxmusl-arm64@npm:0.34.5":
+ version: 0.34.5
+ resolution: "@img/sharp-linuxmusl-arm64@npm:0.34.5"
+ dependencies:
+ "@img/sharp-libvips-linuxmusl-arm64": "npm:1.2.4"
+ dependenciesMeta:
+ "@img/sharp-libvips-linuxmusl-arm64":
+ optional: true
+ conditions: os=linux & cpu=arm64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@img/sharp-linuxmusl-x64@npm:0.34.5":
+ version: 0.34.5
+ resolution: "@img/sharp-linuxmusl-x64@npm:0.34.5"
+ dependencies:
+ "@img/sharp-libvips-linuxmusl-x64": "npm:1.2.4"
+ dependenciesMeta:
+ "@img/sharp-libvips-linuxmusl-x64":
+ optional: true
+ conditions: os=linux & cpu=x64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@img/sharp-wasm32@npm:0.34.5":
+ version: 0.34.5
+ resolution: "@img/sharp-wasm32@npm:0.34.5"
+ dependencies:
+ "@emnapi/runtime": "npm:^1.7.0"
+ conditions: cpu=wasm32
+ languageName: node
+ linkType: hard
+
+"@img/sharp-win32-arm64@npm:0.34.5":
+ version: 0.34.5
+ resolution: "@img/sharp-win32-arm64@npm:0.34.5"
+ conditions: os=win32 & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@img/sharp-win32-ia32@npm:0.34.5":
+ version: 0.34.5
+ resolution: "@img/sharp-win32-ia32@npm:0.34.5"
+ conditions: os=win32 & cpu=ia32
+ languageName: node
+ linkType: hard
+
+"@img/sharp-win32-x64@npm:0.34.5":
+ version: 0.34.5
+ resolution: "@img/sharp-win32-x64@npm:0.34.5"
+ conditions: os=win32 & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@isaacs/fs-minipass@npm:^4.0.0":
+ version: 4.0.1
+ resolution: "@isaacs/fs-minipass@npm:4.0.1"
+ dependencies:
+ minipass: "npm:^7.0.4"
+ checksum: 10c0/c25b6dc1598790d5b55c0947a9b7d111cfa92594db5296c3b907e2f533c033666f692a3939eadac17b1c7c40d362d0b0635dc874cbfe3e70db7c2b07cc97a5d2
+ languageName: node
+ linkType: hard
+
+"@jridgewell/gen-mapping@npm:^0.3.12, @jridgewell/gen-mapping@npm:^0.3.5":
+ version: 0.3.13
+ resolution: "@jridgewell/gen-mapping@npm:0.3.13"
+ dependencies:
+ "@jridgewell/sourcemap-codec": "npm:^1.5.0"
+ "@jridgewell/trace-mapping": "npm:^0.3.24"
+ checksum: 10c0/9a7d65fb13bd9aec1fbab74cda08496839b7e2ceb31f5ab922b323e94d7c481ce0fc4fd7e12e2610915ed8af51178bdc61e168e92a8c8b8303b030b03489b13b
+ languageName: node
+ linkType: hard
+
+"@jridgewell/remapping@npm:^2.3.5":
+ version: 2.3.5
+ resolution: "@jridgewell/remapping@npm:2.3.5"
+ dependencies:
+ "@jridgewell/gen-mapping": "npm:^0.3.5"
+ "@jridgewell/trace-mapping": "npm:^0.3.24"
+ checksum: 10c0/3de494219ffeb2c5c38711d0d7bb128097edf91893090a2dbc8ee0b55d092bb7347b1fd0f478486c5eab010e855c73927b1666f2107516d472d24a73017d1194
+ languageName: node
+ linkType: hard
+
+"@jridgewell/resolve-uri@npm:^3.1.0":
+ version: 3.1.2
+ resolution: "@jridgewell/resolve-uri@npm:3.1.2"
+ checksum: 10c0/d502e6fb516b35032331406d4e962c21fe77cdf1cbdb49c6142bcbd9e30507094b18972778a6e27cbad756209cfe34b1a27729e6fa08a2eb92b33943f680cf1e
+ languageName: node
+ linkType: hard
+
+"@jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.5.0, @jridgewell/sourcemap-codec@npm:^1.5.5":
+ version: 1.5.5
+ resolution: "@jridgewell/sourcemap-codec@npm:1.5.5"
+ checksum: 10c0/f9e538f302b63c0ebc06eecb1dd9918dd4289ed36147a0ddce35d6ea4d7ebbda243cda7b2213b6a5e1d8087a298d5cf630fb2bd39329cdecb82017023f6081a0
+ languageName: node
+ linkType: hard
+
+"@jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.28":
+ version: 0.3.31
+ resolution: "@jridgewell/trace-mapping@npm:0.3.31"
+ dependencies:
+ "@jridgewell/resolve-uri": "npm:^3.1.0"
+ "@jridgewell/sourcemap-codec": "npm:^1.4.14"
+ checksum: 10c0/4b30ec8cd56c5fd9a661f088230af01e0c1a3888d11ffb6b47639700f71225be21d1f7e168048d6d4f9449207b978a235c07c8f15c07705685d16dc06280e9d9
+ languageName: node
+ linkType: hard
+
+"@napi-rs/wasm-runtime@npm:^0.2.11":
+ version: 0.2.12
+ resolution: "@napi-rs/wasm-runtime@npm:0.2.12"
+ dependencies:
+ "@emnapi/core": "npm:^1.4.3"
+ "@emnapi/runtime": "npm:^1.4.3"
+ "@tybys/wasm-util": "npm:^0.10.0"
+ checksum: 10c0/6d07922c0613aab30c6a497f4df297ca7c54e5b480e00035e0209b872d5c6aab7162fc49477267556109c2c7ed1eb9c65a174e27e9b87568106a87b0a6e3ca7d
+ languageName: node
+ linkType: hard
+
+"@napi-rs/wasm-runtime@npm:^1.1.1":
+ version: 1.1.1
+ resolution: "@napi-rs/wasm-runtime@npm:1.1.1"
+ dependencies:
+ "@emnapi/core": "npm:^1.7.1"
+ "@emnapi/runtime": "npm:^1.7.1"
+ "@tybys/wasm-util": "npm:^0.10.1"
+ checksum: 10c0/04d57b67e80736e41fe44674a011878db0a8ad893f4d44abb9d3608debb7c174224cba2796ed5b0c1d367368159f3ca6be45f1c59222f70e32ddc880f803d447
+ languageName: node
+ linkType: hard
+
+"@next/env@npm:15.5.13":
+ version: 15.5.13
+ resolution: "@next/env@npm:15.5.13"
+ checksum: 10c0/288e288fac99377f138dfb64d4d0d3ec9716bf1c21e61a33eff5e02466b21d3ee37cf054276afdd181459f1ee5e5fdb0d207060b713daf07dc99f98de06f1e9e
+ languageName: node
+ linkType: hard
+
+"@next/eslint-plugin-next@npm:15.5.13":
+ version: 15.5.13
+ resolution: "@next/eslint-plugin-next@npm:15.5.13"
+ dependencies:
+ fast-glob: "npm:3.3.1"
+ checksum: 10c0/d4bbf5c3f0f23e4491dd2c842b54a880b321d12072aeeeb5fa157f5c18a03805e09b42e674b6e7d595cc99178d8614f27fa58da6eb75ca5c54663cc1ee366bac
+ languageName: node
+ linkType: hard
+
+"@next/swc-darwin-arm64@npm:15.5.13":
+ version: 15.5.13
+ resolution: "@next/swc-darwin-arm64@npm:15.5.13"
+ conditions: os=darwin & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@next/swc-darwin-x64@npm:15.5.13":
+ version: 15.5.13
+ resolution: "@next/swc-darwin-x64@npm:15.5.13"
+ conditions: os=darwin & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@next/swc-linux-arm64-gnu@npm:15.5.13":
+ version: 15.5.13
+ resolution: "@next/swc-linux-arm64-gnu@npm:15.5.13"
+ conditions: os=linux & cpu=arm64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@next/swc-linux-arm64-musl@npm:15.5.13":
+ version: 15.5.13
+ resolution: "@next/swc-linux-arm64-musl@npm:15.5.13"
+ conditions: os=linux & cpu=arm64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@next/swc-linux-x64-gnu@npm:15.5.13":
+ version: 15.5.13
+ resolution: "@next/swc-linux-x64-gnu@npm:15.5.13"
+ conditions: os=linux & cpu=x64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@next/swc-linux-x64-musl@npm:15.5.13":
+ version: 15.5.13
+ resolution: "@next/swc-linux-x64-musl@npm:15.5.13"
+ conditions: os=linux & cpu=x64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@next/swc-win32-arm64-msvc@npm:15.5.13":
+ version: 15.5.13
+ resolution: "@next/swc-win32-arm64-msvc@npm:15.5.13"
+ conditions: os=win32 & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@next/swc-win32-x64-msvc@npm:15.5.13":
+ version: 15.5.13
+ resolution: "@next/swc-win32-x64-msvc@npm:15.5.13"
+ conditions: os=win32 & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@noble/ciphers@npm:^2.0.0":
+ version: 2.1.1
+ resolution: "@noble/ciphers@npm:2.1.1"
+ checksum: 10c0/f02662723475a9785a2f7bcd6e8e12d4b5f77537154f5e21edb0fed398051fb1ae5057eb444987e1c65342f8632474f0143ea612a2dad49593d3358eb730a079
+ languageName: node
+ linkType: hard
+
+"@noble/hashes@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "@noble/hashes@npm:2.0.1"
+ checksum: 10c0/e81769ce21c3b1c80141a3b99bd001f17edea09879aa936692ae39525477386d696101cd573928a304806efb2b9fa751e1dd83241c67d0c84d30091e85c79bdb
+ languageName: node
+ linkType: hard
+
+"@nodelib/fs.scandir@npm:2.1.5":
+ version: 2.1.5
+ resolution: "@nodelib/fs.scandir@npm:2.1.5"
+ dependencies:
+ "@nodelib/fs.stat": "npm:2.0.5"
+ run-parallel: "npm:^1.1.9"
+ checksum: 10c0/732c3b6d1b1e967440e65f284bd06e5821fedf10a1bea9ed2bb75956ea1f30e08c44d3def9d6a230666574edbaf136f8cfd319c14fd1f87c66e6a44449afb2eb
+ languageName: node
+ linkType: hard
+
+"@nodelib/fs.stat@npm:2.0.5, @nodelib/fs.stat@npm:^2.0.2":
+ version: 2.0.5
+ resolution: "@nodelib/fs.stat@npm:2.0.5"
+ checksum: 10c0/88dafe5e3e29a388b07264680dc996c17f4bda48d163a9d4f5c1112979f0ce8ec72aa7116122c350b4e7976bc5566dc3ddb579be1ceaacc727872eb4ed93926d
+ languageName: node
+ linkType: hard
+
+"@nodelib/fs.walk@npm:^1.2.3":
+ version: 1.2.8
+ resolution: "@nodelib/fs.walk@npm:1.2.8"
+ dependencies:
+ "@nodelib/fs.scandir": "npm:2.1.5"
+ fastq: "npm:^1.6.0"
+ checksum: 10c0/db9de047c3bb9b51f9335a7bb46f4fcfb6829fb628318c12115fbaf7d369bfce71c15b103d1fc3b464812d936220ee9bc1c8f762d032c9f6be9acc99249095b1
+ languageName: node
+ linkType: hard
+
+"@nolyfill/is-core-module@npm:1.0.39":
+ version: 1.0.39
+ resolution: "@nolyfill/is-core-module@npm:1.0.39"
+ checksum: 10c0/34ab85fdc2e0250879518841f74a30c276bca4f6c3e13526d2d1fe515e1adf6d46c25fcd5989d22ea056d76f7c39210945180b4859fc83b050e2da411aa86289
+ languageName: node
+ linkType: hard
+
+"@npmcli/agent@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "@npmcli/agent@npm:4.0.0"
+ dependencies:
+ agent-base: "npm:^7.1.0"
+ http-proxy-agent: "npm:^7.0.0"
+ https-proxy-agent: "npm:^7.0.1"
+ lru-cache: "npm:^11.2.1"
+ socks-proxy-agent: "npm:^8.0.3"
+ checksum: 10c0/f7b5ce0f3dd42c3f8c6546e8433573d8049f67ef11ec22aa4704bc41483122f68bf97752e06302c455ead667af5cb753e6a09bff06632bc465c1cfd4c4b75a53
+ languageName: node
+ linkType: hard
+
+"@npmcli/fs@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "@npmcli/fs@npm:5.0.0"
+ dependencies:
+ semver: "npm:^7.3.5"
+ checksum: 10c0/26e376d780f60ff16e874a0ac9bc3399186846baae0b6e1352286385ac134d900cc5dafaded77f38d77f86898fc923ae1cee9d7399f0275b1aa24878915d722b
+ languageName: node
+ linkType: hard
+
+"@npmcli/redact@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "@npmcli/redact@npm:4.0.0"
+ checksum: 10c0/a1e9ba9c70a6b40e175bda2c3dd8cfdaf096e6b7f7a132c855c083c8dfe545c3237cd56702e2e6627a580b1d63373599d49a1192c4078a85bf47bbde824df31c
+ languageName: node
+ linkType: hard
+
+"@prisma/client@npm:5.22.0":
+ version: 5.22.0
+ resolution: "@prisma/client@npm:5.22.0"
+ peerDependencies:
+ prisma: "*"
+ peerDependenciesMeta:
+ prisma:
+ optional: true
+ checksum: 10c0/ad111b931f184249794f811637456eb38dcfd0d7047e5a1f64804e5256f462fa3ee7c7a552fc8fa181e8daacc2b958af7426cb57bf0dc66605c3ef7c4aef4afb
+ languageName: node
+ linkType: hard
+
+"@prisma/debug@npm:5.22.0":
+ version: 5.22.0
+ resolution: "@prisma/debug@npm:5.22.0"
+ checksum: 10c0/ff7c5e84d9f9b568a2a1992eb39fc7c3ab6d9e326c77fdefec1655ccfbf6c0ee268a5dcf087867848eb00a0328c9cc75a164880ec7cd60f7fd634e2fca2943d9
+ languageName: node
+ linkType: hard
+
+"@prisma/engines-version@npm:5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2":
+ version: 5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2
+ resolution: "@prisma/engines-version@npm:5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2"
+ checksum: 10c0/95df49c6f35f99c0977e9690d9ae0776327df07c6f035e8c4a247a9c21108f0760c02ca6dbe63a35013e5cd1eb77a896edb340f1e28ea04373c6cefc4ce09b51
+ languageName: node
+ linkType: hard
+
+"@prisma/engines@npm:5.22.0":
+ version: 5.22.0
+ resolution: "@prisma/engines@npm:5.22.0"
+ dependencies:
+ "@prisma/debug": "npm:5.22.0"
+ "@prisma/engines-version": "npm:5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2"
+ "@prisma/fetch-engine": "npm:5.22.0"
+ "@prisma/get-platform": "npm:5.22.0"
+ checksum: 10c0/81a439e5064a1036e05da8feaf7ffb19b5dba98d5ea68dc385f7e24e3cc25ef9f0b78a1aa1d7d7234a9afd916ee18b707863cee48274912315bc933429f26ce7
+ languageName: node
+ linkType: hard
+
+"@prisma/fetch-engine@npm:5.22.0":
+ version: 5.22.0
+ resolution: "@prisma/fetch-engine@npm:5.22.0"
+ dependencies:
+ "@prisma/debug": "npm:5.22.0"
+ "@prisma/engines-version": "npm:5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2"
+ "@prisma/get-platform": "npm:5.22.0"
+ checksum: 10c0/0d3dcaffbadcf9185cca37bb50ce3a92fad2a205451731e5c3d02b1ee96a918dde99a9ce231e62bddde5ec8dcb3035338ff1312f8416f2cdaf31a69a19448baf
+ languageName: node
+ linkType: hard
+
+"@prisma/get-platform@npm:5.22.0":
+ version: 5.22.0
+ resolution: "@prisma/get-platform@npm:5.22.0"
+ dependencies:
+ "@prisma/debug": "npm:5.22.0"
+ checksum: 10c0/b934f9bbba1e8dae01721a213a5b166a4dd9f35bf04ad93fb9e24afb67945c09562d4e2c5b4d33b1830cdc7adeb03775309c55ab2c470048ed4cfc947fe495f5
+ languageName: node
+ linkType: hard
+
+"@radix-ui/number@npm:1.1.1":
+ version: 1.1.1
+ resolution: "@radix-ui/number@npm:1.1.1"
+ checksum: 10c0/0570ad92287398e8a7910786d7cee0a998174cdd6637ba61571992897c13204adf70b9ed02d0da2af554119411128e701d9c6b893420612897b438dc91db712b
+ languageName: node
+ linkType: hard
+
+"@radix-ui/primitive@npm:1.1.3":
+ version: 1.1.3
+ resolution: "@radix-ui/primitive@npm:1.1.3"
+ checksum: 10c0/88860165ee7066fa2c179f32ffcd3ee6d527d9dcdc0e8be85e9cb0e2c84834be8e3c1a976c74ba44b193f709544e12f54455d892b28e32f0708d89deda6b9f1d
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-arrow@npm:1.1.7":
+ version: 1.1.7
+ resolution: "@radix-ui/react-arrow@npm:1.1.7"
+ dependencies:
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ 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
+ checksum: 10c0/c3b46766238b3ee2a394d8806a5141432361bf1425110c9f0dcf480bda4ebd304453a53f294b5399c6ee3ccfcae6fd544921fd01ddc379cf5942acdd7168664b
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-avatar@npm:^1.1.11":
+ version: 1.1.11
+ resolution: "@radix-ui/react-avatar@npm:1.1.11"
+ dependencies:
+ "@radix-ui/react-context": "npm:1.1.3"
+ "@radix-ui/react-primitive": "npm:2.1.4"
+ "@radix-ui/react-use-callback-ref": "npm:1.1.1"
+ "@radix-ui/react-use-is-hydrated": "npm:0.1.0"
+ "@radix-ui/react-use-layout-effect": "npm: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
+ checksum: 10c0/b1b3d4b11a8e05a8479d2410fb4e7b1bf825135c4cd42f7e5152568a54a55a3073bd87d50325150417a29306e7b1b371289dc3c4f11739af8a2a7bb8dd7c38c9
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-collection@npm:1.1.7":
+ version: 1.1.7
+ resolution: "@radix-ui/react-collection@npm:1.1.7"
+ dependencies:
+ "@radix-ui/react-compose-refs": "npm:1.1.2"
+ "@radix-ui/react-context": "npm:1.1.2"
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ "@radix-ui/react-slot": "npm:1.2.3"
+ 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
+ checksum: 10c0/fa321a7300095508491f75414f02b243f0c3f179dc0728cfd115e2ea9f6f48f1516532b59f526d9ac81bbab63cd98a052074b4703ec0b9428fac945ebabec5fd
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-compose-refs@npm:1.1.2":
+ version: 1.1.2
+ resolution: "@radix-ui/react-compose-refs@npm:1.1.2"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/d36a9c589eb75d634b9b139c80f916aadaf8a68a7c1c4b8c6c6b88755af1a92f2e343457042089f04cc3f23073619d08bb65419ced1402e9d4e299576d970771
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-context@npm:1.1.2":
+ version: 1.1.2
+ resolution: "@radix-ui/react-context@npm:1.1.2"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/cece731f8cc25d494c6589cc681e5c01a93867d895c75889973afa1a255f163c286e390baa7bc028858eaabe9f6b57270d0ca6377356f652c5557c1c7a41ccce
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-context@npm:1.1.3":
+ version: 1.1.3
+ resolution: "@radix-ui/react-context@npm:1.1.3"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/0f271b4100dbb007ad2675f2529453f07454f214b7ce796d72680bf2dff050d0719083ee6e8962919a74048ff853eff2e50de07d8f8c674d6be91bfa76204cc2
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-dialog@npm:^1.1.15":
+ version: 1.1.15
+ resolution: "@radix-ui/react-dialog@npm:1.1.15"
+ dependencies:
+ "@radix-ui/primitive": "npm:1.1.3"
+ "@radix-ui/react-compose-refs": "npm:1.1.2"
+ "@radix-ui/react-context": "npm:1.1.2"
+ "@radix-ui/react-dismissable-layer": "npm:1.1.11"
+ "@radix-ui/react-focus-guards": "npm:1.1.3"
+ "@radix-ui/react-focus-scope": "npm:1.1.7"
+ "@radix-ui/react-id": "npm:1.1.1"
+ "@radix-ui/react-portal": "npm:1.1.9"
+ "@radix-ui/react-presence": "npm:1.1.5"
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ "@radix-ui/react-slot": "npm:1.2.3"
+ "@radix-ui/react-use-controllable-state": "npm:1.2.2"
+ aria-hidden: "npm:^1.2.4"
+ react-remove-scroll: "npm:^2.6.3"
+ 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
+ checksum: 10c0/2f2c88e3c281acaea2fd9b96fa82132d59177d3aa5da2e7c045596fd4028e84e44ac52ac28f4f236910605dd7d9338c2858ba44a9ced2af2e3e523abbfd33014
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-direction@npm:1.1.1":
+ version: 1.1.1
+ resolution: "@radix-ui/react-direction@npm:1.1.1"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/7a89d9291f846a3105e45f4df98d6b7a08f8d7b30acdcd253005dc9db107ee83cbbebc9e47a9af1e400bcd47697f1511ceab23a399b0da854488fc7220482ac9
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-dismissable-layer@npm:1.1.11":
+ version: 1.1.11
+ resolution: "@radix-ui/react-dismissable-layer@npm:1.1.11"
+ dependencies:
+ "@radix-ui/primitive": "npm:1.1.3"
+ "@radix-ui/react-compose-refs": "npm:1.1.2"
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ "@radix-ui/react-use-callback-ref": "npm:1.1.1"
+ "@radix-ui/react-use-escape-keydown": "npm: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
+ checksum: 10c0/c825572a64073c4d3853702029979f6658770ffd6a98eabc4984e1dee1b226b4078a2a4dc7003f96475b438985e9b21a58e75f51db74dd06848dcae1f2d395dc
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-dropdown-menu@npm:^2.1.16":
+ version: 2.1.16
+ resolution: "@radix-ui/react-dropdown-menu@npm:2.1.16"
+ dependencies:
+ "@radix-ui/primitive": "npm:1.1.3"
+ "@radix-ui/react-compose-refs": "npm:1.1.2"
+ "@radix-ui/react-context": "npm:1.1.2"
+ "@radix-ui/react-id": "npm:1.1.1"
+ "@radix-ui/react-menu": "npm:2.1.16"
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ "@radix-ui/react-use-controllable-state": "npm:1.2.2"
+ 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
+ checksum: 10c0/8caaa8dd791ccb284568720adafa59855e13860aa29eb20e10a04ba671cbbfa519a4c5d3a339a4d9fb08009eeb1065f4a8b5c3c8ef45e9753161cc560106b935
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-focus-guards@npm:1.1.3":
+ version: 1.1.3
+ resolution: "@radix-ui/react-focus-guards@npm:1.1.3"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/0bab65eb8d7e4f72f685d63de7fbba2450e3cb15ad6a20a16b42195e9d335c576356f5a47cb58d1ffc115393e46d7b14b12c5d4b10029b0ec090861255866985
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-focus-scope@npm:1.1.7":
+ version: 1.1.7
+ resolution: "@radix-ui/react-focus-scope@npm:1.1.7"
+ dependencies:
+ "@radix-ui/react-compose-refs": "npm:1.1.2"
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ "@radix-ui/react-use-callback-ref": "npm: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
+ checksum: 10c0/8a6071331bdeeb79b223463de75caf759b8ad19339cab838e537b8dbb2db236891a1f4df252445c854d375d43d9d315dfcce0a6b01553a2984ec372bb8f1300e
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-id@npm:1.1.1":
+ version: 1.1.1
+ resolution: "@radix-ui/react-id@npm:1.1.1"
+ dependencies:
+ "@radix-ui/react-use-layout-effect": "npm:1.1.1"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/7d12e76818763d592c331277ef62b197e2e64945307e650bd058f0090e5ae48bbd07691b23b7e9e977901ef4eadcb3e2d5eaeb17a13859083384be83fc1292c7
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-menu@npm:2.1.16":
+ version: 2.1.16
+ resolution: "@radix-ui/react-menu@npm:2.1.16"
+ dependencies:
+ "@radix-ui/primitive": "npm:1.1.3"
+ "@radix-ui/react-collection": "npm:1.1.7"
+ "@radix-ui/react-compose-refs": "npm:1.1.2"
+ "@radix-ui/react-context": "npm:1.1.2"
+ "@radix-ui/react-direction": "npm:1.1.1"
+ "@radix-ui/react-dismissable-layer": "npm:1.1.11"
+ "@radix-ui/react-focus-guards": "npm:1.1.3"
+ "@radix-ui/react-focus-scope": "npm:1.1.7"
+ "@radix-ui/react-id": "npm:1.1.1"
+ "@radix-ui/react-popper": "npm:1.2.8"
+ "@radix-ui/react-portal": "npm:1.1.9"
+ "@radix-ui/react-presence": "npm:1.1.5"
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ "@radix-ui/react-roving-focus": "npm:1.1.11"
+ "@radix-ui/react-slot": "npm:1.2.3"
+ "@radix-ui/react-use-callback-ref": "npm:1.1.1"
+ aria-hidden: "npm:^1.2.4"
+ react-remove-scroll: "npm:^2.6.3"
+ 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
+ checksum: 10c0/27516b2b987fa9181c4da8645000af8f60691866a349d7a46b9505fa7d2e9d92b9e364db4f7305d08e9e57d0e1afc8df8354f8ee3c12aa05c0100c16b0e76c27
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-popper@npm:1.2.8":
+ version: 1.2.8
+ resolution: "@radix-ui/react-popper@npm:1.2.8"
+ dependencies:
+ "@floating-ui/react-dom": "npm:^2.0.0"
+ "@radix-ui/react-arrow": "npm:1.1.7"
+ "@radix-ui/react-compose-refs": "npm:1.1.2"
+ "@radix-ui/react-context": "npm:1.1.2"
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ "@radix-ui/react-use-callback-ref": "npm:1.1.1"
+ "@radix-ui/react-use-layout-effect": "npm:1.1.1"
+ "@radix-ui/react-use-rect": "npm:1.1.1"
+ "@radix-ui/react-use-size": "npm:1.1.1"
+ "@radix-ui/rect": "npm: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
+ checksum: 10c0/48e3f13eac3b8c13aca8ded37d74db17e1bb294da8d69f142ab6b8719a06c3f90051668bed64520bf9f3abdd77b382ce7ce209d056bb56137cecc949b69b421c
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-portal@npm:1.1.9":
+ version: 1.1.9
+ resolution: "@radix-ui/react-portal@npm:1.1.9"
+ dependencies:
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ "@radix-ui/react-use-layout-effect": "npm: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
+ checksum: 10c0/45b432497c722720c72c493a29ef6085bc84b50eafe79d48b45c553121b63e94f9cdb77a3a74b9c49126f8feb3feee009fe400d48b7759d3552396356b192cd7
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-presence@npm:1.1.5":
+ version: 1.1.5
+ resolution: "@radix-ui/react-presence@npm:1.1.5"
+ dependencies:
+ "@radix-ui/react-compose-refs": "npm:1.1.2"
+ "@radix-ui/react-use-layout-effect": "npm: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
+ checksum: 10c0/d0e61d314250eeaef5369983cb790701d667f51734bafd98cf759072755562018052c594e6cdc5389789f4543cb0a4d98f03ff4e8f37338d6b5bf51a1700c1d1
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-primitive@npm:2.1.3":
+ version: 2.1.3
+ resolution: "@radix-ui/react-primitive@npm:2.1.3"
+ dependencies:
+ "@radix-ui/react-slot": "npm:1.2.3"
+ 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
+ checksum: 10c0/fdff9b84913bb4172ef6d3af7442fca5f9bba5f2709cba08950071f819d7057aec3a4a2d9ef44cf9cbfb8014d02573c6884a04cff175895823aaef809ebdb034
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-primitive@npm:2.1.4":
+ version: 2.1.4
+ resolution: "@radix-ui/react-primitive@npm:2.1.4"
+ dependencies:
+ "@radix-ui/react-slot": "npm:1.2.4"
+ 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
+ checksum: 10c0/90d687b222a25975371ed1f9f08648d75237214b8dec4cbaf09ec9ac951339b17421278f1aff2fb7c5672ba8bd03774a94904efdba73805dd5cc947ce5be8c4a
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-roving-focus@npm:1.1.11":
+ version: 1.1.11
+ resolution: "@radix-ui/react-roving-focus@npm:1.1.11"
+ dependencies:
+ "@radix-ui/primitive": "npm:1.1.3"
+ "@radix-ui/react-collection": "npm:1.1.7"
+ "@radix-ui/react-compose-refs": "npm:1.1.2"
+ "@radix-ui/react-context": "npm:1.1.2"
+ "@radix-ui/react-direction": "npm:1.1.1"
+ "@radix-ui/react-id": "npm:1.1.1"
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ "@radix-ui/react-use-callback-ref": "npm:1.1.1"
+ "@radix-ui/react-use-controllable-state": "npm:1.2.2"
+ 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
+ checksum: 10c0/2cd43339c36e89a3bf1db8aab34b939113dfbde56bf3a33df2d74757c78c9489b847b1962f1e2441c67e41817d120cb6177943e0f655f47bc1ff8e44fd55b1a2
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-select@npm:^2.2.6":
+ version: 2.2.6
+ resolution: "@radix-ui/react-select@npm:2.2.6"
+ dependencies:
+ "@radix-ui/number": "npm:1.1.1"
+ "@radix-ui/primitive": "npm:1.1.3"
+ "@radix-ui/react-collection": "npm:1.1.7"
+ "@radix-ui/react-compose-refs": "npm:1.1.2"
+ "@radix-ui/react-context": "npm:1.1.2"
+ "@radix-ui/react-direction": "npm:1.1.1"
+ "@radix-ui/react-dismissable-layer": "npm:1.1.11"
+ "@radix-ui/react-focus-guards": "npm:1.1.3"
+ "@radix-ui/react-focus-scope": "npm:1.1.7"
+ "@radix-ui/react-id": "npm:1.1.1"
+ "@radix-ui/react-popper": "npm:1.2.8"
+ "@radix-ui/react-portal": "npm:1.1.9"
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ "@radix-ui/react-slot": "npm:1.2.3"
+ "@radix-ui/react-use-callback-ref": "npm:1.1.1"
+ "@radix-ui/react-use-controllable-state": "npm:1.2.2"
+ "@radix-ui/react-use-layout-effect": "npm:1.1.1"
+ "@radix-ui/react-use-previous": "npm:1.1.1"
+ "@radix-ui/react-visually-hidden": "npm:1.2.3"
+ aria-hidden: "npm:^1.2.4"
+ react-remove-scroll: "npm:^2.6.3"
+ 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
+ checksum: 10c0/34b2492589c3a4b118a03900d622640033630f30ac93c4a69b3701513117607f4ac3a0d9dd3cad39caa8b6495660f71f3aa9d0074d4eb4dac6804dc0b8408deb
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-slot@npm:1.2.3":
+ version: 1.2.3
+ resolution: "@radix-ui/react-slot@npm:1.2.3"
+ dependencies:
+ "@radix-ui/react-compose-refs": "npm:1.1.2"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/5913aa0d760f505905779515e4b1f0f71a422350f077cc8d26d1aafe53c97f177fec0e6d7fbbb50d8b5e498aa9df9f707ca75ae3801540c283b26b0136138eef
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-slot@npm:1.2.4, @radix-ui/react-slot@npm:^1.2.4":
+ version: 1.2.4
+ resolution: "@radix-ui/react-slot@npm:1.2.4"
+ dependencies:
+ "@radix-ui/react-compose-refs": "npm:1.1.2"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/8b719bb934f1ae5ac0e37214783085c17c2f1080217caf514c1c6cc3d9ca56c7e19d25470b26da79aa6e605ab36589edaade149b76f5fc0666f1063e2fc0a0dc
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-tabs@npm:^1.1.13":
+ version: 1.1.13
+ resolution: "@radix-ui/react-tabs@npm:1.1.13"
+ dependencies:
+ "@radix-ui/primitive": "npm:1.1.3"
+ "@radix-ui/react-context": "npm:1.1.2"
+ "@radix-ui/react-direction": "npm:1.1.1"
+ "@radix-ui/react-id": "npm:1.1.1"
+ "@radix-ui/react-presence": "npm:1.1.5"
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ "@radix-ui/react-roving-focus": "npm:1.1.11"
+ "@radix-ui/react-use-controllable-state": "npm:1.2.2"
+ 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
+ checksum: 10c0/a3c78cd8c30dcb95faf1605a8424a1a71dab121dfa6e9c0019bb30d0f36d882762c925b17596d4977990005a255d8ddc0b7454e4f83337fe557b45570a2d8058
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-tooltip@npm:^1.2.8":
+ version: 1.2.8
+ resolution: "@radix-ui/react-tooltip@npm:1.2.8"
+ dependencies:
+ "@radix-ui/primitive": "npm:1.1.3"
+ "@radix-ui/react-compose-refs": "npm:1.1.2"
+ "@radix-ui/react-context": "npm:1.1.2"
+ "@radix-ui/react-dismissable-layer": "npm:1.1.11"
+ "@radix-ui/react-id": "npm:1.1.1"
+ "@radix-ui/react-popper": "npm:1.2.8"
+ "@radix-ui/react-portal": "npm:1.1.9"
+ "@radix-ui/react-presence": "npm:1.1.5"
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ "@radix-ui/react-slot": "npm:1.2.3"
+ "@radix-ui/react-use-controllable-state": "npm:1.2.2"
+ "@radix-ui/react-visually-hidden": "npm:1.2.3"
+ 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
+ checksum: 10c0/de0cbae9c571a00671f160928d819e59502f59be8749f536ab4b180181d9d70aee3925a5b2555f8f32d0bea622bc35f65b70ca7ff0449e4844f891302310cc48
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-use-callback-ref@npm:1.1.1":
+ version: 1.1.1
+ resolution: "@radix-ui/react-use-callback-ref@npm:1.1.1"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/5f6aff8592dea6a7e46589808912aba3fb3b626cf6edd2b14f01638b61dbbe49eeb9f67cd5601f4c15b2fb547b9a7e825f7c4961acd4dd70176c969ae405f8d8
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-use-controllable-state@npm:1.2.2":
+ version: 1.2.2
+ resolution: "@radix-ui/react-use-controllable-state@npm:1.2.2"
+ dependencies:
+ "@radix-ui/react-use-effect-event": "npm:0.0.2"
+ "@radix-ui/react-use-layout-effect": "npm:1.1.1"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/f55c4b06e895293aed4b44c9ef26fb24432539f5346fcd6519c7745800535b571058685314e83486a45bf61dc83887e24826490d3068acc317fb0a9010516e63
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-use-effect-event@npm:0.0.2":
+ version: 0.0.2
+ resolution: "@radix-ui/react-use-effect-event@npm:0.0.2"
+ dependencies:
+ "@radix-ui/react-use-layout-effect": "npm:1.1.1"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/e84ff72a3e76c5ae9c94941028bb4b6472f17d4104481b9eab773deab3da640ecea035e54da9d6f4df8d84c18ef6913baf92b7511bee06930dc58bd0c0add417
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-use-escape-keydown@npm:1.1.1":
+ version: 1.1.1
+ resolution: "@radix-ui/react-use-escape-keydown@npm:1.1.1"
+ dependencies:
+ "@radix-ui/react-use-callback-ref": "npm:1.1.1"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/bff53be99e940fef1d3c4df7d560e1d9133182e5a98336255d3063327d1d3dd4ec54a95dc5afe15cca4fb6c184f0a956c70de2815578c318cf995a7f9beabaa1
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-use-is-hydrated@npm:0.1.0":
+ version: 0.1.0
+ resolution: "@radix-ui/react-use-is-hydrated@npm:0.1.0"
+ dependencies:
+ use-sync-external-store: "npm:^1.5.0"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/635079bafe32829fc7405895154568ea94a22689b170489fd6d77668e4885e72ff71ed6d0ea3d602852841ef0f1927aa400fee2178d5dfbeb8bc9297da7d6498
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-use-layout-effect@npm:1.1.1":
+ version: 1.1.1
+ resolution: "@radix-ui/react-use-layout-effect@npm:1.1.1"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/9f98fdaba008dfc58050de60a77670b885792df473cf82c1cef8daee919a5dd5a77d270209f5f0b0abfaac78cb1627396e3ff56c81b735be550409426fe8b040
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-use-previous@npm:1.1.1":
+ version: 1.1.1
+ resolution: "@radix-ui/react-use-previous@npm:1.1.1"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/52f1089d941491cd59b7f52a5679a14e9381711419a0557ce0f3bc9a4c117078224efec54dcced41a3653a13a386a7b6ec75435d61a273e8b9f5d00235f2b182
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-use-rect@npm:1.1.1":
+ version: 1.1.1
+ resolution: "@radix-ui/react-use-rect@npm:1.1.1"
+ dependencies:
+ "@radix-ui/rect": "npm:1.1.1"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/271711404c05c589c8dbdaa748749e7daf44bcc6bffc9ecd910821c3ebca0ee245616cf5b39653ce690f53f875c3836fd3f36f51ab1c628273b6db599eee4864
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-use-size@npm:1.1.1":
+ version: 1.1.1
+ resolution: "@radix-ui/react-use-size@npm:1.1.1"
+ dependencies:
+ "@radix-ui/react-use-layout-effect": "npm:1.1.1"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/851d09a816f44282e0e9e2147b1b571410174cc048703a50c4fa54d672de994fd1dfff1da9d480ecfd12c77ae8f48d74f01adaf668f074156b8cd0043c6c21d8
+ languageName: node
+ linkType: hard
+
+"@radix-ui/react-visually-hidden@npm:1.2.3":
+ version: 1.2.3
+ resolution: "@radix-ui/react-visually-hidden@npm:1.2.3"
+ dependencies:
+ "@radix-ui/react-primitive": "npm:2.1.3"
+ 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
+ checksum: 10c0/cf86a37f1cbee50a964056f3dc4f6bb1ee79c76daa321f913aa20ff3e1ccdfafbf2b114d7bb616aeefc7c4b895e6ca898523fdb67710d89bd5d8edb739a0d9b6
+ languageName: node
+ linkType: hard
+
+"@radix-ui/rect@npm:1.1.1":
+ version: 1.1.1
+ resolution: "@radix-ui/rect@npm:1.1.1"
+ checksum: 10c0/0dac4f0f15691199abe6a0e067821ddd9d0349c0c05f39834e4eafc8403caf724106884035ae91bbc826e10367e6a5672e7bec4d4243860fa7649de246b1f60b
+ languageName: node
+ linkType: hard
+
+"@reduxjs/toolkit@npm:^1.9.0 || 2.x.x":
+ version: 2.11.2
+ resolution: "@reduxjs/toolkit@npm:2.11.2"
+ dependencies:
+ "@standard-schema/spec": "npm:^1.0.0"
+ "@standard-schema/utils": "npm:^0.3.0"
+ immer: "npm:^11.0.0"
+ redux: "npm:^5.0.1"
+ redux-thunk: "npm:^3.1.0"
+ reselect: "npm:^5.1.0"
+ peerDependencies:
+ react: ^16.9.0 || ^17.0.0 || ^18 || ^19
+ react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0
+ peerDependenciesMeta:
+ react:
+ optional: true
+ react-redux:
+ optional: true
+ checksum: 10c0/4d388b96dc4b12a577af23607c252b3647c1b3b5136dbb0212e1dbbef9bb309e93d3ba6a95795ee165e87e4286453025cd67a98b5b3bb6d244b93ea487dd1ac0
+ languageName: node
+ linkType: hard
+
+"@rolldown/pluginutils@npm:1.0.0-beta.27":
+ version: 1.0.0-beta.27
+ resolution: "@rolldown/pluginutils@npm:1.0.0-beta.27"
+ checksum: 10c0/9658f235b345201d4f6bfb1f32da9754ca164f892d1cb68154fe5f53c1df42bd675ecd409836dff46884a7847d6c00bdc38af870f7c81e05bba5c2645eb4ab9c
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-android-arm-eabi@npm:4.59.0":
+ version: 4.59.0
+ resolution: "@rollup/rollup-android-arm-eabi@npm:4.59.0"
+ conditions: os=android & cpu=arm
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-android-arm64@npm:4.59.0":
+ version: 4.59.0
+ resolution: "@rollup/rollup-android-arm64@npm:4.59.0"
+ conditions: os=android & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-darwin-arm64@npm:4.59.0":
+ version: 4.59.0
+ resolution: "@rollup/rollup-darwin-arm64@npm:4.59.0"
+ conditions: os=darwin & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-darwin-x64@npm:4.59.0":
+ version: 4.59.0
+ resolution: "@rollup/rollup-darwin-x64@npm:4.59.0"
+ conditions: os=darwin & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-freebsd-arm64@npm:4.59.0":
+ version: 4.59.0
+ resolution: "@rollup/rollup-freebsd-arm64@npm:4.59.0"
+ conditions: os=freebsd & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-freebsd-x64@npm:4.59.0":
+ version: 4.59.0
+ resolution: "@rollup/rollup-freebsd-x64@npm:4.59.0"
+ conditions: os=freebsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-arm-gnueabihf@npm:4.59.0":
+ version: 4.59.0
+ resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.59.0"
+ conditions: os=linux & cpu=arm & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-arm-musleabihf@npm:4.59.0":
+ version: 4.59.0
+ resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.59.0"
+ conditions: os=linux & cpu=arm & libc=musl
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-arm64-gnu@npm:4.59.0":
+ version: 4.59.0
+ resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.59.0"
+ conditions: os=linux & cpu=arm64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-arm64-musl@npm:4.59.0":
+ version: 4.59.0
+ resolution: "@rollup/rollup-linux-arm64-musl@npm:4.59.0"
+ conditions: os=linux & cpu=arm64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-loong64-gnu@npm:4.59.0":
+ version: 4.59.0
+ resolution: "@rollup/rollup-linux-loong64-gnu@npm:4.59.0"
+ conditions: os=linux & cpu=loong64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-loong64-musl@npm:4.59.0":
+ version: 4.59.0
+ resolution: "@rollup/rollup-linux-loong64-musl@npm:4.59.0"
+ conditions: os=linux & cpu=loong64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-ppc64-gnu@npm:4.59.0":
+ version: 4.59.0
+ resolution: "@rollup/rollup-linux-ppc64-gnu@npm:4.59.0"
+ conditions: os=linux & cpu=ppc64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-ppc64-musl@npm:4.59.0":
+ version: 4.59.0
+ resolution: "@rollup/rollup-linux-ppc64-musl@npm:4.59.0"
+ conditions: os=linux & cpu=ppc64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-riscv64-gnu@npm:4.59.0":
+ version: 4.59.0
+ resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.59.0"
+ conditions: os=linux & cpu=riscv64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-riscv64-musl@npm:4.59.0":
+ version: 4.59.0
+ resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.59.0"
+ conditions: os=linux & cpu=riscv64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-s390x-gnu@npm:4.59.0":
+ version: 4.59.0
+ resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.59.0"
+ conditions: os=linux & cpu=s390x & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-x64-gnu@npm:4.59.0":
+ version: 4.59.0
+ resolution: "@rollup/rollup-linux-x64-gnu@npm:4.59.0"
+ conditions: os=linux & cpu=x64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-x64-musl@npm:4.59.0":
+ version: 4.59.0
+ resolution: "@rollup/rollup-linux-x64-musl@npm:4.59.0"
+ conditions: os=linux & cpu=x64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-openbsd-x64@npm:4.59.0":
+ version: 4.59.0
+ resolution: "@rollup/rollup-openbsd-x64@npm:4.59.0"
+ conditions: os=openbsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-openharmony-arm64@npm:4.59.0":
+ version: 4.59.0
+ resolution: "@rollup/rollup-openharmony-arm64@npm:4.59.0"
+ conditions: os=openharmony & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-win32-arm64-msvc@npm:4.59.0":
+ version: 4.59.0
+ resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.59.0"
+ conditions: os=win32 & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-win32-ia32-msvc@npm:4.59.0":
+ version: 4.59.0
+ resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.59.0"
+ conditions: os=win32 & cpu=ia32
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-win32-x64-gnu@npm:4.59.0":
+ version: 4.59.0
+ resolution: "@rollup/rollup-win32-x64-gnu@npm:4.59.0"
+ conditions: os=win32 & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-win32-x64-msvc@npm:4.59.0":
+ version: 4.59.0
+ resolution: "@rollup/rollup-win32-x64-msvc@npm:4.59.0"
+ conditions: os=win32 & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@rtsao/scc@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "@rtsao/scc@npm:1.1.0"
+ checksum: 10c0/b5bcfb0d87f7d1c1c7c0f7693f53b07866ed9fec4c34a97a8c948fb9a7c0082e416ce4d3b60beb4f5e167cbe04cdeefbf6771320f3ede059b9ce91188c409a5b
+ languageName: node
+ linkType: hard
+
+"@rushstack/eslint-patch@npm:^1.10.3":
+ version: 1.16.1
+ resolution: "@rushstack/eslint-patch@npm:1.16.1"
+ checksum: 10c0/4928bac90e52ed15e3a9a2a5bcd89e69b24141773fc3689aa6f1ee8c4d2576c4f0fe0fb1be080b7989cc44dfef7c52cf0a1940f8ded9e78a464cf4bc76e8cab3
+ languageName: node
+ linkType: hard
+
+"@standard-schema/spec@npm:^1.0.0":
+ version: 1.1.0
+ resolution: "@standard-schema/spec@npm:1.1.0"
+ checksum: 10c0/d90f55acde4b2deb983529c87e8025fa693de1a5e8b49ecc6eb84d1fd96328add0e03d7d551442156c7432fd78165b2c26ff561b970a9a881f046abb78d6a526
+ languageName: node
+ linkType: hard
+
+"@standard-schema/utils@npm:^0.3.0":
+ version: 0.3.0
+ resolution: "@standard-schema/utils@npm:0.3.0"
+ checksum: 10c0/6eb74cd13e52d5fc74054df51e37d947ef53f3ab9e02c085665dcca3c38c60ece8d735cebbdf18fbb13c775fbcb9becb3f53109b0e092a63f0f7389ce0993fd0
+ languageName: node
+ linkType: hard
+
+"@swc/helpers@npm:0.5.15":
+ version: 0.5.15
+ resolution: "@swc/helpers@npm:0.5.15"
+ dependencies:
+ tslib: "npm:^2.8.0"
+ checksum: 10c0/33002f74f6f885f04c132960835fdfc474186983ea567606db62e86acd0680ca82f34647e8e610f4e1e422d1c16fce729dde22cd3b797ab1fd9061a825dabca4
+ languageName: node
+ linkType: hard
+
+"@tailwindcss/node@npm:4.2.1":
+ version: 4.2.1
+ resolution: "@tailwindcss/node@npm:4.2.1"
+ dependencies:
+ "@jridgewell/remapping": "npm:^2.3.5"
+ enhanced-resolve: "npm:^5.19.0"
+ jiti: "npm:^2.6.1"
+ lightningcss: "npm:1.31.1"
+ magic-string: "npm:^0.30.21"
+ source-map-js: "npm:^1.2.1"
+ tailwindcss: "npm:4.2.1"
+ checksum: 10c0/7b1bf77d2d714df98201cc2f308bee8edfebaf2ef520ec15cb9515e2aadabb28b4d2ecb165dd278716b3f6767da10e4d9a445de34ee8f7ec056fc9c1d8e275a1
+ languageName: node
+ linkType: hard
+
+"@tailwindcss/oxide-android-arm64@npm:4.2.1":
+ version: 4.2.1
+ resolution: "@tailwindcss/oxide-android-arm64@npm:4.2.1"
+ conditions: os=android & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@tailwindcss/oxide-darwin-arm64@npm:4.2.1":
+ version: 4.2.1
+ resolution: "@tailwindcss/oxide-darwin-arm64@npm:4.2.1"
+ conditions: os=darwin & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@tailwindcss/oxide-darwin-x64@npm:4.2.1":
+ version: 4.2.1
+ resolution: "@tailwindcss/oxide-darwin-x64@npm:4.2.1"
+ conditions: os=darwin & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@tailwindcss/oxide-freebsd-x64@npm:4.2.1":
+ version: 4.2.1
+ resolution: "@tailwindcss/oxide-freebsd-x64@npm:4.2.1"
+ conditions: os=freebsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@tailwindcss/oxide-linux-arm-gnueabihf@npm:4.2.1":
+ version: 4.2.1
+ resolution: "@tailwindcss/oxide-linux-arm-gnueabihf@npm:4.2.1"
+ conditions: os=linux & cpu=arm
+ languageName: node
+ linkType: hard
+
+"@tailwindcss/oxide-linux-arm64-gnu@npm:4.2.1":
+ version: 4.2.1
+ resolution: "@tailwindcss/oxide-linux-arm64-gnu@npm:4.2.1"
+ conditions: os=linux & cpu=arm64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@tailwindcss/oxide-linux-arm64-musl@npm:4.2.1":
+ version: 4.2.1
+ resolution: "@tailwindcss/oxide-linux-arm64-musl@npm:4.2.1"
+ conditions: os=linux & cpu=arm64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@tailwindcss/oxide-linux-x64-gnu@npm:4.2.1":
+ version: 4.2.1
+ resolution: "@tailwindcss/oxide-linux-x64-gnu@npm:4.2.1"
+ conditions: os=linux & cpu=x64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@tailwindcss/oxide-linux-x64-musl@npm:4.2.1":
+ version: 4.2.1
+ resolution: "@tailwindcss/oxide-linux-x64-musl@npm:4.2.1"
+ conditions: os=linux & cpu=x64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@tailwindcss/oxide-wasm32-wasi@npm:4.2.1":
+ version: 4.2.1
+ resolution: "@tailwindcss/oxide-wasm32-wasi@npm:4.2.1"
+ dependencies:
+ "@emnapi/core": "npm:^1.8.1"
+ "@emnapi/runtime": "npm:^1.8.1"
+ "@emnapi/wasi-threads": "npm:^1.1.0"
+ "@napi-rs/wasm-runtime": "npm:^1.1.1"
+ "@tybys/wasm-util": "npm:^0.10.1"
+ tslib: "npm:^2.8.1"
+ conditions: cpu=wasm32
+ languageName: node
+ linkType: hard
+
+"@tailwindcss/oxide-win32-arm64-msvc@npm:4.2.1":
+ version: 4.2.1
+ resolution: "@tailwindcss/oxide-win32-arm64-msvc@npm:4.2.1"
+ conditions: os=win32 & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@tailwindcss/oxide-win32-x64-msvc@npm:4.2.1":
+ version: 4.2.1
+ resolution: "@tailwindcss/oxide-win32-x64-msvc@npm:4.2.1"
+ conditions: os=win32 & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@tailwindcss/oxide@npm:4.2.1":
+ version: 4.2.1
+ resolution: "@tailwindcss/oxide@npm:4.2.1"
+ dependencies:
+ "@tailwindcss/oxide-android-arm64": "npm:4.2.1"
+ "@tailwindcss/oxide-darwin-arm64": "npm:4.2.1"
+ "@tailwindcss/oxide-darwin-x64": "npm:4.2.1"
+ "@tailwindcss/oxide-freebsd-x64": "npm:4.2.1"
+ "@tailwindcss/oxide-linux-arm-gnueabihf": "npm:4.2.1"
+ "@tailwindcss/oxide-linux-arm64-gnu": "npm:4.2.1"
+ "@tailwindcss/oxide-linux-arm64-musl": "npm:4.2.1"
+ "@tailwindcss/oxide-linux-x64-gnu": "npm:4.2.1"
+ "@tailwindcss/oxide-linux-x64-musl": "npm:4.2.1"
+ "@tailwindcss/oxide-wasm32-wasi": "npm:4.2.1"
+ "@tailwindcss/oxide-win32-arm64-msvc": "npm:4.2.1"
+ "@tailwindcss/oxide-win32-x64-msvc": "npm:4.2.1"
+ dependenciesMeta:
+ "@tailwindcss/oxide-android-arm64":
+ optional: true
+ "@tailwindcss/oxide-darwin-arm64":
+ optional: true
+ "@tailwindcss/oxide-darwin-x64":
+ optional: true
+ "@tailwindcss/oxide-freebsd-x64":
+ optional: true
+ "@tailwindcss/oxide-linux-arm-gnueabihf":
+ optional: true
+ "@tailwindcss/oxide-linux-arm64-gnu":
+ optional: true
+ "@tailwindcss/oxide-linux-arm64-musl":
+ optional: true
+ "@tailwindcss/oxide-linux-x64-gnu":
+ optional: true
+ "@tailwindcss/oxide-linux-x64-musl":
+ optional: true
+ "@tailwindcss/oxide-wasm32-wasi":
+ optional: true
+ "@tailwindcss/oxide-win32-arm64-msvc":
+ optional: true
+ "@tailwindcss/oxide-win32-x64-msvc":
+ optional: true
+ checksum: 10c0/4f9bfa40cde6925eed1759caf857831779a834a1b8776cc7df5bb48a279b7dcd2e761a31ffbd297d135a64b58f25e092d7c781c06cf44667746f7e5a5a3e0183
+ languageName: node
+ linkType: hard
+
+"@tailwindcss/postcss@npm:^4.1.3":
+ version: 4.2.1
+ resolution: "@tailwindcss/postcss@npm:4.2.1"
+ dependencies:
+ "@alloc/quick-lru": "npm:^5.2.0"
+ "@tailwindcss/node": "npm:4.2.1"
+ "@tailwindcss/oxide": "npm:4.2.1"
+ postcss: "npm:^8.5.6"
+ tailwindcss: "npm:4.2.1"
+ checksum: 10c0/c9869a10c284241b2e51ba25750ae711d1ac3187356093c3a047eb8139124e73412036de7a11ad5c145360a312dcdebde59849f6d65e6296cba525186a8243f6
+ languageName: node
+ linkType: hard
+
+"@tybys/wasm-util@npm:^0.10.0, @tybys/wasm-util@npm:^0.10.1":
+ version: 0.10.1
+ resolution: "@tybys/wasm-util@npm:0.10.1"
+ dependencies:
+ tslib: "npm:^2.4.0"
+ checksum: 10c0/b255094f293794c6d2289300c5fbcafbb5532a3aed3a5ffd2f8dc1828e639b88d75f6a376dd8f94347a44813fd7a7149d8463477a9a49525c8b2dcaa38c2d1e8
+ languageName: node
+ linkType: hard
+
+"@types/babel__core@npm:^7.20.5":
+ version: 7.20.5
+ resolution: "@types/babel__core@npm:7.20.5"
+ dependencies:
+ "@babel/parser": "npm:^7.20.7"
+ "@babel/types": "npm:^7.20.7"
+ "@types/babel__generator": "npm:*"
+ "@types/babel__template": "npm:*"
+ "@types/babel__traverse": "npm:*"
+ checksum: 10c0/bdee3bb69951e833a4b811b8ee9356b69a61ed5b7a23e1a081ec9249769117fa83aaaf023bb06562a038eb5845155ff663e2d5c75dd95c1d5ccc91db012868ff
+ languageName: node
+ linkType: hard
+
+"@types/babel__generator@npm:*":
+ version: 7.27.0
+ resolution: "@types/babel__generator@npm:7.27.0"
+ dependencies:
+ "@babel/types": "npm:^7.0.0"
+ checksum: 10c0/9f9e959a8792df208a9d048092fda7e1858bddc95c6314857a8211a99e20e6830bdeb572e3587ae8be5429e37f2a96fcf222a9f53ad232f5537764c9e13a2bbd
+ languageName: node
+ linkType: hard
+
+"@types/babel__template@npm:*":
+ version: 7.4.4
+ resolution: "@types/babel__template@npm:7.4.4"
+ dependencies:
+ "@babel/parser": "npm:^7.1.0"
+ "@babel/types": "npm:^7.0.0"
+ checksum: 10c0/cc84f6c6ab1eab1427e90dd2b76ccee65ce940b778a9a67be2c8c39e1994e6f5bbc8efa309f6cea8dc6754994524cd4d2896558df76d92e7a1f46ecffee7112b
+ languageName: node
+ linkType: hard
+
+"@types/babel__traverse@npm:*":
+ version: 7.28.0
+ resolution: "@types/babel__traverse@npm:7.28.0"
+ dependencies:
+ "@babel/types": "npm:^7.28.2"
+ checksum: 10c0/b52d7d4e8fc6a9018fe7361c4062c1c190f5778cf2466817cb9ed19d69fbbb54f9a85ffedeb748ed8062d2cf7d4cc088ee739848f47c57740de1c48cbf0d0994
+ languageName: node
+ linkType: hard
+
+"@types/bcryptjs@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "@types/bcryptjs@npm:3.0.0"
+ dependencies:
+ bcryptjs: "npm:*"
+ checksum: 10c0/5d61ce381736f8252627cf32f2bbc17003c0361c6cf63ac23034a651b9c1edfdbf8f786730816e0b5257a927ffa369658562183a68495eb07ca2ddc77fbb171c
+ languageName: node
+ linkType: hard
+
+"@types/chai@npm:^5.2.2":
+ version: 5.2.3
+ resolution: "@types/chai@npm:5.2.3"
+ dependencies:
+ "@types/deep-eql": "npm:*"
+ assertion-error: "npm:^2.0.1"
+ checksum: 10c0/e0ef1de3b6f8045a5e473e867c8565788c444271409d155588504840ad1a53611011f85072188c2833941189400228c1745d78323dac13fcede9c2b28bacfb2f
+ languageName: node
+ linkType: hard
+
+"@types/d3-array@npm:^3.0.3":
+ version: 3.2.2
+ resolution: "@types/d3-array@npm:3.2.2"
+ checksum: 10c0/6137cb97302f8a4f18ca22c0560c585cfcb823f276b23d89f2c0c005d72697ec13bca671c08e68b4b0cabd622e3f0e91782ee221580d6774074050be96dd7028
+ languageName: node
+ linkType: hard
+
+"@types/d3-color@npm:*":
+ version: 3.1.3
+ resolution: "@types/d3-color@npm:3.1.3"
+ checksum: 10c0/65eb0487de606eb5ad81735a9a5b3142d30bc5ea801ed9b14b77cb14c9b909f718c059f13af341264ee189acf171508053342142bdf99338667cea26a2d8d6ae
+ languageName: node
+ linkType: hard
+
+"@types/d3-ease@npm:^3.0.0":
+ version: 3.0.2
+ resolution: "@types/d3-ease@npm:3.0.2"
+ checksum: 10c0/aff5a1e572a937ee9bff6465225d7ba27d5e0c976bd9eacdac2e6f10700a7cb0c9ea2597aff6b43a6ed850a3210030870238894a77ec73e309b4a9d0333f099c
+ languageName: node
+ linkType: hard
+
+"@types/d3-interpolate@npm:^3.0.1":
+ version: 3.0.4
+ resolution: "@types/d3-interpolate@npm:3.0.4"
+ dependencies:
+ "@types/d3-color": "npm:*"
+ checksum: 10c0/066ebb8da570b518dd332df6b12ae3b1eaa0a7f4f0c702e3c57f812cf529cc3500ec2aac8dc094f31897790346c6b1ebd8cd7a077176727f4860c2b181a65ca4
+ languageName: node
+ linkType: hard
+
+"@types/d3-path@npm:*":
+ version: 3.1.1
+ resolution: "@types/d3-path@npm:3.1.1"
+ checksum: 10c0/2c36eb31ebaf2ce4712e793fd88087117976f7c4ed69cc2431825f999c8c77cca5cea286f3326432b770739ac6ccd5d04d851eb65e7a4dbcc10c982b49ad2c02
+ languageName: node
+ linkType: hard
+
+"@types/d3-scale@npm:^4.0.2":
+ version: 4.0.9
+ resolution: "@types/d3-scale@npm:4.0.9"
+ dependencies:
+ "@types/d3-time": "npm:*"
+ checksum: 10c0/4ac44233c05cd50b65b33ecb35d99fdf07566bcdbc55bc1306b2f27d1c5134d8c560d356f2c8e76b096e9125ffb8d26d95f78d56e210d1c542cb255bdf31d6c8
+ languageName: node
+ linkType: hard
+
+"@types/d3-shape@npm:^3.1.0":
+ version: 3.1.8
+ resolution: "@types/d3-shape@npm:3.1.8"
+ dependencies:
+ "@types/d3-path": "npm:*"
+ checksum: 10c0/49ec2172b9eb66fc1d036e2a23966216bb972e9af51ddbed134df24bd71aedf207bb1ef81903a119eb4e1f5e927cf44beacaf64c9af86474e5548594b102b574
+ languageName: node
+ linkType: hard
+
+"@types/d3-time@npm:*, @types/d3-time@npm:^3.0.0":
+ version: 3.0.4
+ resolution: "@types/d3-time@npm:3.0.4"
+ checksum: 10c0/6d9e2255d63f7a313a543113920c612e957d70da4fb0890931da6c2459010291b8b1f95e149a538500c1c99e7e6c89ffcce5554dd29a31ff134a38ea94b6d174
+ languageName: node
+ linkType: hard
+
+"@types/d3-timer@npm:^3.0.0":
+ version: 3.0.2
+ resolution: "@types/d3-timer@npm:3.0.2"
+ checksum: 10c0/c644dd9571fcc62b1aa12c03bcad40571553020feeb5811f1d8a937ac1e65b8a04b759b4873aef610e28b8714ac71c9885a4d6c127a048d95118f7e5b506d9e1
+ languageName: node
+ linkType: hard
+
+"@types/debug@npm:^4.0.0":
+ version: 4.1.12
+ resolution: "@types/debug@npm:4.1.12"
+ dependencies:
+ "@types/ms": "npm:*"
+ checksum: 10c0/5dcd465edbb5a7f226e9a5efd1f399c6172407ef5840686b73e3608ce135eeca54ae8037dcd9f16bdb2768ac74925b820a8b9ecc588a58ca09eca6acabe33e2f
+ languageName: node
+ linkType: hard
+
+"@types/deep-eql@npm:*":
+ version: 4.0.2
+ resolution: "@types/deep-eql@npm:4.0.2"
+ checksum: 10c0/bf3f811843117900d7084b9d0c852da9a044d12eb40e6de73b552598a6843c21291a8a381b0532644574beecd5e3491c5ff3a0365ab86b15d59862c025384844
+ languageName: node
+ linkType: hard
+
+"@types/estree-jsx@npm:^1.0.0":
+ version: 1.0.5
+ resolution: "@types/estree-jsx@npm:1.0.5"
+ dependencies:
+ "@types/estree": "npm:*"
+ checksum: 10c0/07b354331516428b27a3ab99ee397547d47eb223c34053b48f84872fafb841770834b90cc1a0068398e7c7ccb15ec51ab00ec64b31dc5e3dbefd624638a35c6d
+ languageName: node
+ linkType: hard
+
+"@types/estree@npm:*, @types/estree@npm:1.0.8, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.6":
+ version: 1.0.8
+ resolution: "@types/estree@npm:1.0.8"
+ checksum: 10c0/39d34d1afaa338ab9763f37ad6066e3f349444f9052b9676a7cc0252ef9485a41c6d81c9c4e0d26e9077993354edf25efc853f3224dd4b447175ef62bdcc86a5
+ languageName: node
+ linkType: hard
+
+"@types/hast@npm:^3.0.0":
+ version: 3.0.4
+ resolution: "@types/hast@npm:3.0.4"
+ dependencies:
+ "@types/unist": "npm:*"
+ checksum: 10c0/3249781a511b38f1d330fd1e3344eed3c4e7ea8eff82e835d35da78e637480d36fad37a78be5a7aed8465d237ad0446abc1150859d0fde395354ea634decf9f7
+ languageName: node
+ linkType: hard
+
+"@types/http-proxy@npm:^1.17.17":
+ version: 1.17.17
+ resolution: "@types/http-proxy@npm:1.17.17"
+ dependencies:
+ "@types/node": "npm:*"
+ checksum: 10c0/547e322a5eecf0b50d08f6a46bd89c8c8663d67dbdcd472da5daf968b03e63a82f6b3650443378abe6c10a46475dac52015f30e8c74ba2ea5820dd4e9cdef2d4
+ languageName: node
+ linkType: hard
+
+"@types/json-schema@npm:^7.0.15":
+ version: 7.0.15
+ resolution: "@types/json-schema@npm:7.0.15"
+ checksum: 10c0/a996a745e6c5d60292f36731dd41341339d4eeed8180bb09226e5c8d23759067692b1d88e5d91d72ee83dfc00d3aca8e7bd43ea120516c17922cbcb7c3e252db
+ languageName: node
+ linkType: hard
+
+"@types/json5@npm:^0.0.29":
+ version: 0.0.29
+ resolution: "@types/json5@npm:0.0.29"
+ checksum: 10c0/6bf5337bc447b706bb5b4431d37686aa2ea6d07cfd6f79cc31de80170d6ff9b1c7384a9c0ccbc45b3f512bae9e9f75c2e12109806a15331dc94e8a8db6dbb4ac
+ languageName: node
+ linkType: hard
+
+"@types/mdast@npm:^4.0.0":
+ version: 4.0.4
+ resolution: "@types/mdast@npm:4.0.4"
+ dependencies:
+ "@types/unist": "npm:*"
+ checksum: 10c0/84f403dbe582ee508fd9c7643ac781ad8597fcbfc9ccb8d4715a2c92e4545e5772cbd0dbdf18eda65789386d81b009967fdef01b24faf6640f817287f54d9c82
+ languageName: node
+ linkType: hard
+
+"@types/ms@npm:*":
+ version: 2.1.0
+ resolution: "@types/ms@npm:2.1.0"
+ checksum: 10c0/5ce692ffe1549e1b827d99ef8ff71187457e0eb44adbae38fdf7b9a74bae8d20642ee963c14516db1d35fa2652e65f47680fdf679dcbde52bbfadd021f497225
+ languageName: node
+ linkType: hard
+
+"@types/node@npm:*":
+ version: 25.5.0
+ resolution: "@types/node@npm:25.5.0"
+ dependencies:
+ undici-types: "npm:~7.18.0"
+ checksum: 10c0/70c508165b6758c4f88d4f91abca526c3985eee1985503d4c2bd994dbaf588e52ac57e571160f18f117d76e963570ac82bd20e743c18987e82564312b3b62119
+ languageName: node
+ linkType: hard
+
+"@types/node@npm:^22.13.10":
+ version: 22.19.15
+ resolution: "@types/node@npm:22.19.15"
+ dependencies:
+ undici-types: "npm:~6.21.0"
+ checksum: 10c0/f17eaf3d0d1da5e93ad9e287efb78201f8a5282973c004c5f70d91675c5c6b926a23acaa7b158a42b3d7e27e36b349d65a531710c91c308fca53dd7fa280ef98
+ languageName: node
+ linkType: hard
+
+"@types/react-dom@npm:^19.1.0":
+ version: 19.2.3
+ resolution: "@types/react-dom@npm:19.2.3"
+ peerDependencies:
+ "@types/react": ^19.2.0
+ checksum: 10c0/b486ebe0f4e2fb35e2e108df1d8fc0927ca5d6002d5771e8a739de11239fe62d0e207c50886185253c99eb9dedfeeb956ea7429e5ba17f6693c7acb4c02f8cd1
+ languageName: node
+ linkType: hard
+
+"@types/react@npm:^19.1.0":
+ version: 19.2.14
+ resolution: "@types/react@npm:19.2.14"
+ dependencies:
+ csstype: "npm:^3.2.2"
+ checksum: 10c0/7d25bf41b57719452d86d2ac0570b659210402707313a36ee612666bf11275a1c69824f8c3ee1fdca077ccfe15452f6da8f1224529b917050eb2d861e52b59b7
+ languageName: node
+ linkType: hard
+
+"@types/unist@npm:*, @types/unist@npm:^3.0.0":
+ version: 3.0.3
+ resolution: "@types/unist@npm:3.0.3"
+ checksum: 10c0/2b1e4adcab78388e088fcc3c0ae8700f76619dbcb4741d7d201f87e2cb346bfc29a89003cfea2d76c996e1061452e14fcd737e8b25aacf949c1f2d6b2bc3dd60
+ languageName: node
+ linkType: hard
+
+"@types/unist@npm:^2.0.0":
+ version: 2.0.11
+ resolution: "@types/unist@npm:2.0.11"
+ checksum: 10c0/24dcdf25a168f453bb70298145eb043cfdbb82472db0bc0b56d6d51cd2e484b9ed8271d4ac93000a80da568f2402e9339723db262d0869e2bf13bc58e081768d
+ languageName: node
+ linkType: hard
+
+"@types/use-sync-external-store@npm:^0.0.6":
+ version: 0.0.6
+ resolution: "@types/use-sync-external-store@npm:0.0.6"
+ checksum: 10c0/77c045a98f57488201f678b181cccd042279aff3da34540ad242f893acc52b358bd0a8207a321b8ac09adbcef36e3236944390e2df4fcedb556ce7bb2a88f2a8
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/eslint-plugin@npm:^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0":
+ version: 8.57.1
+ resolution: "@typescript-eslint/eslint-plugin@npm:8.57.1"
+ dependencies:
+ "@eslint-community/regexpp": "npm:^4.12.2"
+ "@typescript-eslint/scope-manager": "npm:8.57.1"
+ "@typescript-eslint/type-utils": "npm:8.57.1"
+ "@typescript-eslint/utils": "npm:8.57.1"
+ "@typescript-eslint/visitor-keys": "npm:8.57.1"
+ ignore: "npm:^7.0.5"
+ natural-compare: "npm:^1.4.0"
+ ts-api-utils: "npm:^2.4.0"
+ peerDependencies:
+ "@typescript-eslint/parser": ^8.57.1
+ eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
+ typescript: ">=4.8.4 <6.0.0"
+ checksum: 10c0/5bf9227f5d608d4313c9f898da3a2f6737eca985aa925df9e90b73499b9d552221781d3d09245543c6d09995ab262ea0d6773d2dae4b8bdf319765d46b22d0e1
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/parser@npm:^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0":
+ version: 8.57.1
+ resolution: "@typescript-eslint/parser@npm:8.57.1"
+ dependencies:
+ "@typescript-eslint/scope-manager": "npm:8.57.1"
+ "@typescript-eslint/types": "npm:8.57.1"
+ "@typescript-eslint/typescript-estree": "npm:8.57.1"
+ "@typescript-eslint/visitor-keys": "npm:8.57.1"
+ debug: "npm:^4.4.3"
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
+ typescript: ">=4.8.4 <6.0.0"
+ checksum: 10c0/ab624f5ad6f3585ee690d11be36597135779a373e7f07810ed921163de2e879000f6d3213db67413ee630bcf25d5cfaa24b089ee49596cd11b0456372bc17163
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/project-service@npm:8.57.1":
+ version: 8.57.1
+ resolution: "@typescript-eslint/project-service@npm:8.57.1"
+ dependencies:
+ "@typescript-eslint/tsconfig-utils": "npm:^8.57.1"
+ "@typescript-eslint/types": "npm:^8.57.1"
+ debug: "npm:^4.4.3"
+ peerDependencies:
+ typescript: ">=4.8.4 <6.0.0"
+ checksum: 10c0/7830f61e35364ba77799f4badeaca8bd8914bbcda6afe37b788821f94f4b88b9c49817c50f4bdba497e8e542a705e9d921d36f5e67960ebf33f4f3d3111cdfee
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/scope-manager@npm:8.57.1":
+ version: 8.57.1
+ resolution: "@typescript-eslint/scope-manager@npm:8.57.1"
+ dependencies:
+ "@typescript-eslint/types": "npm:8.57.1"
+ "@typescript-eslint/visitor-keys": "npm:8.57.1"
+ checksum: 10c0/42b0b54981318bf21be6b107df82910718497b7b7b2b60df635aa06d78e313759e4b675830c0e542b6d87104d35b49df41b9fb7739b8ae326eaba2d6f7116166
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/tsconfig-utils@npm:8.57.1, @typescript-eslint/tsconfig-utils@npm:^8.57.1":
+ version: 8.57.1
+ resolution: "@typescript-eslint/tsconfig-utils@npm:8.57.1"
+ peerDependencies:
+ typescript: ">=4.8.4 <6.0.0"
+ checksum: 10c0/3d3c8d80621507d31e4656c693534f28a1c04dfb047538cb79b0b6da874ef41875f5df5e814fa3a38812451cff6d5a7ae38d0bf77eb7fec7867f9c80af361b00
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/type-utils@npm:8.57.1":
+ version: 8.57.1
+ resolution: "@typescript-eslint/type-utils@npm:8.57.1"
+ dependencies:
+ "@typescript-eslint/types": "npm:8.57.1"
+ "@typescript-eslint/typescript-estree": "npm:8.57.1"
+ "@typescript-eslint/utils": "npm:8.57.1"
+ debug: "npm:^4.4.3"
+ ts-api-utils: "npm:^2.4.0"
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
+ typescript: ">=4.8.4 <6.0.0"
+ checksum: 10c0/e8eae4e3b9ca71ad065c307fd3cdefdcc6abc31bda2ef74f0e54b5c9ac0ee6bc0e2d69ec9097899f4d7a99d4a8a72391503b47f4317b3b6b9ba41cea24e6b9e9
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/types@npm:8.57.1, @typescript-eslint/types@npm:^8.57.1":
+ version: 8.57.1
+ resolution: "@typescript-eslint/types@npm:8.57.1"
+ checksum: 10c0/f447015276a31871440b07e328c2bbcee8337d72dca90ae00ac91e87d09e28a8a9c2fe44726a5226fcaa7db9d5347aafa650d59f7577a074dc65ea1414d24da1
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/typescript-estree@npm:8.57.1":
+ version: 8.57.1
+ resolution: "@typescript-eslint/typescript-estree@npm:8.57.1"
+ dependencies:
+ "@typescript-eslint/project-service": "npm:8.57.1"
+ "@typescript-eslint/tsconfig-utils": "npm:8.57.1"
+ "@typescript-eslint/types": "npm:8.57.1"
+ "@typescript-eslint/visitor-keys": "npm:8.57.1"
+ debug: "npm:^4.4.3"
+ minimatch: "npm:^10.2.2"
+ semver: "npm:^7.7.3"
+ tinyglobby: "npm:^0.2.15"
+ ts-api-utils: "npm:^2.4.0"
+ peerDependencies:
+ typescript: ">=4.8.4 <6.0.0"
+ checksum: 10c0/a87e1d920a8fd2231b6a98b279dc7680d10ceac072001e85a72cd43adce288ed471afcaf8f171378f5a3221c500b3cf0ffc10a75fd521fb69fbd8b26d4626677
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/utils@npm:8.57.1":
+ version: 8.57.1
+ resolution: "@typescript-eslint/utils@npm:8.57.1"
+ dependencies:
+ "@eslint-community/eslint-utils": "npm:^4.9.1"
+ "@typescript-eslint/scope-manager": "npm:8.57.1"
+ "@typescript-eslint/types": "npm:8.57.1"
+ "@typescript-eslint/typescript-estree": "npm:8.57.1"
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
+ typescript: ">=4.8.4 <6.0.0"
+ checksum: 10c0/c85d6e7c618dbf902fda98cc795883388bc512bc2c34c7ac0481ea43acb6dd3cd38d60bdb571b586f392419a17998c89330fd7b0b9a344161f4a595637dd3f55
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/visitor-keys@npm:8.57.1":
+ version: 8.57.1
+ resolution: "@typescript-eslint/visitor-keys@npm:8.57.1"
+ dependencies:
+ "@typescript-eslint/types": "npm:8.57.1"
+ eslint-visitor-keys: "npm:^5.0.0"
+ checksum: 10c0/088a545c4aec6d9cabb266e1e40634f5fafa06cb05ef172526555957b0d99ac08822733fb788a09227071fdd6bd8b63f054393a0ecf9d4599c54b57918aa0e57
+ languageName: node
+ linkType: hard
+
+"@ungap/structured-clone@npm:^1.0.0":
+ version: 1.3.0
+ resolution: "@ungap/structured-clone@npm:1.3.0"
+ checksum: 10c0/0fc3097c2540ada1fc340ee56d58d96b5b536a2a0dab6e3ec17d4bfc8c4c86db345f61a375a8185f9da96f01c69678f836a2b57eeaa9e4b8eeafd26428e57b0a
+ languageName: node
+ linkType: hard
+
+"@unrs/resolver-binding-android-arm-eabi@npm:1.11.1":
+ version: 1.11.1
+ resolution: "@unrs/resolver-binding-android-arm-eabi@npm:1.11.1"
+ conditions: os=android & cpu=arm
+ languageName: node
+ linkType: hard
+
+"@unrs/resolver-binding-android-arm64@npm:1.11.1":
+ version: 1.11.1
+ resolution: "@unrs/resolver-binding-android-arm64@npm:1.11.1"
+ conditions: os=android & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@unrs/resolver-binding-darwin-arm64@npm:1.11.1":
+ version: 1.11.1
+ resolution: "@unrs/resolver-binding-darwin-arm64@npm:1.11.1"
+ conditions: os=darwin & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@unrs/resolver-binding-darwin-x64@npm:1.11.1":
+ version: 1.11.1
+ resolution: "@unrs/resolver-binding-darwin-x64@npm:1.11.1"
+ conditions: os=darwin & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@unrs/resolver-binding-freebsd-x64@npm:1.11.1":
+ version: 1.11.1
+ resolution: "@unrs/resolver-binding-freebsd-x64@npm:1.11.1"
+ conditions: os=freebsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@unrs/resolver-binding-linux-arm-gnueabihf@npm:1.11.1":
+ version: 1.11.1
+ resolution: "@unrs/resolver-binding-linux-arm-gnueabihf@npm:1.11.1"
+ conditions: os=linux & cpu=arm
+ languageName: node
+ linkType: hard
+
+"@unrs/resolver-binding-linux-arm-musleabihf@npm:1.11.1":
+ version: 1.11.1
+ resolution: "@unrs/resolver-binding-linux-arm-musleabihf@npm:1.11.1"
+ conditions: os=linux & cpu=arm
+ languageName: node
+ linkType: hard
+
+"@unrs/resolver-binding-linux-arm64-gnu@npm:1.11.1":
+ version: 1.11.1
+ resolution: "@unrs/resolver-binding-linux-arm64-gnu@npm:1.11.1"
+ conditions: os=linux & cpu=arm64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@unrs/resolver-binding-linux-arm64-musl@npm:1.11.1":
+ version: 1.11.1
+ resolution: "@unrs/resolver-binding-linux-arm64-musl@npm:1.11.1"
+ conditions: os=linux & cpu=arm64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@unrs/resolver-binding-linux-ppc64-gnu@npm:1.11.1":
+ version: 1.11.1
+ resolution: "@unrs/resolver-binding-linux-ppc64-gnu@npm:1.11.1"
+ conditions: os=linux & cpu=ppc64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@unrs/resolver-binding-linux-riscv64-gnu@npm:1.11.1":
+ version: 1.11.1
+ resolution: "@unrs/resolver-binding-linux-riscv64-gnu@npm:1.11.1"
+ conditions: os=linux & cpu=riscv64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@unrs/resolver-binding-linux-riscv64-musl@npm:1.11.1":
+ version: 1.11.1
+ resolution: "@unrs/resolver-binding-linux-riscv64-musl@npm:1.11.1"
+ conditions: os=linux & cpu=riscv64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@unrs/resolver-binding-linux-s390x-gnu@npm:1.11.1":
+ version: 1.11.1
+ resolution: "@unrs/resolver-binding-linux-s390x-gnu@npm:1.11.1"
+ conditions: os=linux & cpu=s390x & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@unrs/resolver-binding-linux-x64-gnu@npm:1.11.1":
+ version: 1.11.1
+ resolution: "@unrs/resolver-binding-linux-x64-gnu@npm:1.11.1"
+ conditions: os=linux & cpu=x64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@unrs/resolver-binding-linux-x64-musl@npm:1.11.1":
+ version: 1.11.1
+ resolution: "@unrs/resolver-binding-linux-x64-musl@npm:1.11.1"
+ conditions: os=linux & cpu=x64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@unrs/resolver-binding-wasm32-wasi@npm:1.11.1":
+ version: 1.11.1
+ resolution: "@unrs/resolver-binding-wasm32-wasi@npm:1.11.1"
+ dependencies:
+ "@napi-rs/wasm-runtime": "npm:^0.2.11"
+ conditions: cpu=wasm32
+ languageName: node
+ linkType: hard
+
+"@unrs/resolver-binding-win32-arm64-msvc@npm:1.11.1":
+ version: 1.11.1
+ resolution: "@unrs/resolver-binding-win32-arm64-msvc@npm:1.11.1"
+ conditions: os=win32 & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@unrs/resolver-binding-win32-ia32-msvc@npm:1.11.1":
+ version: 1.11.1
+ resolution: "@unrs/resolver-binding-win32-ia32-msvc@npm:1.11.1"
+ conditions: os=win32 & cpu=ia32
+ languageName: node
+ linkType: hard
+
+"@unrs/resolver-binding-win32-x64-msvc@npm:1.11.1":
+ version: 1.11.1
+ resolution: "@unrs/resolver-binding-win32-x64-msvc@npm:1.11.1"
+ conditions: os=win32 & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@vitejs/plugin-react@npm:^4.3.4":
+ version: 4.7.0
+ resolution: "@vitejs/plugin-react@npm:4.7.0"
+ dependencies:
+ "@babel/core": "npm:^7.28.0"
+ "@babel/plugin-transform-react-jsx-self": "npm:^7.27.1"
+ "@babel/plugin-transform-react-jsx-source": "npm:^7.27.1"
+ "@rolldown/pluginutils": "npm:1.0.0-beta.27"
+ "@types/babel__core": "npm:^7.20.5"
+ react-refresh: "npm:^0.17.0"
+ peerDependencies:
+ vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
+ checksum: 10c0/692f23960972879485d647713663ec299c478222c96567d60285acf7c7dc5c178e71abfe9d2eefddef1eeb01514dacbc2ed68aad84628debf9c7116134734253
+ languageName: node
+ linkType: hard
+
+"@vitest/expect@npm:3.2.4":
+ version: 3.2.4
+ resolution: "@vitest/expect@npm:3.2.4"
+ dependencies:
+ "@types/chai": "npm:^5.2.2"
+ "@vitest/spy": "npm:3.2.4"
+ "@vitest/utils": "npm:3.2.4"
+ chai: "npm:^5.2.0"
+ tinyrainbow: "npm:^2.0.0"
+ checksum: 10c0/7586104e3fd31dbe1e6ecaafb9a70131e4197dce2940f727b6a84131eee3decac7b10f9c7c72fa5edbdb68b6f854353bd4c0fa84779e274207fb7379563b10db
+ languageName: node
+ linkType: hard
+
+"@vitest/mocker@npm:3.2.4":
+ version: 3.2.4
+ resolution: "@vitest/mocker@npm:3.2.4"
+ dependencies:
+ "@vitest/spy": "npm:3.2.4"
+ estree-walker: "npm:^3.0.3"
+ magic-string: "npm:^0.30.17"
+ peerDependencies:
+ msw: ^2.4.9
+ vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0
+ peerDependenciesMeta:
+ msw:
+ optional: true
+ vite:
+ optional: true
+ checksum: 10c0/f7a4aea19bbbf8f15905847ee9143b6298b2c110f8b64789224cb0ffdc2e96f9802876aa2ca83f1ec1b6e1ff45e822abb34f0054c24d57b29ab18add06536ccd
+ languageName: node
+ linkType: hard
+
+"@vitest/pretty-format@npm:3.2.4, @vitest/pretty-format@npm:^3.2.4":
+ version: 3.2.4
+ resolution: "@vitest/pretty-format@npm:3.2.4"
+ dependencies:
+ tinyrainbow: "npm:^2.0.0"
+ checksum: 10c0/5ad7d4278e067390d7d633e307fee8103958806a419ca380aec0e33fae71b44a64415f7a9b4bc11635d3c13d4a9186111c581d3cef9c65cc317e68f077456887
+ languageName: node
+ linkType: hard
+
+"@vitest/runner@npm:3.2.4":
+ version: 3.2.4
+ resolution: "@vitest/runner@npm:3.2.4"
+ dependencies:
+ "@vitest/utils": "npm:3.2.4"
+ pathe: "npm:^2.0.3"
+ strip-literal: "npm:^3.0.0"
+ checksum: 10c0/e8be51666c72b3668ae3ea348b0196656a4a5adb836cb5e270720885d9517421815b0d6c98bfdf1795ed02b994b7bfb2b21566ee356a40021f5bf4f6ed4e418a
+ languageName: node
+ linkType: hard
+
+"@vitest/snapshot@npm:3.2.4":
+ version: 3.2.4
+ resolution: "@vitest/snapshot@npm:3.2.4"
+ dependencies:
+ "@vitest/pretty-format": "npm:3.2.4"
+ magic-string: "npm:^0.30.17"
+ pathe: "npm:^2.0.3"
+ checksum: 10c0/f8301a3d7d1559fd3d59ed51176dd52e1ed5c2d23aa6d8d6aa18787ef46e295056bc726a021698d8454c16ed825ecba163362f42fa90258bb4a98cfd2c9424fc
+ languageName: node
+ linkType: hard
+
+"@vitest/spy@npm:3.2.4":
+ version: 3.2.4
+ resolution: "@vitest/spy@npm:3.2.4"
+ dependencies:
+ tinyspy: "npm:^4.0.3"
+ checksum: 10c0/6ebf0b4697dc238476d6b6a60c76ba9eb1dd8167a307e30f08f64149612fd50227682b876420e4c2e09a76334e73f72e3ebf0e350714dc22474258292e202024
+ languageName: node
+ linkType: hard
+
+"@vitest/utils@npm:3.2.4":
+ version: 3.2.4
+ resolution: "@vitest/utils@npm:3.2.4"
+ dependencies:
+ "@vitest/pretty-format": "npm:3.2.4"
+ loupe: "npm:^3.1.4"
+ tinyrainbow: "npm:^2.0.0"
+ checksum: 10c0/024a9b8c8bcc12cf40183c246c244b52ecff861c6deb3477cbf487ac8781ad44c68a9c5fd69f8c1361878e55b97c10d99d511f2597f1f7244b5e5101d028ba64
+ languageName: node
+ linkType: hard
+
+"abbrev@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "abbrev@npm:4.0.0"
+ checksum: 10c0/b4cc16935235e80702fc90192e349e32f8ef0ed151ef506aa78c81a7c455ec18375c4125414b99f84b2e055199d66383e787675f0bcd87da7a4dbd59f9eac1d5
+ languageName: node
+ linkType: hard
+
+"acorn-jsx@npm:^5.3.2":
+ version: 5.3.2
+ resolution: "acorn-jsx@npm:5.3.2"
+ peerDependencies:
+ acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+ checksum: 10c0/4c54868fbef3b8d58927d5e33f0a4de35f59012fe7b12cf9dfbb345fb8f46607709e1c4431be869a23fb63c151033d84c4198fa9f79385cec34fcb1dd53974c1
+ languageName: node
+ linkType: hard
+
+"acorn@npm:^8.15.0":
+ version: 8.16.0
+ resolution: "acorn@npm:8.16.0"
+ bin:
+ acorn: bin/acorn
+ checksum: 10c0/c9c52697227661b68d0debaf972222d4f622aa06b185824164e153438afa7b08273432ca43ea792cadb24dada1d46f6f6bb1ef8de9956979288cc1b96bf9914e
+ languageName: node
+ linkType: hard
+
+"agent-base@npm:^7.1.0, agent-base@npm:^7.1.2":
+ version: 7.1.4
+ resolution: "agent-base@npm:7.1.4"
+ checksum: 10c0/c2c9ab7599692d594b6a161559ada307b7a624fa4c7b03e3afdb5a5e31cd0e53269115b620fcab024c5ac6a6f37fa5eb2e004f076ad30f5f7e6b8b671f7b35fe
+ languageName: node
+ linkType: hard
+
+"ajv@npm:^6.14.0":
+ version: 6.14.0
+ resolution: "ajv@npm:6.14.0"
+ dependencies:
+ fast-deep-equal: "npm:^3.1.1"
+ fast-json-stable-stringify: "npm:^2.0.0"
+ json-schema-traverse: "npm:^0.4.1"
+ uri-js: "npm:^4.2.2"
+ checksum: 10c0/a2bc39b0555dc9802c899f86990eb8eed6e366cddbf65be43d5aa7e4f3c4e1a199d5460fd7ca4fb3d864000dbbc049253b72faa83b3b30e641ca52cb29a68c22
+ languageName: node
+ linkType: hard
+
+"ansi-styles@npm:^4.1.0":
+ version: 4.3.0
+ resolution: "ansi-styles@npm:4.3.0"
+ dependencies:
+ color-convert: "npm:^2.0.1"
+ checksum: 10c0/895a23929da416f2bd3de7e9cb4eabd340949328ab85ddd6e484a637d8f6820d485f53933446f5291c3b760cbc488beb8e88573dd0f9c7daf83dccc8fe81b041
+ languageName: node
+ linkType: hard
+
+"argparse@npm:^2.0.1":
+ version: 2.0.1
+ resolution: "argparse@npm:2.0.1"
+ checksum: 10c0/c5640c2d89045371c7cedd6a70212a04e360fd34d6edeae32f6952c63949e3525ea77dbec0289d8213a99bbaeab5abfa860b5c12cf88a2e6cf8106e90dd27a7e
+ languageName: node
+ linkType: hard
+
+"aria-hidden@npm:^1.2.4":
+ version: 1.2.6
+ resolution: "aria-hidden@npm:1.2.6"
+ dependencies:
+ tslib: "npm:^2.0.0"
+ checksum: 10c0/7720cb539497a9f760f68f98a4b30f22c6767aa0e72fa7d58279f7c164e258fc38b2699828f8de881aab0fc8e9c56d1313a3f1a965046fc0381a554dbc72b54a
+ languageName: node
+ linkType: hard
+
+"aria-query@npm:^5.3.2":
+ version: 5.3.2
+ resolution: "aria-query@npm:5.3.2"
+ checksum: 10c0/003c7e3e2cff5540bf7a7893775fc614de82b0c5dde8ae823d47b7a28a9d4da1f7ed85f340bdb93d5649caa927755f0e31ecc7ab63edfdfc00c8ef07e505e03e
+ languageName: node
+ linkType: hard
+
+"array-buffer-byte-length@npm:^1.0.1, array-buffer-byte-length@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "array-buffer-byte-length@npm:1.0.2"
+ dependencies:
+ call-bound: "npm:^1.0.3"
+ is-array-buffer: "npm:^3.0.5"
+ checksum: 10c0/74e1d2d996941c7a1badda9cabb7caab8c449db9086407cad8a1b71d2604cc8abf105db8ca4e02c04579ec58b7be40279ddb09aea4784832984485499f48432d
+ languageName: node
+ linkType: hard
+
+"array-includes@npm:^3.1.6, array-includes@npm:^3.1.8, array-includes@npm:^3.1.9":
+ version: 3.1.9
+ resolution: "array-includes@npm:3.1.9"
+ dependencies:
+ call-bind: "npm:^1.0.8"
+ call-bound: "npm:^1.0.4"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.24.0"
+ es-object-atoms: "npm:^1.1.1"
+ get-intrinsic: "npm:^1.3.0"
+ is-string: "npm:^1.1.1"
+ math-intrinsics: "npm:^1.1.0"
+ checksum: 10c0/0235fa69078abeac05ac4250699c44996bc6f774a9cbe45db48674ce6bd142f09b327d31482ff75cf03344db4ea03eae23edb862d59378b484b47ed842574856
+ languageName: node
+ linkType: hard
+
+"array.prototype.findlast@npm:^1.2.5":
+ version: 1.2.5
+ resolution: "array.prototype.findlast@npm:1.2.5"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.23.2"
+ es-errors: "npm:^1.3.0"
+ es-object-atoms: "npm:^1.0.0"
+ es-shim-unscopables: "npm:^1.0.2"
+ checksum: 10c0/ddc952b829145ab45411b9d6adcb51a8c17c76bf89c9dd64b52d5dffa65d033da8c076ed2e17091779e83bc892b9848188d7b4b33453c5565e65a92863cb2775
+ languageName: node
+ linkType: hard
+
+"array.prototype.findlastindex@npm:^1.2.6":
+ version: 1.2.6
+ resolution: "array.prototype.findlastindex@npm:1.2.6"
+ dependencies:
+ call-bind: "npm:^1.0.8"
+ call-bound: "npm:^1.0.4"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.23.9"
+ es-errors: "npm:^1.3.0"
+ es-object-atoms: "npm:^1.1.1"
+ es-shim-unscopables: "npm:^1.1.0"
+ checksum: 10c0/82559310d2e57ec5f8fc53d7df420e3abf0ba497935de0a5570586035478ba7d07618cb18e2d4ada2da514c8fb98a034aaf5c06caa0a57e2f7f4c4adedef5956
+ languageName: node
+ linkType: hard
+
+"array.prototype.flat@npm:^1.3.1, array.prototype.flat@npm:^1.3.3":
+ version: 1.3.3
+ resolution: "array.prototype.flat@npm:1.3.3"
+ dependencies:
+ call-bind: "npm:^1.0.8"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.23.5"
+ es-shim-unscopables: "npm:^1.0.2"
+ checksum: 10c0/d90e04dfbc43bb96b3d2248576753d1fb2298d2d972e29ca7ad5ec621f0d9e16ff8074dae647eac4f31f4fb7d3f561a7ac005fb01a71f51705a13b5af06a7d8a
+ languageName: node
+ linkType: hard
+
+"array.prototype.flatmap@npm:^1.3.2, array.prototype.flatmap@npm:^1.3.3":
+ version: 1.3.3
+ resolution: "array.prototype.flatmap@npm:1.3.3"
+ dependencies:
+ call-bind: "npm:^1.0.8"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.23.5"
+ es-shim-unscopables: "npm:^1.0.2"
+ checksum: 10c0/ba899ea22b9dc9bf276e773e98ac84638ed5e0236de06f13d63a90b18ca9e0ec7c97d622d899796e3773930b946cd2413d098656c0c5d8cc58c6f25c21e6bd54
+ languageName: node
+ linkType: hard
+
+"array.prototype.tosorted@npm:^1.1.4":
+ version: 1.1.4
+ resolution: "array.prototype.tosorted@npm:1.1.4"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.23.3"
+ es-errors: "npm:^1.3.0"
+ es-shim-unscopables: "npm:^1.0.2"
+ checksum: 10c0/eb3c4c4fc0381b0bf6dba2ea4d48d367c2827a0d4236a5718d97caaccc6b78f11f4cadf090736e86301d295a6aa4967ed45568f92ced51be8cbbacd9ca410943
+ languageName: node
+ linkType: hard
+
+"arraybuffer.prototype.slice@npm:^1.0.4":
+ version: 1.0.4
+ resolution: "arraybuffer.prototype.slice@npm:1.0.4"
+ dependencies:
+ array-buffer-byte-length: "npm:^1.0.1"
+ call-bind: "npm:^1.0.8"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.23.5"
+ es-errors: "npm:^1.3.0"
+ get-intrinsic: "npm:^1.2.6"
+ is-array-buffer: "npm:^3.0.4"
+ checksum: 10c0/2f2459caa06ae0f7f615003f9104b01f6435cc803e11bd2a655107d52a1781dc040532dc44d93026b694cc18793993246237423e13a5337e86b43ed604932c06
+ languageName: node
+ linkType: hard
+
+"assertion-error@npm:^2.0.1":
+ version: 2.0.1
+ resolution: "assertion-error@npm:2.0.1"
+ checksum: 10c0/bbbcb117ac6480138f8c93cf7f535614282dea9dc828f540cdece85e3c665e8f78958b96afac52f29ff883c72638e6a87d469ecc9fe5bc902df03ed24a55dba8
+ languageName: node
+ linkType: hard
+
+"ast-types-flow@npm:^0.0.8":
+ version: 0.0.8
+ resolution: "ast-types-flow@npm:0.0.8"
+ checksum: 10c0/f2a0ba8055353b743c41431974521e5e852a9824870cd6fce2db0e538ac7bf4da406bbd018d109af29ff3f8f0993f6a730c9eddbd0abd031fbcb29ca75c1014e
+ languageName: node
+ linkType: hard
+
+"async-function@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "async-function@npm:1.0.0"
+ checksum: 10c0/669a32c2cb7e45091330c680e92eaeb791bc1d4132d827591e499cd1f776ff5a873e77e5f92d0ce795a8d60f10761dec9ddfe7225a5de680f5d357f67b1aac73
+ languageName: node
+ linkType: hard
+
+"async-generator-function@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "async-generator-function@npm:1.0.0"
+ checksum: 10c0/2c50ef856c543ad500d8d8777d347e3c1ba623b93e99c9263ecc5f965c1b12d2a140e2ab6e43c3d0b85366110696f28114649411cbcd10b452a92a2318394186
+ languageName: node
+ linkType: hard
+
+"available-typed-arrays@npm:^1.0.7":
+ version: 1.0.7
+ resolution: "available-typed-arrays@npm:1.0.7"
+ dependencies:
+ possible-typed-array-names: "npm:^1.0.0"
+ checksum: 10c0/d07226ef4f87daa01bd0fe80f8f310982e345f372926da2e5296aecc25c41cab440916bbaa4c5e1034b453af3392f67df5961124e4b586df1e99793a1374bdb2
+ languageName: node
+ linkType: hard
+
+"axe-core@npm:^4.10.0":
+ version: 4.11.1
+ resolution: "axe-core@npm:4.11.1"
+ checksum: 10c0/1e6997454b61c7c9a4d740f395952835dcf87f2c04fd81577217d68634d197d602c224f9e8f17b22815db4c117a2519980cfc8911fc0027c54a6d8ebca47c6a7
+ languageName: node
+ linkType: hard
+
+"axobject-query@npm:^4.1.0":
+ version: 4.1.0
+ resolution: "axobject-query@npm:4.1.0"
+ checksum: 10c0/c470e4f95008f232eadd755b018cb55f16c03ccf39c027b941cd8820ac6b68707ce5d7368a46756db4256fbc91bb4ead368f84f7fb034b2b7932f082f6dc0775
+ languageName: node
+ linkType: hard
+
+"bail@npm:^2.0.0":
+ version: 2.0.2
+ resolution: "bail@npm:2.0.2"
+ checksum: 10c0/25cbea309ef6a1f56214187004e8f34014eb015713ea01fa5b9b7e9e776ca88d0fdffd64143ac42dc91966c915a4b7b683411b56e14929fad16153fc026ffb8b
+ languageName: node
+ linkType: hard
+
+"balanced-match@npm:^1.0.0":
+ version: 1.0.2
+ resolution: "balanced-match@npm:1.0.2"
+ checksum: 10c0/9308baf0a7e4838a82bbfd11e01b1cb0f0cf2893bc1676c27c2a8c0e70cbae1c59120c3268517a8ae7fb6376b4639ef81ca22582611dbee4ed28df945134aaee
+ languageName: node
+ linkType: hard
+
+"balanced-match@npm:^4.0.2":
+ version: 4.0.4
+ resolution: "balanced-match@npm:4.0.4"
+ checksum: 10c0/07e86102a3eb2ee2a6a1a89164f29d0dbaebd28f2ca3f5ca786f36b8b23d9e417eb3be45a4acf754f837be5ac0a2317de90d3fcb7f4f4dc95720a1f36b26a17b
+ languageName: node
+ linkType: hard
+
+"baseline-browser-mapping@npm:^2.9.0":
+ version: 2.10.8
+ resolution: "baseline-browser-mapping@npm:2.10.8"
+ bin:
+ baseline-browser-mapping: dist/cli.cjs
+ checksum: 10c0/a77882e8ac37a900a9a0757b9bf4e50f407829ed17ee7630273ab5da0ae10d9c64ed4c5a1e03afb3490e39713440092417ded4bb856eeb9bd44856eacbd97497
+ languageName: node
+ linkType: hard
+
+"bcryptjs@npm:*, bcryptjs@npm:^3.0.3":
+ version: 3.0.3
+ resolution: "bcryptjs@npm:3.0.3"
+ bin:
+ bcrypt: bin/bcrypt
+ checksum: 10c0/127c94699f07eab5fbbb89d600c3f0e36ae6fd001e028139740b41fffb62a23a2743523fb88f442ae3308a27d4843b97ccb9e436d78f5c5899be187d0972c6d5
+ languageName: node
+ linkType: hard
+
+"better-auth@npm:1.4.7":
+ version: 1.4.7
+ resolution: "better-auth@npm:1.4.7"
+ dependencies:
+ "@better-auth/core": "npm:1.4.7"
+ "@better-auth/telemetry": "npm:1.4.7"
+ "@better-auth/utils": "npm:0.3.0"
+ "@better-fetch/fetch": "npm:1.1.21"
+ "@noble/ciphers": "npm:^2.0.0"
+ "@noble/hashes": "npm:^2.0.0"
+ better-call: "npm:1.1.5"
+ defu: "npm:^6.1.4"
+ jose: "npm:^6.1.0"
+ kysely: "npm:^0.28.5"
+ nanostores: "npm:^1.0.1"
+ zod: "npm:^4.1.12"
+ peerDependencies:
+ "@lynx-js/react": "*"
+ "@prisma/client": ^5.22.0
+ "@sveltejs/kit": ^2.0.0
+ "@tanstack/react-start": ^1.0.0
+ better-sqlite3: ^12.4.1
+ drizzle-kit: ^0.31.4
+ drizzle-orm: ^0.41.0
+ mongodb: ^6.18.0
+ mysql2: ^3.14.4
+ next: ^14.0.0 || ^15.0.0 || ^16.0.0
+ pg: ^8.16.3
+ prisma: ^5.22.0
+ react: ^18.0.0 || ^19.0.0
+ react-dom: ^18.0.0 || ^19.0.0
+ solid-js: ^1.0.0
+ svelte: ^4.0.0 || ^5.0.0
+ vitest: ^4.0.15
+ vue: ^3.0.0
+ peerDependenciesMeta:
+ "@lynx-js/react":
+ optional: true
+ "@prisma/client":
+ optional: true
+ "@sveltejs/kit":
+ optional: true
+ "@tanstack/react-start":
+ optional: true
+ better-sqlite3:
+ optional: true
+ drizzle-kit:
+ optional: true
+ drizzle-orm:
+ optional: true
+ mongodb:
+ optional: true
+ mysql2:
+ optional: true
+ next:
+ optional: true
+ pg:
+ optional: true
+ prisma:
+ optional: true
+ react:
+ optional: true
+ react-dom:
+ optional: true
+ solid-js:
+ optional: true
+ svelte:
+ optional: true
+ vitest:
+ optional: true
+ vue:
+ optional: true
+ checksum: 10c0/4d8e6bd997d7052f60b49e46f796788df86bc8a89f121baa247465c35988c992429adf44a74ef25bb222026b4bb25a8852600e664157cf8f2bfc11260dd212b9
+ languageName: node
+ linkType: hard
+
+"better-call@npm:1.1.5":
+ version: 1.1.5
+ resolution: "better-call@npm:1.1.5"
+ dependencies:
+ "@better-auth/utils": "npm:^0.3.0"
+ "@better-fetch/fetch": "npm:^1.1.4"
+ rou3: "npm:^0.7.10"
+ set-cookie-parser: "npm:^2.7.1"
+ peerDependencies:
+ zod: ^4.0.0
+ peerDependenciesMeta:
+ zod:
+ optional: true
+ checksum: 10c0/c9329a7cfc2f2d47488df1ac758a0c0c77c5a789ac00917ee990bec797227fb23a9c1199f5a4551ea0242cfe76acf4528cca35bc8b081fc98b33b3a08a7eb583
+ languageName: node
+ linkType: hard
+
+"brace-expansion@npm:^1.1.7":
+ version: 1.1.12
+ resolution: "brace-expansion@npm:1.1.12"
+ dependencies:
+ balanced-match: "npm:^1.0.0"
+ concat-map: "npm:0.0.1"
+ checksum: 10c0/975fecac2bb7758c062c20d0b3b6288c7cc895219ee25f0a64a9de662dbac981ff0b6e89909c3897c1f84fa353113a721923afdec5f8b2350255b097f12b1f73
+ languageName: node
+ linkType: hard
+
+"brace-expansion@npm:^5.0.2":
+ version: 5.0.4
+ resolution: "brace-expansion@npm:5.0.4"
+ dependencies:
+ balanced-match: "npm:^4.0.2"
+ checksum: 10c0/359cbcfa80b2eb914ca1f3440e92313fbfe7919ee6b274c35db55bec555aded69dac5ee78f102cec90c35f98c20fa43d10936d0cd9978158823c249257e1643a
+ languageName: node
+ linkType: hard
+
+"braces@npm:^3.0.3":
+ version: 3.0.3
+ resolution: "braces@npm:3.0.3"
+ dependencies:
+ fill-range: "npm:^7.1.1"
+ checksum: 10c0/7c6dfd30c338d2997ba77500539227b9d1f85e388a5f43220865201e407e076783d0881f2d297b9f80951b4c957fcf0b51c1d2d24227631643c3f7c284b0aa04
+ languageName: node
+ linkType: hard
+
+"browserslist@npm:^4.24.0":
+ version: 4.28.1
+ resolution: "browserslist@npm:4.28.1"
+ dependencies:
+ baseline-browser-mapping: "npm:^2.9.0"
+ caniuse-lite: "npm:^1.0.30001759"
+ electron-to-chromium: "npm:^1.5.263"
+ node-releases: "npm:^2.0.27"
+ update-browserslist-db: "npm:^1.2.0"
+ bin:
+ browserslist: cli.js
+ checksum: 10c0/545a5fa9d7234e3777a7177ec1e9134bb2ba60a69e6b95683f6982b1473aad347c77c1264ccf2ac5dea609a9731fbfbda6b85782bdca70f80f86e28a402504bd
+ languageName: node
+ linkType: hard
+
+"cac@npm:^6.7.14":
+ version: 6.7.14
+ resolution: "cac@npm:6.7.14"
+ checksum: 10c0/4ee06aaa7bab8981f0d54e5f5f9d4adcd64058e9697563ce336d8a3878ed018ee18ebe5359b2430eceae87e0758e62ea2019c3f52ae6e211b1bd2e133856cd10
+ languageName: node
+ linkType: hard
+
+"cacache@npm:^20.0.1":
+ version: 20.0.3
+ resolution: "cacache@npm:20.0.3"
+ dependencies:
+ "@npmcli/fs": "npm:^5.0.0"
+ fs-minipass: "npm:^3.0.0"
+ glob: "npm:^13.0.0"
+ lru-cache: "npm:^11.1.0"
+ minipass: "npm:^7.0.3"
+ minipass-collect: "npm:^2.0.1"
+ minipass-flush: "npm:^1.0.5"
+ minipass-pipeline: "npm:^1.2.4"
+ p-map: "npm:^7.0.2"
+ ssri: "npm:^13.0.0"
+ unique-filename: "npm:^5.0.0"
+ checksum: 10c0/c7da1ca694d20e8f8aedabd21dc11518f809a7d2b59aa76a1fc655db5a9e62379e465c157ddd2afe34b19230808882288effa6911b2de26a088a6d5645123462
+ languageName: node
+ linkType: hard
+
+"call-bind-apply-helpers@npm:^1.0.0, call-bind-apply-helpers@npm:^1.0.1, call-bind-apply-helpers@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "call-bind-apply-helpers@npm:1.0.2"
+ dependencies:
+ es-errors: "npm:^1.3.0"
+ function-bind: "npm:^1.1.2"
+ checksum: 10c0/47bd9901d57b857590431243fea704ff18078b16890a6b3e021e12d279bbf211d039155e27d7566b374d49ee1f8189344bac9833dec7a20cdec370506361c938
+ languageName: node
+ linkType: hard
+
+"call-bind@npm:^1.0.7, call-bind@npm:^1.0.8":
+ version: 1.0.8
+ resolution: "call-bind@npm:1.0.8"
+ dependencies:
+ call-bind-apply-helpers: "npm:^1.0.0"
+ es-define-property: "npm:^1.0.0"
+ get-intrinsic: "npm:^1.2.4"
+ set-function-length: "npm:^1.2.2"
+ checksum: 10c0/a13819be0681d915144467741b69875ae5f4eba8961eb0bf322aab63ec87f8250eb6d6b0dcbb2e1349876412a56129ca338592b3829ef4343527f5f18a0752d4
+ languageName: node
+ linkType: hard
+
+"call-bound@npm:^1.0.2, call-bound@npm:^1.0.3, call-bound@npm:^1.0.4":
+ version: 1.0.4
+ resolution: "call-bound@npm:1.0.4"
+ dependencies:
+ call-bind-apply-helpers: "npm:^1.0.2"
+ get-intrinsic: "npm:^1.3.0"
+ checksum: 10c0/f4796a6a0941e71c766aea672f63b72bc61234c4f4964dc6d7606e3664c307e7d77845328a8f3359ce39ddb377fed67318f9ee203dea1d47e46165dcf2917644
+ languageName: node
+ linkType: hard
+
+"callsites@npm:^3.0.0":
+ version: 3.1.0
+ resolution: "callsites@npm:3.1.0"
+ checksum: 10c0/fff92277400eb06c3079f9e74f3af120db9f8ea03bad0e84d9aede54bbe2d44a56cccb5f6cf12211f93f52306df87077ecec5b712794c5a9b5dac6d615a3f301
+ languageName: node
+ linkType: hard
+
+"caniuse-lite@npm:^1.0.30001579, caniuse-lite@npm:^1.0.30001759":
+ version: 1.0.30001780
+ resolution: "caniuse-lite@npm:1.0.30001780"
+ checksum: 10c0/8a88f39758a228852d6f3ac92362ecb7694b1b2b022f194d8dfe59123ad40a5de6202bf2dff0fe316bb3d5ca9caf316c22056e0da693459c3be2771cde4f4bf9
+ languageName: node
+ linkType: hard
+
+"ccount@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "ccount@npm:2.0.1"
+ checksum: 10c0/3939b1664390174484322bc3f45b798462e6c07ee6384cb3d645e0aa2f318502d174845198c1561930e1d431087f74cf1fe291ae9a4722821a9f4ba67e574350
+ languageName: node
+ linkType: hard
+
+"chai@npm:^5.2.0":
+ version: 5.3.3
+ resolution: "chai@npm:5.3.3"
+ dependencies:
+ assertion-error: "npm:^2.0.1"
+ check-error: "npm:^2.1.1"
+ deep-eql: "npm:^5.0.1"
+ loupe: "npm:^3.1.0"
+ pathval: "npm:^2.0.0"
+ checksum: 10c0/b360fd4d38861622e5010c2f709736988b05c7f31042305fa3f4e9911f6adb80ccfb4e302068bf8ed10e835c2e2520cba0f5edc13d878b886987e5aa62483f53
+ languageName: node
+ linkType: hard
+
+"chalk@npm:^4.0.0":
+ version: 4.1.2
+ resolution: "chalk@npm:4.1.2"
+ dependencies:
+ ansi-styles: "npm:^4.1.0"
+ supports-color: "npm:^7.1.0"
+ checksum: 10c0/4a3fef5cc34975c898ffe77141450f679721df9dde00f6c304353fa9c8b571929123b26a0e4617bde5018977eb655b31970c297b91b63ee83bb82aeb04666880
+ languageName: node
+ linkType: hard
+
+"character-entities-html4@npm:^2.0.0":
+ version: 2.1.0
+ resolution: "character-entities-html4@npm:2.1.0"
+ checksum: 10c0/fe61b553f083400c20c0b0fd65095df30a0b445d960f3bbf271536ae6c3ba676f39cb7af0b4bf2755812f08ab9b88f2feed68f9aebb73bb153f7a115fe5c6e40
+ languageName: node
+ linkType: hard
+
+"character-entities-legacy@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "character-entities-legacy@npm:3.0.0"
+ checksum: 10c0/ec4b430af873661aa754a896a2b55af089b4e938d3d010fad5219299a6b6d32ab175142699ee250640678cd64bdecd6db3c9af0b8759ab7b155d970d84c4c7d1
+ languageName: node
+ linkType: hard
+
+"character-entities@npm:^2.0.0":
+ version: 2.0.2
+ resolution: "character-entities@npm:2.0.2"
+ checksum: 10c0/b0c645a45bcc90ff24f0e0140f4875a8436b8ef13b6bcd31ec02cfb2ca502b680362aa95386f7815bdc04b6464d48cf191210b3840d7c04241a149ede591a308
+ languageName: node
+ linkType: hard
+
+"character-reference-invalid@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "character-reference-invalid@npm:2.0.1"
+ checksum: 10c0/2ae0dec770cd8659d7e8b0ce24392d83b4c2f0eb4a3395c955dce5528edd4cc030a794cfa06600fcdd700b3f2de2f9b8e40e309c0011c4180e3be64a0b42e6a1
+ languageName: node
+ linkType: hard
+
+"check-error@npm:^2.1.1":
+ version: 2.1.3
+ resolution: "check-error@npm:2.1.3"
+ checksum: 10c0/878e99038fb6476316b74668cd6a498c7e66df3efe48158fa40db80a06ba4258742ac3ee2229c4a2a98c5e73f5dff84eb3e50ceb6b65bbd8f831eafc8338607d
+ languageName: node
+ linkType: hard
+
+"chownr@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "chownr@npm:3.0.0"
+ checksum: 10c0/43925b87700f7e3893296c8e9c56cc58f926411cce3a6e5898136daaf08f08b9a8eb76d37d3267e707d0dcc17aed2e2ebdf5848c0c3ce95cf910a919935c1b10
+ languageName: node
+ linkType: hard
+
+"class-variance-authority@npm:^0.7.1":
+ version: 0.7.1
+ resolution: "class-variance-authority@npm:0.7.1"
+ dependencies:
+ clsx: "npm:^2.1.1"
+ checksum: 10c0/0f438cea22131808b99272de0fa933c2532d5659773bfec0c583de7b3f038378996d3350683426b8e9c74a6286699382106d71fbec52f0dd5fbb191792cccb5b
+ languageName: node
+ linkType: hard
+
+"client-only@npm:0.0.1":
+ version: 0.0.1
+ resolution: "client-only@npm:0.0.1"
+ checksum: 10c0/9d6cfd0c19e1c96a434605added99dff48482152af791ec4172fb912a71cff9027ff174efd8cdb2160cc7f377543e0537ffc462d4f279bc4701de3f2a3c4b358
+ languageName: node
+ linkType: hard
+
+"clsx@npm:^2.1.1":
+ version: 2.1.1
+ resolution: "clsx@npm:2.1.1"
+ checksum: 10c0/c4c8eb865f8c82baab07e71bfa8897c73454881c4f99d6bc81585aecd7c441746c1399d08363dc096c550cceaf97bd4ce1e8854e1771e9998d9f94c4fe075839
+ languageName: node
+ linkType: hard
+
+"color-convert@npm:^2.0.1":
+ version: 2.0.1
+ resolution: "color-convert@npm:2.0.1"
+ dependencies:
+ color-name: "npm:~1.1.4"
+ checksum: 10c0/37e1150172f2e311fe1b2df62c6293a342ee7380da7b9cfdba67ea539909afbd74da27033208d01d6d5cfc65ee7868a22e18d7e7648e004425441c0f8a15a7d7
+ languageName: node
+ linkType: hard
+
+"color-name@npm:~1.1.4":
+ version: 1.1.4
+ resolution: "color-name@npm:1.1.4"
+ checksum: 10c0/a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95
+ languageName: node
+ linkType: hard
+
+"comma-separated-tokens@npm:^2.0.0":
+ version: 2.0.3
+ resolution: "comma-separated-tokens@npm:2.0.3"
+ checksum: 10c0/91f90f1aae320f1755d6957ef0b864fe4f54737f3313bd95e0802686ee2ca38bff1dd381964d00ae5db42912dd1f4ae5c2709644e82706ffc6f6842a813cdd67
+ languageName: node
+ linkType: hard
+
+"concat-map@npm:0.0.1":
+ version: 0.0.1
+ resolution: "concat-map@npm:0.0.1"
+ checksum: 10c0/c996b1cfdf95b6c90fee4dae37e332c8b6eb7d106430c17d538034c0ad9a1630cb194d2ab37293b1bdd4d779494beee7786d586a50bd9376fd6f7bcc2bd4c98f
+ languageName: node
+ linkType: hard
+
+"convert-source-map@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "convert-source-map@npm:2.0.0"
+ checksum: 10c0/8f2f7a27a1a011cc6cc88cc4da2d7d0cfa5ee0369508baae3d98c260bb3ac520691464e5bbe4ae7cdf09860c1d69ecc6f70c63c6e7c7f7e3f18ec08484dc7d9b
+ languageName: node
+ linkType: hard
+
+"cross-spawn@npm:^7.0.6":
+ version: 7.0.6
+ resolution: "cross-spawn@npm:7.0.6"
+ dependencies:
+ path-key: "npm:^3.1.0"
+ shebang-command: "npm:^2.0.0"
+ which: "npm:^2.0.1"
+ checksum: 10c0/053ea8b2135caff68a9e81470e845613e374e7309a47731e81639de3eaeb90c3d01af0e0b44d2ab9d50b43467223b88567dfeb3262db942dc063b9976718ffc1
+ languageName: node
+ linkType: hard
+
+"csstype@npm:^3.2.2":
+ version: 3.2.3
+ resolution: "csstype@npm:3.2.3"
+ checksum: 10c0/cd29c51e70fa822f1cecd8641a1445bed7063697469d35633b516e60fe8c1bde04b08f6c5b6022136bb669b64c63d4173af54864510fbb4ee23281801841a3ce
+ languageName: node
+ linkType: hard
+
+"d3-array@npm:2 - 3, d3-array@npm:2.10.0 - 3, d3-array@npm:^3.1.6":
+ version: 3.2.4
+ resolution: "d3-array@npm:3.2.4"
+ dependencies:
+ internmap: "npm:1 - 2"
+ checksum: 10c0/08b95e91130f98c1375db0e0af718f4371ccacef7d5d257727fe74f79a24383e79aba280b9ffae655483ffbbad4fd1dec4ade0119d88c4749f388641c8bf8c50
+ languageName: node
+ linkType: hard
+
+"d3-color@npm:1 - 3":
+ version: 3.1.0
+ resolution: "d3-color@npm:3.1.0"
+ checksum: 10c0/a4e20e1115fa696fce041fbe13fbc80dc4c19150fa72027a7c128ade980bc0eeeba4bcf28c9e21f0bce0e0dbfe7ca5869ef67746541dcfda053e4802ad19783c
+ languageName: node
+ linkType: hard
+
+"d3-ease@npm:^3.0.1":
+ version: 3.0.1
+ resolution: "d3-ease@npm:3.0.1"
+ checksum: 10c0/fec8ef826c0cc35cda3092c6841e07672868b1839fcaf556e19266a3a37e6bc7977d8298c0fcb9885e7799bfdcef7db1baaba9cd4dcf4bc5e952cf78574a88b0
+ languageName: node
+ linkType: hard
+
+"d3-format@npm:1 - 3":
+ version: 3.1.2
+ resolution: "d3-format@npm:3.1.2"
+ checksum: 10c0/0de452ae07585238e7f01607a7e0066665c34609652188b6ac7dc9f424f69465a425e07d16d79bd0e5955202ac7f241c66d0c76f68a79fc6f4857c94cf420652
+ languageName: node
+ linkType: hard
+
+"d3-interpolate@npm:1.2.0 - 3, d3-interpolate@npm:^3.0.1":
+ version: 3.0.1
+ resolution: "d3-interpolate@npm:3.0.1"
+ dependencies:
+ d3-color: "npm:1 - 3"
+ checksum: 10c0/19f4b4daa8d733906671afff7767c19488f51a43d251f8b7f484d5d3cfc36c663f0a66c38fe91eee30f40327443d799be17169f55a293a3ba949e84e57a33e6a
+ languageName: node
+ linkType: hard
+
+"d3-path@npm:^3.1.0":
+ version: 3.1.0
+ resolution: "d3-path@npm:3.1.0"
+ checksum: 10c0/dc1d58ec87fa8319bd240cf7689995111a124b141428354e9637aa83059eb12e681f77187e0ada5dedfce346f7e3d1f903467ceb41b379bfd01cd8e31721f5da
+ languageName: node
+ linkType: hard
+
+"d3-scale@npm:^4.0.2":
+ version: 4.0.2
+ resolution: "d3-scale@npm:4.0.2"
+ dependencies:
+ d3-array: "npm:2.10.0 - 3"
+ d3-format: "npm:1 - 3"
+ d3-interpolate: "npm:1.2.0 - 3"
+ d3-time: "npm:2.1.1 - 3"
+ d3-time-format: "npm:2 - 4"
+ checksum: 10c0/65d9ad8c2641aec30ed5673a7410feb187a224d6ca8d1a520d68a7d6eac9d04caedbff4713d1e8545be33eb7fec5739983a7ab1d22d4e5ad35368c6729d362f1
+ languageName: node
+ linkType: hard
+
+"d3-shape@npm:^3.1.0":
+ version: 3.2.0
+ resolution: "d3-shape@npm:3.2.0"
+ dependencies:
+ d3-path: "npm:^3.1.0"
+ checksum: 10c0/f1c9d1f09926daaf6f6193ae3b4c4b5521e81da7d8902d24b38694517c7f527ce3c9a77a9d3a5722ad1e3ff355860b014557b450023d66a944eabf8cfde37132
+ languageName: node
+ linkType: hard
+
+"d3-time-format@npm:2 - 4":
+ version: 4.1.0
+ resolution: "d3-time-format@npm:4.1.0"
+ dependencies:
+ d3-time: "npm:1 - 3"
+ checksum: 10c0/735e00fb25a7fd5d418fac350018713ae394eefddb0d745fab12bbff0517f9cdb5f807c7bbe87bb6eeb06249662f8ea84fec075f7d0cd68609735b2ceb29d206
+ languageName: node
+ linkType: hard
+
+"d3-time@npm:1 - 3, d3-time@npm:2.1.1 - 3, d3-time@npm:^3.0.0":
+ version: 3.1.0
+ resolution: "d3-time@npm:3.1.0"
+ dependencies:
+ d3-array: "npm:2 - 3"
+ checksum: 10c0/a984f77e1aaeaa182679b46fbf57eceb6ebdb5f67d7578d6f68ef933f8eeb63737c0949991618a8d29472dbf43736c7d7f17c452b2770f8c1271191cba724ca1
+ languageName: node
+ linkType: hard
+
+"d3-timer@npm:^3.0.1":
+ version: 3.0.1
+ resolution: "d3-timer@npm:3.0.1"
+ checksum: 10c0/d4c63cb4bb5461d7038aac561b097cd1c5673969b27cbdd0e87fa48d9300a538b9e6f39b4a7f0e3592ef4f963d858c8a9f0e92754db73116770856f2fc04561a
+ languageName: node
+ linkType: hard
+
+"damerau-levenshtein@npm:^1.0.8":
+ version: 1.0.8
+ resolution: "damerau-levenshtein@npm:1.0.8"
+ checksum: 10c0/4c2647e0f42acaee7d068756c1d396e296c3556f9c8314bac1ac63ffb236217ef0e7e58602b18bb2173deec7ec8e0cac8e27cccf8f5526666b4ff11a13ad54a3
+ languageName: node
+ linkType: hard
+
+"data-view-buffer@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "data-view-buffer@npm:1.0.2"
+ dependencies:
+ call-bound: "npm:^1.0.3"
+ es-errors: "npm:^1.3.0"
+ is-data-view: "npm:^1.0.2"
+ checksum: 10c0/7986d40fc7979e9e6241f85db8d17060dd9a71bd53c894fa29d126061715e322a4cd47a00b0b8c710394854183d4120462b980b8554012acc1c0fa49df7ad38c
+ languageName: node
+ linkType: hard
+
+"data-view-byte-length@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "data-view-byte-length@npm:1.0.2"
+ dependencies:
+ call-bound: "npm:^1.0.3"
+ es-errors: "npm:^1.3.0"
+ is-data-view: "npm:^1.0.2"
+ checksum: 10c0/f8a4534b5c69384d95ac18137d381f18a5cfae1f0fc1df0ef6feef51ef0d568606d970b69e02ea186c6c0f0eac77fe4e6ad96fec2569cc86c3afcc7475068c55
+ languageName: node
+ linkType: hard
+
+"data-view-byte-offset@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "data-view-byte-offset@npm:1.0.1"
+ dependencies:
+ call-bound: "npm:^1.0.2"
+ es-errors: "npm:^1.3.0"
+ is-data-view: "npm:^1.0.1"
+ checksum: 10c0/fa7aa40078025b7810dcffc16df02c480573b7b53ef1205aa6a61533011005c1890e5ba17018c692ce7c900212b547262d33279fde801ad9843edc0863bf78c4
+ languageName: node
+ linkType: hard
+
+"debug@npm:4, debug@npm:^4.0.0, debug@npm:^4.1.0, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.4.0, debug@npm:^4.4.1, debug@npm:^4.4.3":
+ version: 4.4.3
+ resolution: "debug@npm:4.4.3"
+ dependencies:
+ ms: "npm:^2.1.3"
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+ checksum: 10c0/d79136ec6c83ecbefd0f6a5593da6a9c91ec4d7ddc4b54c883d6e71ec9accb5f67a1a5e96d00a328196b5b5c86d365e98d8a3a70856aaf16b4e7b1985e67f5a6
+ languageName: node
+ linkType: hard
+
+"debug@npm:^3.2.7":
+ version: 3.2.7
+ resolution: "debug@npm:3.2.7"
+ dependencies:
+ ms: "npm:^2.1.1"
+ checksum: 10c0/37d96ae42cbc71c14844d2ae3ba55adf462ec89fd3a999459dec3833944cd999af6007ff29c780f1c61153bcaaf2c842d1e4ce1ec621e4fc4923244942e4a02a
+ languageName: node
+ linkType: hard
+
+"decimal.js-light@npm:^2.5.1":
+ version: 2.5.1
+ resolution: "decimal.js-light@npm:2.5.1"
+ checksum: 10c0/4fd33f535aac9e5bd832796831b65d9ec7914ad129c7437b3ab991b0c2eaaa5a57e654e6174c4a17f1b3895ea366f0c1ab4955cdcdf7cfdcf3ad5a58b456c020
+ languageName: node
+ linkType: hard
+
+"decode-named-character-reference@npm:^1.0.0":
+ version: 1.3.0
+ resolution: "decode-named-character-reference@npm:1.3.0"
+ dependencies:
+ character-entities: "npm:^2.0.0"
+ checksum: 10c0/787f4c87f3b82ea342aa7c2d7b1882b6fb9511bb77f72ae44dcaabea0470bacd1e9c6a0080ab886545019fa0cb3a7109573fad6b61a362844c3a0ac52b36e4bb
+ languageName: node
+ linkType: hard
+
+"deep-eql@npm:^5.0.1":
+ version: 5.0.2
+ resolution: "deep-eql@npm:5.0.2"
+ checksum: 10c0/7102cf3b7bb719c6b9c0db2e19bf0aa9318d141581befe8c7ce8ccd39af9eaa4346e5e05adef7f9bd7015da0f13a3a25dcfe306ef79dc8668aedbecb658dd247
+ languageName: node
+ linkType: hard
+
+"deep-is@npm:^0.1.3":
+ version: 0.1.4
+ resolution: "deep-is@npm:0.1.4"
+ checksum: 10c0/7f0ee496e0dff14a573dc6127f14c95061b448b87b995fc96c017ce0a1e66af1675e73f1d6064407975bc4ea6ab679497a29fff7b5b9c4e99cb10797c1ad0b4c
+ languageName: node
+ linkType: hard
+
+"define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.4":
+ version: 1.1.4
+ resolution: "define-data-property@npm:1.1.4"
+ dependencies:
+ es-define-property: "npm:^1.0.0"
+ es-errors: "npm:^1.3.0"
+ gopd: "npm:^1.0.1"
+ checksum: 10c0/dea0606d1483eb9db8d930d4eac62ca0fa16738b0b3e07046cddfacf7d8c868bbe13fa0cb263eb91c7d0d527960dc3f2f2471a69ed7816210307f6744fe62e37
+ languageName: node
+ linkType: hard
+
+"define-properties@npm:^1.1.3, define-properties@npm:^1.2.1":
+ version: 1.2.1
+ resolution: "define-properties@npm:1.2.1"
+ dependencies:
+ define-data-property: "npm:^1.0.1"
+ has-property-descriptors: "npm:^1.0.0"
+ object-keys: "npm:^1.1.1"
+ checksum: 10c0/88a152319ffe1396ccc6ded510a3896e77efac7a1bfbaa174a7b00414a1747377e0bb525d303794a47cf30e805c2ec84e575758512c6e44a993076d29fd4e6c3
+ languageName: node
+ linkType: hard
+
+"defu@npm:^6.1.4":
+ version: 6.1.4
+ resolution: "defu@npm:6.1.4"
+ checksum: 10c0/2d6cc366262dc0cb8096e429368e44052fdf43ed48e53ad84cc7c9407f890301aa5fcb80d0995abaaf842b3949f154d060be4160f7a46cb2bc2f7726c81526f5
+ languageName: node
+ linkType: hard
+
+"dequal@npm:^2.0.0":
+ version: 2.0.3
+ resolution: "dequal@npm:2.0.3"
+ checksum: 10c0/f98860cdf58b64991ae10205137c0e97d384c3a4edc7f807603887b7c4b850af1224a33d88012009f150861cbee4fa2d322c4cc04b9313bee312e47f6ecaa888
+ languageName: node
+ linkType: hard
+
+"detect-libc@npm:^2.0.3, detect-libc@npm:^2.1.2":
+ version: 2.1.2
+ resolution: "detect-libc@npm:2.1.2"
+ checksum: 10c0/acc675c29a5649fa1fb6e255f993b8ee829e510b6b56b0910666949c80c364738833417d0edb5f90e4e46be17228b0f2b66a010513984e18b15deeeac49369c4
+ languageName: node
+ linkType: hard
+
+"detect-node-es@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "detect-node-es@npm:1.1.0"
+ checksum: 10c0/e562f00de23f10c27d7119e1af0e7388407eb4b06596a25f6d79a360094a109ff285de317f02b090faae093d314cf6e73ac3214f8a5bb3a0def5bece94557fbe
+ languageName: node
+ linkType: hard
+
+"devlop@npm:^1.0.0, devlop@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "devlop@npm:1.1.0"
+ dependencies:
+ dequal: "npm:^2.0.0"
+ checksum: 10c0/e0928ab8f94c59417a2b8389c45c55ce0a02d9ac7fd74ef62d01ba48060129e1d594501b77de01f3eeafc7cb00773819b0df74d96251cf20b31c5b3071f45c0e
+ languageName: node
+ linkType: hard
+
+"doctrine@npm:^2.1.0":
+ version: 2.1.0
+ resolution: "doctrine@npm:2.1.0"
+ dependencies:
+ esutils: "npm:^2.0.2"
+ checksum: 10c0/b6416aaff1f380bf56c3b552f31fdf7a69b45689368deca72d28636f41c16bb28ec3ebc40ace97db4c1afc0ceeb8120e8492fe0046841c94c2933b2e30a7d5ac
+ languageName: node
+ linkType: hard
+
+"dunder-proto@npm:^1.0.0, dunder-proto@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "dunder-proto@npm:1.0.1"
+ dependencies:
+ call-bind-apply-helpers: "npm:^1.0.1"
+ es-errors: "npm:^1.3.0"
+ gopd: "npm:^1.2.0"
+ checksum: 10c0/199f2a0c1c16593ca0a145dbf76a962f8033ce3129f01284d48c45ed4e14fea9bbacd7b3610b6cdc33486cef20385ac054948fefc6272fcce645c09468f93031
+ languageName: node
+ linkType: hard
+
+"electron-to-chromium@npm:^1.5.263":
+ version: 1.5.321
+ resolution: "electron-to-chromium@npm:1.5.321"
+ checksum: 10c0/1272703857b8ac9868a75d495c141b71bad36adcb0df53393196da3819012fa2596ba48fccac750bdcb746a523d2a33543b36e9dc0ae727a55e7a6f00b2b155a
+ languageName: node
+ linkType: hard
+
+"emoji-regex@npm:^9.2.2":
+ version: 9.2.2
+ resolution: "emoji-regex@npm:9.2.2"
+ checksum: 10c0/af014e759a72064cf66e6e694a7fc6b0ed3d8db680427b021a89727689671cefe9d04151b2cad51dbaf85d5ba790d061cd167f1cf32eb7b281f6368b3c181639
+ languageName: node
+ linkType: hard
+
+"enhanced-resolve@npm:^5.19.0":
+ version: 5.20.1
+ resolution: "enhanced-resolve@npm:5.20.1"
+ dependencies:
+ graceful-fs: "npm:^4.2.4"
+ tapable: "npm:^2.3.0"
+ checksum: 10c0/c6503ee1b2d725843e047e774445ecb12b779aa52db25d11ebe18d4b3adc148d3d993d2038b3d0c38ad836c9c4b3930fbc55df42f72b44785e2f94e5530eda69
+ languageName: node
+ linkType: hard
+
+"env-paths@npm:^2.2.0":
+ version: 2.2.1
+ resolution: "env-paths@npm:2.2.1"
+ checksum: 10c0/285325677bf00e30845e330eec32894f5105529db97496ee3f598478e50f008c5352a41a30e5e72ec9de8a542b5a570b85699cd63bd2bc646dbcb9f311d83bc4
+ languageName: node
+ linkType: hard
+
+"es-abstract@npm:^1.17.5, es-abstract@npm:^1.23.2, es-abstract@npm:^1.23.3, es-abstract@npm:^1.23.5, es-abstract@npm:^1.23.6, es-abstract@npm:^1.23.9, es-abstract@npm:^1.24.0, es-abstract@npm:^1.24.1":
+ version: 1.24.1
+ resolution: "es-abstract@npm:1.24.1"
+ dependencies:
+ array-buffer-byte-length: "npm:^1.0.2"
+ arraybuffer.prototype.slice: "npm:^1.0.4"
+ available-typed-arrays: "npm:^1.0.7"
+ call-bind: "npm:^1.0.8"
+ call-bound: "npm:^1.0.4"
+ data-view-buffer: "npm:^1.0.2"
+ data-view-byte-length: "npm:^1.0.2"
+ data-view-byte-offset: "npm:^1.0.1"
+ es-define-property: "npm:^1.0.1"
+ es-errors: "npm:^1.3.0"
+ es-object-atoms: "npm:^1.1.1"
+ es-set-tostringtag: "npm:^2.1.0"
+ es-to-primitive: "npm:^1.3.0"
+ function.prototype.name: "npm:^1.1.8"
+ get-intrinsic: "npm:^1.3.0"
+ get-proto: "npm:^1.0.1"
+ get-symbol-description: "npm:^1.1.0"
+ globalthis: "npm:^1.0.4"
+ gopd: "npm:^1.2.0"
+ has-property-descriptors: "npm:^1.0.2"
+ has-proto: "npm:^1.2.0"
+ has-symbols: "npm:^1.1.0"
+ hasown: "npm:^2.0.2"
+ internal-slot: "npm:^1.1.0"
+ is-array-buffer: "npm:^3.0.5"
+ is-callable: "npm:^1.2.7"
+ is-data-view: "npm:^1.0.2"
+ is-negative-zero: "npm:^2.0.3"
+ is-regex: "npm:^1.2.1"
+ is-set: "npm:^2.0.3"
+ is-shared-array-buffer: "npm:^1.0.4"
+ is-string: "npm:^1.1.1"
+ is-typed-array: "npm:^1.1.15"
+ is-weakref: "npm:^1.1.1"
+ math-intrinsics: "npm:^1.1.0"
+ object-inspect: "npm:^1.13.4"
+ object-keys: "npm:^1.1.1"
+ object.assign: "npm:^4.1.7"
+ own-keys: "npm:^1.0.1"
+ regexp.prototype.flags: "npm:^1.5.4"
+ safe-array-concat: "npm:^1.1.3"
+ safe-push-apply: "npm:^1.0.0"
+ safe-regex-test: "npm:^1.1.0"
+ set-proto: "npm:^1.0.0"
+ stop-iteration-iterator: "npm:^1.1.0"
+ string.prototype.trim: "npm:^1.2.10"
+ string.prototype.trimend: "npm:^1.0.9"
+ string.prototype.trimstart: "npm:^1.0.8"
+ typed-array-buffer: "npm:^1.0.3"
+ typed-array-byte-length: "npm:^1.0.3"
+ typed-array-byte-offset: "npm:^1.0.4"
+ typed-array-length: "npm:^1.0.7"
+ unbox-primitive: "npm:^1.1.0"
+ which-typed-array: "npm:^1.1.19"
+ checksum: 10c0/fca062ef8b5daacf743732167d319a212d45cb655b0bb540821d38d715416ae15b04b84fc86da9e2c89135aa7b337337b6c867f84dcde698d75d55688d5d765c
+ languageName: node
+ linkType: hard
+
+"es-define-property@npm:^1.0.0, es-define-property@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "es-define-property@npm:1.0.1"
+ checksum: 10c0/3f54eb49c16c18707949ff25a1456728c883e81259f045003499efba399c08bad00deebf65cccde8c0e07908c1a225c9d472b7107e558f2a48e28d530e34527c
+ languageName: node
+ linkType: hard
+
+"es-errors@npm:^1.3.0":
+ version: 1.3.0
+ resolution: "es-errors@npm:1.3.0"
+ checksum: 10c0/0a61325670072f98d8ae3b914edab3559b6caa980f08054a3b872052640d91da01d38df55df797fcc916389d77fc92b8d5906cf028f4db46d7e3003abecbca85
+ languageName: node
+ linkType: hard
+
+"es-iterator-helpers@npm:^1.2.1":
+ version: 1.3.1
+ resolution: "es-iterator-helpers@npm:1.3.1"
+ dependencies:
+ call-bind: "npm:^1.0.8"
+ call-bound: "npm:^1.0.4"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.24.1"
+ es-errors: "npm:^1.3.0"
+ es-set-tostringtag: "npm:^2.1.0"
+ function-bind: "npm:^1.1.2"
+ get-intrinsic: "npm:^1.3.0"
+ globalthis: "npm:^1.0.4"
+ gopd: "npm:^1.2.0"
+ has-property-descriptors: "npm:^1.0.2"
+ has-proto: "npm:^1.2.0"
+ has-symbols: "npm:^1.1.0"
+ internal-slot: "npm:^1.1.0"
+ iterator.prototype: "npm:^1.1.5"
+ math-intrinsics: "npm:^1.1.0"
+ safe-array-concat: "npm:^1.1.3"
+ checksum: 10c0/39837bb23bf6e53a066ae6a218c62bbc2c3cdd7da19336104bd7a16521675fcd9a61abe9cecf37992616584bee1d72f057bac66f2115fcf4840c934df6e96689
+ languageName: node
+ linkType: hard
+
+"es-module-lexer@npm:^1.7.0":
+ version: 1.7.0
+ resolution: "es-module-lexer@npm:1.7.0"
+ checksum: 10c0/4c935affcbfeba7fb4533e1da10fa8568043df1e3574b869385980de9e2d475ddc36769891936dbb07036edb3c3786a8b78ccf44964cd130dedc1f2c984b6c7b
+ languageName: node
+ linkType: hard
+
+"es-object-atoms@npm:^1.0.0, es-object-atoms@npm:^1.1.1":
+ version: 1.1.1
+ resolution: "es-object-atoms@npm:1.1.1"
+ dependencies:
+ es-errors: "npm:^1.3.0"
+ checksum: 10c0/65364812ca4daf48eb76e2a3b7a89b3f6a2e62a1c420766ce9f692665a29d94fe41fe88b65f24106f449859549711e4b40d9fb8002d862dfd7eb1c512d10be0c
+ languageName: node
+ linkType: hard
+
+"es-set-tostringtag@npm:^2.1.0":
+ version: 2.1.0
+ resolution: "es-set-tostringtag@npm:2.1.0"
+ dependencies:
+ es-errors: "npm:^1.3.0"
+ get-intrinsic: "npm:^1.2.6"
+ has-tostringtag: "npm:^1.0.2"
+ hasown: "npm:^2.0.2"
+ checksum: 10c0/ef2ca9ce49afe3931cb32e35da4dcb6d86ab02592cfc2ce3e49ced199d9d0bb5085fc7e73e06312213765f5efa47cc1df553a6a5154584b21448e9fb8355b1af
+ languageName: node
+ linkType: hard
+
+"es-shim-unscopables@npm:^1.0.2, es-shim-unscopables@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "es-shim-unscopables@npm:1.1.0"
+ dependencies:
+ hasown: "npm:^2.0.2"
+ checksum: 10c0/1b9702c8a1823fc3ef39035a4e958802cf294dd21e917397c561d0b3e195f383b978359816b1732d02b255ccf63e1e4815da0065b95db8d7c992037be3bbbcdb
+ languageName: node
+ linkType: hard
+
+"es-to-primitive@npm:^1.3.0":
+ version: 1.3.0
+ resolution: "es-to-primitive@npm:1.3.0"
+ dependencies:
+ is-callable: "npm:^1.2.7"
+ is-date-object: "npm:^1.0.5"
+ is-symbol: "npm:^1.0.4"
+ checksum: 10c0/c7e87467abb0b438639baa8139f701a06537d2b9bc758f23e8622c3b42fd0fdb5bde0f535686119e446dd9d5e4c0f238af4e14960f4771877cf818d023f6730b
+ languageName: node
+ linkType: hard
+
+"es-toolkit@npm:^1.39.3":
+ version: 1.45.1
+ resolution: "es-toolkit@npm:1.45.1"
+ dependenciesMeta:
+ "@trivago/prettier-plugin-sort-imports@4.3.0":
+ unplugged: true
+ prettier-plugin-sort-re-exports@0.0.1:
+ unplugged: true
+ checksum: 10c0/b19180c778af8fe2fb450e8e05a5793166c91e0aa66b87d9fcfcc5618bd33e6ceec9c103e074458d32b2044972dc4fc63631b3b615834fde261917e9561f6f59
+ languageName: node
+ linkType: hard
+
+"esbuild@npm:^0.27.0":
+ version: 0.27.4
+ resolution: "esbuild@npm:0.27.4"
+ dependencies:
+ "@esbuild/aix-ppc64": "npm:0.27.4"
+ "@esbuild/android-arm": "npm:0.27.4"
+ "@esbuild/android-arm64": "npm:0.27.4"
+ "@esbuild/android-x64": "npm:0.27.4"
+ "@esbuild/darwin-arm64": "npm:0.27.4"
+ "@esbuild/darwin-x64": "npm:0.27.4"
+ "@esbuild/freebsd-arm64": "npm:0.27.4"
+ "@esbuild/freebsd-x64": "npm:0.27.4"
+ "@esbuild/linux-arm": "npm:0.27.4"
+ "@esbuild/linux-arm64": "npm:0.27.4"
+ "@esbuild/linux-ia32": "npm:0.27.4"
+ "@esbuild/linux-loong64": "npm:0.27.4"
+ "@esbuild/linux-mips64el": "npm:0.27.4"
+ "@esbuild/linux-ppc64": "npm:0.27.4"
+ "@esbuild/linux-riscv64": "npm:0.27.4"
+ "@esbuild/linux-s390x": "npm:0.27.4"
+ "@esbuild/linux-x64": "npm:0.27.4"
+ "@esbuild/netbsd-arm64": "npm:0.27.4"
+ "@esbuild/netbsd-x64": "npm:0.27.4"
+ "@esbuild/openbsd-arm64": "npm:0.27.4"
+ "@esbuild/openbsd-x64": "npm:0.27.4"
+ "@esbuild/openharmony-arm64": "npm:0.27.4"
+ "@esbuild/sunos-x64": "npm:0.27.4"
+ "@esbuild/win32-arm64": "npm:0.27.4"
+ "@esbuild/win32-ia32": "npm:0.27.4"
+ "@esbuild/win32-x64": "npm:0.27.4"
+ dependenciesMeta:
+ "@esbuild/aix-ppc64":
+ optional: true
+ "@esbuild/android-arm":
+ optional: true
+ "@esbuild/android-arm64":
+ optional: true
+ "@esbuild/android-x64":
+ optional: true
+ "@esbuild/darwin-arm64":
+ optional: true
+ "@esbuild/darwin-x64":
+ optional: true
+ "@esbuild/freebsd-arm64":
+ optional: true
+ "@esbuild/freebsd-x64":
+ optional: true
+ "@esbuild/linux-arm":
+ optional: true
+ "@esbuild/linux-arm64":
+ optional: true
+ "@esbuild/linux-ia32":
+ optional: true
+ "@esbuild/linux-loong64":
+ optional: true
+ "@esbuild/linux-mips64el":
+ optional: true
+ "@esbuild/linux-ppc64":
+ optional: true
+ "@esbuild/linux-riscv64":
+ optional: true
+ "@esbuild/linux-s390x":
+ optional: true
+ "@esbuild/linux-x64":
+ optional: true
+ "@esbuild/netbsd-arm64":
+ optional: true
+ "@esbuild/netbsd-x64":
+ optional: true
+ "@esbuild/openbsd-arm64":
+ optional: true
+ "@esbuild/openbsd-x64":
+ optional: true
+ "@esbuild/openharmony-arm64":
+ optional: true
+ "@esbuild/sunos-x64":
+ optional: true
+ "@esbuild/win32-arm64":
+ optional: true
+ "@esbuild/win32-ia32":
+ optional: true
+ "@esbuild/win32-x64":
+ optional: true
+ bin:
+ esbuild: bin/esbuild
+ checksum: 10c0/2a1c2bcccda279f2afd72a7f8259860cb4483b32453d17878e1ecb4ac416b9e7c1001e7aa0a25ba4c29c1e250a3ceaae5d8bb72a119815bc8db4e9b5f5321490
+ languageName: node
+ linkType: hard
+
+"escalade@npm:^3.2.0":
+ version: 3.2.0
+ resolution: "escalade@npm:3.2.0"
+ checksum: 10c0/ced4dd3a78e15897ed3be74e635110bbf3b08877b0a41be50dcb325ee0e0b5f65fc2d50e9845194d7c4633f327e2e1c6cce00a71b617c5673df0374201d67f65
+ languageName: node
+ linkType: hard
+
+"escape-string-regexp@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "escape-string-regexp@npm:4.0.0"
+ checksum: 10c0/9497d4dd307d845bd7f75180d8188bb17ea8c151c1edbf6b6717c100e104d629dc2dfb687686181b0f4b7d732c7dfdc4d5e7a8ff72de1b0ca283a75bbb3a9cd9
+ languageName: node
+ linkType: hard
+
+"escape-string-regexp@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "escape-string-regexp@npm:5.0.0"
+ checksum: 10c0/6366f474c6f37a802800a435232395e04e9885919873e382b157ab7e8f0feb8fed71497f84a6f6a81a49aab41815522f5839112bd38026d203aea0c91622df95
+ languageName: node
+ linkType: hard
+
+"eslint-config-next@npm:^15.3.1":
+ version: 15.5.13
+ resolution: "eslint-config-next@npm:15.5.13"
+ dependencies:
+ "@next/eslint-plugin-next": "npm:15.5.13"
+ "@rushstack/eslint-patch": "npm:^1.10.3"
+ "@typescript-eslint/eslint-plugin": "npm:^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0"
+ "@typescript-eslint/parser": "npm:^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0"
+ eslint-import-resolver-node: "npm:^0.3.6"
+ eslint-import-resolver-typescript: "npm:^3.5.2"
+ eslint-plugin-import: "npm:^2.31.0"
+ eslint-plugin-jsx-a11y: "npm:^6.10.0"
+ eslint-plugin-react: "npm:^7.37.0"
+ eslint-plugin-react-hooks: "npm:^5.0.0"
+ peerDependencies:
+ eslint: ^7.23.0 || ^8.0.0 || ^9.0.0
+ typescript: ">=3.3.1"
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/0a655408ac8f92556bc9a3694420fc4a245761d7f819acdd5a68b69638655ac66ed3167a09fb3b37a2f9277cd34cf10df936cb3c32f192d00dd80a8ac5f9827b
+ languageName: node
+ linkType: hard
+
+"eslint-import-resolver-node@npm:^0.3.6, eslint-import-resolver-node@npm:^0.3.9":
+ version: 0.3.9
+ resolution: "eslint-import-resolver-node@npm:0.3.9"
+ dependencies:
+ debug: "npm:^3.2.7"
+ is-core-module: "npm:^2.13.0"
+ resolve: "npm:^1.22.4"
+ checksum: 10c0/0ea8a24a72328a51fd95aa8f660dcca74c1429806737cf10261ab90cfcaaf62fd1eff664b76a44270868e0a932711a81b250053942595bcd00a93b1c1575dd61
+ languageName: node
+ linkType: hard
+
+"eslint-import-resolver-typescript@npm:^3.5.2":
+ version: 3.10.1
+ resolution: "eslint-import-resolver-typescript@npm:3.10.1"
+ dependencies:
+ "@nolyfill/is-core-module": "npm:1.0.39"
+ debug: "npm:^4.4.0"
+ get-tsconfig: "npm:^4.10.0"
+ is-bun-module: "npm:^2.0.0"
+ stable-hash: "npm:^0.0.5"
+ tinyglobby: "npm:^0.2.13"
+ unrs-resolver: "npm:^1.6.2"
+ peerDependencies:
+ eslint: "*"
+ eslint-plugin-import: "*"
+ eslint-plugin-import-x: "*"
+ peerDependenciesMeta:
+ eslint-plugin-import:
+ optional: true
+ eslint-plugin-import-x:
+ optional: true
+ checksum: 10c0/02ba72cf757753ab9250806c066d09082e00807b7b6525d7687e1c0710bc3f6947e39120227fe1f93dabea3510776d86fb3fd769466ba3c46ce67e9f874cb702
+ languageName: node
+ linkType: hard
+
+"eslint-module-utils@npm:^2.12.1":
+ version: 2.12.1
+ resolution: "eslint-module-utils@npm:2.12.1"
+ dependencies:
+ debug: "npm:^3.2.7"
+ peerDependenciesMeta:
+ eslint:
+ optional: true
+ checksum: 10c0/6f4efbe7a91ae49bf67b4ab3644cb60bc5bd7db4cb5521de1b65be0847ffd3fb6bce0dd68f0995e1b312d137f768e2a1f842ee26fe73621afa05f850628fdc40
+ languageName: node
+ linkType: hard
+
+"eslint-plugin-import@npm:^2.31.0":
+ version: 2.32.0
+ resolution: "eslint-plugin-import@npm:2.32.0"
+ dependencies:
+ "@rtsao/scc": "npm:^1.1.0"
+ array-includes: "npm:^3.1.9"
+ array.prototype.findlastindex: "npm:^1.2.6"
+ array.prototype.flat: "npm:^1.3.3"
+ array.prototype.flatmap: "npm:^1.3.3"
+ debug: "npm:^3.2.7"
+ doctrine: "npm:^2.1.0"
+ eslint-import-resolver-node: "npm:^0.3.9"
+ eslint-module-utils: "npm:^2.12.1"
+ hasown: "npm:^2.0.2"
+ is-core-module: "npm:^2.16.1"
+ is-glob: "npm:^4.0.3"
+ minimatch: "npm:^3.1.2"
+ object.fromentries: "npm:^2.0.8"
+ object.groupby: "npm:^1.0.3"
+ object.values: "npm:^1.2.1"
+ semver: "npm:^6.3.1"
+ string.prototype.trimend: "npm:^1.0.9"
+ tsconfig-paths: "npm:^3.15.0"
+ peerDependencies:
+ eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9
+ checksum: 10c0/bfb1b8fc8800398e62ddfefbf3638d185286edfed26dfe00875cc2846d954491b4f5112457831588b757fa789384e1ae585f812614c4797f0499fa234fd4a48b
+ languageName: node
+ linkType: hard
+
+"eslint-plugin-jsx-a11y@npm:^6.10.0":
+ version: 6.10.2
+ resolution: "eslint-plugin-jsx-a11y@npm:6.10.2"
+ dependencies:
+ aria-query: "npm:^5.3.2"
+ array-includes: "npm:^3.1.8"
+ array.prototype.flatmap: "npm:^1.3.2"
+ ast-types-flow: "npm:^0.0.8"
+ axe-core: "npm:^4.10.0"
+ axobject-query: "npm:^4.1.0"
+ damerau-levenshtein: "npm:^1.0.8"
+ emoji-regex: "npm:^9.2.2"
+ hasown: "npm:^2.0.2"
+ jsx-ast-utils: "npm:^3.3.5"
+ language-tags: "npm:^1.0.9"
+ minimatch: "npm:^3.1.2"
+ object.fromentries: "npm:^2.0.8"
+ safe-regex-test: "npm:^1.0.3"
+ string.prototype.includes: "npm:^2.0.1"
+ peerDependencies:
+ eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9
+ checksum: 10c0/d93354e03b0cf66f018d5c50964e074dffe4ddf1f9b535fa020d19c4ae45f89c1a16e9391ca61ac3b19f7042c751ac0d361a056a65cbd1de24718a53ff8daa6e
+ languageName: node
+ linkType: hard
+
+"eslint-plugin-react-hooks@npm:^5.0.0":
+ version: 5.2.0
+ resolution: "eslint-plugin-react-hooks@npm:5.2.0"
+ peerDependencies:
+ eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0
+ checksum: 10c0/1c8d50fa5984c6dea32470651807d2922cc3934cf3425e78f84a24c2dfd972e7f019bee84aefb27e0cf2c13fea0ac1d4473267727408feeb1c56333ca1489385
+ languageName: node
+ linkType: hard
+
+"eslint-plugin-react@npm:^7.37.0":
+ version: 7.37.5
+ resolution: "eslint-plugin-react@npm:7.37.5"
+ dependencies:
+ array-includes: "npm:^3.1.8"
+ array.prototype.findlast: "npm:^1.2.5"
+ array.prototype.flatmap: "npm:^1.3.3"
+ array.prototype.tosorted: "npm:^1.1.4"
+ doctrine: "npm:^2.1.0"
+ es-iterator-helpers: "npm:^1.2.1"
+ estraverse: "npm:^5.3.0"
+ hasown: "npm:^2.0.2"
+ jsx-ast-utils: "npm:^2.4.1 || ^3.0.0"
+ minimatch: "npm:^3.1.2"
+ object.entries: "npm:^1.1.9"
+ object.fromentries: "npm:^2.0.8"
+ object.values: "npm:^1.2.1"
+ prop-types: "npm:^15.8.1"
+ resolve: "npm:^2.0.0-next.5"
+ semver: "npm:^6.3.1"
+ string.prototype.matchall: "npm:^4.0.12"
+ string.prototype.repeat: "npm:^1.0.0"
+ peerDependencies:
+ eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7
+ checksum: 10c0/c850bfd556291d4d9234f5ca38db1436924a1013627c8ab1853f77cac73ec19b020e861e6c7b783436a48b6ffcdfba4547598235a37ad4611b6739f65fd8ad57
+ languageName: node
+ linkType: hard
+
+"eslint-scope@npm:^8.4.0":
+ version: 8.4.0
+ resolution: "eslint-scope@npm:8.4.0"
+ dependencies:
+ esrecurse: "npm:^4.3.0"
+ estraverse: "npm:^5.2.0"
+ checksum: 10c0/407f6c600204d0f3705bd557f81bd0189e69cd7996f408f8971ab5779c0af733d1af2f1412066b40ee1588b085874fc37a2333986c6521669cdbdd36ca5058e0
+ languageName: node
+ linkType: hard
+
+"eslint-visitor-keys@npm:^3.4.3":
+ version: 3.4.3
+ resolution: "eslint-visitor-keys@npm:3.4.3"
+ checksum: 10c0/92708e882c0a5ffd88c23c0b404ac1628cf20104a108c745f240a13c332a11aac54f49a22d5762efbffc18ecbc9a580d1b7ad034bf5f3cc3307e5cbff2ec9820
+ languageName: node
+ linkType: hard
+
+"eslint-visitor-keys@npm:^4.2.1":
+ version: 4.2.1
+ resolution: "eslint-visitor-keys@npm:4.2.1"
+ checksum: 10c0/fcd43999199d6740db26c58dbe0c2594623e31ca307e616ac05153c9272f12f1364f5a0b1917a8e962268fdecc6f3622c1c2908b4fcc2e047a106fe6de69dc43
+ languageName: node
+ linkType: hard
+
+"eslint-visitor-keys@npm:^5.0.0":
+ version: 5.0.1
+ resolution: "eslint-visitor-keys@npm:5.0.1"
+ checksum: 10c0/16190bdf2cbae40a1109384c94450c526a79b0b9c3cb21e544256ed85ac48a4b84db66b74a6561d20fe6ab77447f150d711c2ad5ad74df4fcc133736bce99678
+ languageName: node
+ linkType: hard
+
+"eslint@npm:^9.0.0":
+ version: 9.39.4
+ resolution: "eslint@npm:9.39.4"
+ dependencies:
+ "@eslint-community/eslint-utils": "npm:^4.8.0"
+ "@eslint-community/regexpp": "npm:^4.12.1"
+ "@eslint/config-array": "npm:^0.21.2"
+ "@eslint/config-helpers": "npm:^0.4.2"
+ "@eslint/core": "npm:^0.17.0"
+ "@eslint/eslintrc": "npm:^3.3.5"
+ "@eslint/js": "npm:9.39.4"
+ "@eslint/plugin-kit": "npm:^0.4.1"
+ "@humanfs/node": "npm:^0.16.6"
+ "@humanwhocodes/module-importer": "npm:^1.0.1"
+ "@humanwhocodes/retry": "npm:^0.4.2"
+ "@types/estree": "npm:^1.0.6"
+ ajv: "npm:^6.14.0"
+ chalk: "npm:^4.0.0"
+ cross-spawn: "npm:^7.0.6"
+ debug: "npm:^4.3.2"
+ escape-string-regexp: "npm:^4.0.0"
+ eslint-scope: "npm:^8.4.0"
+ eslint-visitor-keys: "npm:^4.2.1"
+ espree: "npm:^10.4.0"
+ esquery: "npm:^1.5.0"
+ esutils: "npm:^2.0.2"
+ fast-deep-equal: "npm:^3.1.3"
+ file-entry-cache: "npm:^8.0.0"
+ find-up: "npm:^5.0.0"
+ glob-parent: "npm:^6.0.2"
+ ignore: "npm:^5.2.0"
+ imurmurhash: "npm:^0.1.4"
+ is-glob: "npm:^4.0.0"
+ json-stable-stringify-without-jsonify: "npm:^1.0.1"
+ lodash.merge: "npm:^4.6.2"
+ minimatch: "npm:^3.1.5"
+ natural-compare: "npm:^1.4.0"
+ optionator: "npm:^0.9.3"
+ peerDependencies:
+ jiti: "*"
+ peerDependenciesMeta:
+ jiti:
+ optional: true
+ bin:
+ eslint: bin/eslint.js
+ checksum: 10c0/1955067c2d991f0c84f4c4abfafe31bb47fa3b717a7fd3e43fe1e511c6f859d7700cbca969f85661dc4c130f7aeced5e5444884314198a54428f5e5141db9337
+ languageName: node
+ linkType: hard
+
+"espree@npm:^10.0.1, espree@npm:^10.4.0":
+ version: 10.4.0
+ resolution: "espree@npm:10.4.0"
+ dependencies:
+ acorn: "npm:^8.15.0"
+ acorn-jsx: "npm:^5.3.2"
+ eslint-visitor-keys: "npm:^4.2.1"
+ checksum: 10c0/c63fe06131c26c8157b4083313cb02a9a54720a08e21543300e55288c40e06c3fc284bdecf108d3a1372c5934a0a88644c98714f38b6ae8ed272b40d9ea08d6b
+ languageName: node
+ linkType: hard
+
+"esquery@npm:^1.5.0":
+ version: 1.7.0
+ resolution: "esquery@npm:1.7.0"
+ dependencies:
+ estraverse: "npm:^5.1.0"
+ checksum: 10c0/77d5173db450b66f3bc685d11af4c90cffeedb340f34a39af96d43509a335ce39c894fd79233df32d38f5e4e219fa0f7076f6ec90bae8320170ba082c0db4793
+ languageName: node
+ linkType: hard
+
+"esrecurse@npm:^4.3.0":
+ version: 4.3.0
+ resolution: "esrecurse@npm:4.3.0"
+ dependencies:
+ estraverse: "npm:^5.2.0"
+ checksum: 10c0/81a37116d1408ded88ada45b9fb16dbd26fba3aadc369ce50fcaf82a0bac12772ebd7b24cd7b91fc66786bf2c1ac7b5f196bc990a473efff972f5cb338877cf5
+ languageName: node
+ linkType: hard
+
+"estraverse@npm:^5.1.0, estraverse@npm:^5.2.0, estraverse@npm:^5.3.0":
+ version: 5.3.0
+ resolution: "estraverse@npm:5.3.0"
+ checksum: 10c0/1ff9447b96263dec95d6d67431c5e0771eb9776427421260a3e2f0fdd5d6bd4f8e37a7338f5ad2880c9f143450c9b1e4fc2069060724570a49cf9cf0312bd107
+ languageName: node
+ linkType: hard
+
+"estree-util-is-identifier-name@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "estree-util-is-identifier-name@npm:3.0.0"
+ checksum: 10c0/d1881c6ed14bd588ebd508fc90bf2a541811dbb9ca04dec2f39d27dcaa635f85b5ed9bbbe7fc6fb1ddfca68744a5f7c70456b4b7108b6c4c52780631cc787c5b
+ languageName: node
+ linkType: hard
+
+"estree-walker@npm:^3.0.3":
+ version: 3.0.3
+ resolution: "estree-walker@npm:3.0.3"
+ dependencies:
+ "@types/estree": "npm:^1.0.0"
+ checksum: 10c0/c12e3c2b2642d2bcae7d5aa495c60fa2f299160946535763969a1c83fc74518ffa9c2cd3a8b69ac56aea547df6a8aac25f729a342992ef0bbac5f1c73e78995d
+ languageName: node
+ linkType: hard
+
+"esutils@npm:^2.0.2":
+ version: 2.0.3
+ resolution: "esutils@npm:2.0.3"
+ checksum: 10c0/9a2fe69a41bfdade834ba7c42de4723c97ec776e40656919c62cbd13607c45e127a003f05f724a1ea55e5029a4cf2de444b13009f2af71271e42d93a637137c7
+ languageName: node
+ linkType: hard
+
+"eventemitter3@npm:^4.0.0":
+ version: 4.0.7
+ resolution: "eventemitter3@npm:4.0.7"
+ checksum: 10c0/5f6d97cbcbac47be798e6355e3a7639a84ee1f7d9b199a07017f1d2f1e2fe236004d14fa5dfaeba661f94ea57805385e326236a6debbc7145c8877fbc0297c6b
+ languageName: node
+ linkType: hard
+
+"eventemitter3@npm:^5.0.1":
+ version: 5.0.4
+ resolution: "eventemitter3@npm:5.0.4"
+ checksum: 10c0/575b8cac8d709e1473da46f8f15ef311b57ff7609445a7c71af5cd42598583eee6f098fa7a593e30f27e94b8865642baa0689e8fa97c016f742abdb3b1bf6d9a
+ languageName: node
+ linkType: hard
+
+"expect-type@npm:^1.2.1":
+ version: 1.3.0
+ resolution: "expect-type@npm:1.3.0"
+ checksum: 10c0/8412b3fe4f392c420ab41dae220b09700e4e47c639a29ba7ba2e83cc6cffd2b4926f7ac9e47d7e277e8f4f02acda76fd6931cb81fd2b382fa9477ef9ada953fd
+ languageName: node
+ linkType: hard
+
+"exponential-backoff@npm:^3.1.1":
+ version: 3.1.3
+ resolution: "exponential-backoff@npm:3.1.3"
+ checksum: 10c0/77e3ae682b7b1f4972f563c6dbcd2b0d54ac679e62d5d32f3e5085feba20483cf28bd505543f520e287a56d4d55a28d7874299941faf637e779a1aa5994d1267
+ languageName: node
+ linkType: hard
+
+"extend@npm:^3.0.0":
+ version: 3.0.2
+ resolution: "extend@npm:3.0.2"
+ checksum: 10c0/73bf6e27406e80aa3e85b0d1c4fd987261e628064e170ca781125c0b635a3dabad5e05adbf07595ea0cf1e6c5396cacb214af933da7cbaf24fe75ff14818e8f9
+ languageName: node
+ linkType: hard
+
+"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3":
+ version: 3.1.3
+ resolution: "fast-deep-equal@npm:3.1.3"
+ checksum: 10c0/40dedc862eb8992c54579c66d914635afbec43350afbbe991235fdcb4e3a8d5af1b23ae7e79bef7d4882d0ecee06c3197488026998fb19f72dc95acff1d1b1d0
+ languageName: node
+ linkType: hard
+
+"fast-glob@npm:3.3.1":
+ version: 3.3.1
+ resolution: "fast-glob@npm:3.3.1"
+ dependencies:
+ "@nodelib/fs.stat": "npm:^2.0.2"
+ "@nodelib/fs.walk": "npm:^1.2.3"
+ glob-parent: "npm:^5.1.2"
+ merge2: "npm:^1.3.0"
+ micromatch: "npm:^4.0.4"
+ checksum: 10c0/b68431128fb6ce4b804c5f9622628426d990b66c75b21c0d16e3d80e2d1398bf33f7e1724e66a2e3f299285dcf5b8d745b122d0304e7dd66f5231081f33ec67c
+ languageName: node
+ linkType: hard
+
+"fast-json-stable-stringify@npm:^2.0.0":
+ version: 2.1.0
+ resolution: "fast-json-stable-stringify@npm:2.1.0"
+ checksum: 10c0/7f081eb0b8a64e0057b3bb03f974b3ef00135fbf36c1c710895cd9300f13c94ba809bb3a81cf4e1b03f6e5285610a61abbd7602d0652de423144dfee5a389c9b
+ languageName: node
+ linkType: hard
+
+"fast-levenshtein@npm:^2.0.6":
+ version: 2.0.6
+ resolution: "fast-levenshtein@npm:2.0.6"
+ checksum: 10c0/111972b37338bcb88f7d9e2c5907862c280ebf4234433b95bc611e518d192ccb2d38119c4ac86e26b668d75f7f3894f4ff5c4982899afced7ca78633b08287c4
+ languageName: node
+ linkType: hard
+
+"fastq@npm:^1.6.0":
+ version: 1.20.1
+ resolution: "fastq@npm:1.20.1"
+ dependencies:
+ reusify: "npm:^1.0.4"
+ checksum: 10c0/e5dd725884decb1f11e5c822221d76136f239d0236f176fab80b7b8f9e7619ae57e6b4e5b73defc21e6b9ef99437ee7b545cff8e6c2c337819633712fa9d352e
+ languageName: node
+ linkType: hard
+
+"fdir@npm:^6.5.0":
+ version: 6.5.0
+ resolution: "fdir@npm:6.5.0"
+ peerDependencies:
+ picomatch: ^3 || ^4
+ peerDependenciesMeta:
+ picomatch:
+ optional: true
+ checksum: 10c0/e345083c4306b3aed6cb8ec551e26c36bab5c511e99ea4576a16750ddc8d3240e63826cc624f5ae17ad4dc82e68a253213b60d556c11bfad064b7607847ed07f
+ languageName: node
+ linkType: hard
+
+"file-entry-cache@npm:^8.0.0":
+ version: 8.0.0
+ resolution: "file-entry-cache@npm:8.0.0"
+ dependencies:
+ flat-cache: "npm:^4.0.0"
+ checksum: 10c0/9e2b5938b1cd9b6d7e3612bdc533afd4ac17b2fc646569e9a8abbf2eb48e5eb8e316bc38815a3ef6a1b456f4107f0d0f055a614ca613e75db6bf9ff4d72c1638
+ languageName: node
+ linkType: hard
+
+"fill-range@npm:^7.1.1":
+ version: 7.1.1
+ resolution: "fill-range@npm:7.1.1"
+ dependencies:
+ to-regex-range: "npm:^5.0.1"
+ checksum: 10c0/b75b691bbe065472f38824f694c2f7449d7f5004aa950426a2c28f0306c60db9b880c0b0e4ed819997ffb882d1da02cfcfc819bddc94d71627f5269682edf018
+ languageName: node
+ linkType: hard
+
+"find-up@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "find-up@npm:5.0.0"
+ dependencies:
+ locate-path: "npm:^6.0.0"
+ path-exists: "npm:^4.0.0"
+ checksum: 10c0/062c5a83a9c02f53cdd6d175a37ecf8f87ea5bbff1fdfb828f04bfa021441bc7583e8ebc0872a4c1baab96221fb8a8a275a19809fb93fbc40bd69ec35634069a
+ languageName: node
+ linkType: hard
+
+"flat-cache@npm:^4.0.0":
+ version: 4.0.1
+ resolution: "flat-cache@npm:4.0.1"
+ dependencies:
+ flatted: "npm:^3.2.9"
+ keyv: "npm:^4.5.4"
+ checksum: 10c0/2c59d93e9faa2523e4fda6b4ada749bed432cfa28c8e251f33b25795e426a1c6dbada777afb1f74fcfff33934fdbdea921ee738fcc33e71adc9d6eca984a1cfc
+ languageName: node
+ linkType: hard
+
+"flatted@npm:^3.2.9":
+ version: 3.4.2
+ resolution: "flatted@npm:3.4.2"
+ checksum: 10c0/a65b67aae7172d6cdf63691be7de6c5cd5adbdfdfe2e9da1a09b617c9512ed794037741ee53d93114276bff3f93cd3b0d97d54f9b316e1e4885dde6e9ffdf7ed
+ languageName: node
+ linkType: hard
+
+"follow-redirects@npm:^1.0.0":
+ version: 1.15.11
+ resolution: "follow-redirects@npm:1.15.11"
+ peerDependenciesMeta:
+ debug:
+ optional: true
+ checksum: 10c0/d301f430542520a54058d4aeeb453233c564aaccac835d29d15e050beb33f339ad67d9bddbce01739c5dc46a6716dbe3d9d0d5134b1ca203effa11a7ef092343
+ languageName: node
+ linkType: hard
+
+"for-each@npm:^0.3.3, for-each@npm:^0.3.5":
+ version: 0.3.5
+ resolution: "for-each@npm:0.3.5"
+ dependencies:
+ is-callable: "npm:^1.2.7"
+ checksum: 10c0/0e0b50f6a843a282637d43674d1fb278dda1dd85f4f99b640024cfb10b85058aac0cc781bf689d5fe50b4b7f638e91e548560723a4e76e04fe96ae35ef039cee
+ languageName: node
+ linkType: hard
+
+"fs-minipass@npm:^3.0.0":
+ version: 3.0.3
+ resolution: "fs-minipass@npm:3.0.3"
+ dependencies:
+ minipass: "npm:^7.0.3"
+ checksum: 10c0/63e80da2ff9b621e2cb1596abcb9207f1cf82b968b116ccd7b959e3323144cce7fb141462200971c38bbf2ecca51695069db45265705bed09a7cd93ae5b89f94
+ languageName: node
+ linkType: hard
+
+"fsevents@npm:2.3.3, fsevents@npm:~2.3.2, fsevents@npm:~2.3.3":
+ version: 2.3.3
+ resolution: "fsevents@npm:2.3.3"
+ dependencies:
+ node-gyp: "npm:latest"
+ checksum: 10c0/a1f0c44595123ed717febbc478aa952e47adfc28e2092be66b8ab1635147254ca6cfe1df792a8997f22716d4cbafc73309899ff7bfac2ac3ad8cf2e4ecc3ec60
+ conditions: os=darwin
+ languageName: node
+ linkType: hard
+
+"fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin":
+ version: 2.3.3
+ resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1"
+ dependencies:
+ node-gyp: "npm:latest"
+ conditions: os=darwin
+ languageName: node
+ linkType: hard
+
+"function-bind@npm:^1.1.2":
+ version: 1.1.2
+ resolution: "function-bind@npm:1.1.2"
+ checksum: 10c0/d8680ee1e5fcd4c197e4ac33b2b4dce03c71f4d91717292785703db200f5c21f977c568d28061226f9b5900cbcd2c84463646134fd5337e7925e0942bc3f46d5
+ languageName: node
+ linkType: hard
+
+"function.prototype.name@npm:^1.1.6, function.prototype.name@npm:^1.1.8":
+ version: 1.1.8
+ resolution: "function.prototype.name@npm:1.1.8"
+ dependencies:
+ call-bind: "npm:^1.0.8"
+ call-bound: "npm:^1.0.3"
+ define-properties: "npm:^1.2.1"
+ functions-have-names: "npm:^1.2.3"
+ hasown: "npm:^2.0.2"
+ is-callable: "npm:^1.2.7"
+ checksum: 10c0/e920a2ab52663005f3cbe7ee3373e3c71c1fb5558b0b0548648cdf3e51961085032458e26c71ff1a8c8c20e7ee7caeb03d43a5d1fa8610c459333323a2e71253
+ languageName: node
+ linkType: hard
+
+"functions-have-names@npm:^1.2.3":
+ version: 1.2.3
+ resolution: "functions-have-names@npm:1.2.3"
+ checksum: 10c0/33e77fd29bddc2d9bb78ab3eb854c165909201f88c75faa8272e35899e2d35a8a642a15e7420ef945e1f64a9670d6aa3ec744106b2aa42be68ca5114025954ca
+ languageName: node
+ linkType: hard
+
+"generator-function@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "generator-function@npm:2.0.1"
+ checksum: 10c0/8a9f59df0f01cfefafdb3b451b80555e5cf6d76487095db91ac461a0e682e4ff7a9dbce15f4ecec191e53586d59eece01949e05a4b4492879600bbbe8e28d6b8
+ languageName: node
+ linkType: hard
+
+"gensync@npm:^1.0.0-beta.2":
+ version: 1.0.0-beta.2
+ resolution: "gensync@npm:1.0.0-beta.2"
+ checksum: 10c0/782aba6cba65b1bb5af3b095d96249d20edbe8df32dbf4696fd49be2583faf676173bf4809386588828e4dd76a3354fcbeb577bab1c833ccd9fc4577f26103f8
+ languageName: node
+ linkType: hard
+
+"get-intrinsic@npm:^1.2.4, get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6, get-intrinsic@npm:^1.2.7, get-intrinsic@npm:^1.3.0":
+ version: 1.3.1
+ resolution: "get-intrinsic@npm:1.3.1"
+ dependencies:
+ async-function: "npm:^1.0.0"
+ async-generator-function: "npm:^1.0.0"
+ call-bind-apply-helpers: "npm:^1.0.2"
+ es-define-property: "npm:^1.0.1"
+ es-errors: "npm:^1.3.0"
+ es-object-atoms: "npm:^1.1.1"
+ function-bind: "npm:^1.1.2"
+ generator-function: "npm:^2.0.0"
+ get-proto: "npm:^1.0.1"
+ gopd: "npm:^1.2.0"
+ has-symbols: "npm:^1.1.0"
+ hasown: "npm:^2.0.2"
+ math-intrinsics: "npm:^1.1.0"
+ checksum: 10c0/9f4ab0cf7efe0fd2c8185f52e6f637e708f3a112610c88869f8f041bb9ecc2ce44bf285dfdbdc6f4f7c277a5b88d8e94a432374d97cca22f3de7fc63795deb5d
+ languageName: node
+ linkType: hard
+
+"get-nonce@npm:^1.0.0":
+ version: 1.0.1
+ resolution: "get-nonce@npm:1.0.1"
+ checksum: 10c0/2d7df55279060bf0568549e1ffc9b84bc32a32b7541675ca092dce56317cdd1a59a98dcc4072c9f6a980779440139a3221d7486f52c488e69dc0fd27b1efb162
+ languageName: node
+ linkType: hard
+
+"get-proto@npm:^1.0.0, get-proto@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "get-proto@npm:1.0.1"
+ dependencies:
+ dunder-proto: "npm:^1.0.1"
+ es-object-atoms: "npm:^1.0.0"
+ checksum: 10c0/9224acb44603c5526955e83510b9da41baf6ae73f7398875fba50edc5e944223a89c4a72b070fcd78beb5f7bdda58ecb6294adc28f7acfc0da05f76a2399643c
+ languageName: node
+ linkType: hard
+
+"get-symbol-description@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "get-symbol-description@npm:1.1.0"
+ dependencies:
+ call-bound: "npm:^1.0.3"
+ es-errors: "npm:^1.3.0"
+ get-intrinsic: "npm:^1.2.6"
+ checksum: 10c0/d6a7d6afca375779a4b307738c9e80dbf7afc0bdbe5948768d54ab9653c865523d8920e670991a925936eb524b7cb6a6361d199a760b21d0ca7620194455aa4b
+ languageName: node
+ linkType: hard
+
+"get-tsconfig@npm:^4.10.0":
+ version: 4.13.6
+ resolution: "get-tsconfig@npm:4.13.6"
+ dependencies:
+ resolve-pkg-maps: "npm:^1.0.0"
+ checksum: 10c0/bab6937302f542f97217cbe7cbbdfa7e85a56a377bc7a73e69224c1f0b7c9ae8365918e55752ae8648265903f506c1705f63c0de1d4bab1ec2830fef3e539a1a
+ languageName: node
+ linkType: hard
+
+"glob-parent@npm:^5.1.2":
+ version: 5.1.2
+ resolution: "glob-parent@npm:5.1.2"
+ dependencies:
+ is-glob: "npm:^4.0.1"
+ checksum: 10c0/cab87638e2112bee3f839ef5f6e0765057163d39c66be8ec1602f3823da4692297ad4e972de876ea17c44d652978638d2fd583c6713d0eb6591706825020c9ee
+ languageName: node
+ linkType: hard
+
+"glob-parent@npm:^6.0.2":
+ version: 6.0.2
+ resolution: "glob-parent@npm:6.0.2"
+ dependencies:
+ is-glob: "npm:^4.0.3"
+ checksum: 10c0/317034d88654730230b3f43bb7ad4f7c90257a426e872ea0bf157473ac61c99bf5d205fad8f0185f989be8d2fa6d3c7dce1645d99d545b6ea9089c39f838e7f8
+ languageName: node
+ linkType: hard
+
+"glob@npm:^13.0.0":
+ version: 13.0.6
+ resolution: "glob@npm:13.0.6"
+ dependencies:
+ minimatch: "npm:^10.2.2"
+ minipass: "npm:^7.1.3"
+ path-scurry: "npm:^2.0.2"
+ checksum: 10c0/269c236f11a9b50357fe7a8c6aadac667e01deb5242b19c84975628f05f4438d8ee1354bb62c5d6c10f37fd59911b54d7799730633a2786660d8c69f1d18120a
+ languageName: node
+ linkType: hard
+
+"globals@npm:^14.0.0":
+ version: 14.0.0
+ resolution: "globals@npm:14.0.0"
+ checksum: 10c0/b96ff42620c9231ad468d4c58ff42afee7777ee1c963013ff8aabe095a451d0ceeb8dcd8ef4cbd64d2538cef45f787a78ba3a9574f4a634438963e334471302d
+ languageName: node
+ linkType: hard
+
+"globalthis@npm:^1.0.4":
+ version: 1.0.4
+ resolution: "globalthis@npm:1.0.4"
+ dependencies:
+ define-properties: "npm:^1.2.1"
+ gopd: "npm:^1.0.1"
+ checksum: 10c0/9d156f313af79d80b1566b93e19285f481c591ad6d0d319b4be5e03750d004dde40a39a0f26f7e635f9007a3600802f53ecd85a759b86f109e80a5f705e01846
+ languageName: node
+ linkType: hard
+
+"gopd@npm:^1.0.1, gopd@npm:^1.2.0":
+ version: 1.2.0
+ resolution: "gopd@npm:1.2.0"
+ checksum: 10c0/50fff1e04ba2b7737c097358534eacadad1e68d24cccee3272e04e007bed008e68d2614f3987788428fd192a5ae3889d08fb2331417e4fc4a9ab366b2043cead
+ languageName: node
+ linkType: hard
+
+"graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6":
+ version: 4.2.11
+ resolution: "graceful-fs@npm:4.2.11"
+ checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2
+ languageName: node
+ linkType: hard
+
+"has-bigints@npm:^1.0.2":
+ version: 1.1.0
+ resolution: "has-bigints@npm:1.1.0"
+ checksum: 10c0/2de0cdc4a1ccf7a1e75ffede1876994525ac03cc6f5ae7392d3415dd475cd9eee5bceec63669ab61aa997ff6cceebb50ef75561c7002bed8988de2b9d1b40788
+ languageName: node
+ linkType: hard
+
+"has-flag@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "has-flag@npm:4.0.0"
+ checksum: 10c0/2e789c61b7888d66993e14e8331449e525ef42aac53c627cc53d1c3334e768bcb6abdc4f5f0de1478a25beec6f0bd62c7549058b7ac53e924040d4f301f02fd1
+ languageName: node
+ linkType: hard
+
+"has-property-descriptors@npm:^1.0.0, has-property-descriptors@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "has-property-descriptors@npm:1.0.2"
+ dependencies:
+ es-define-property: "npm:^1.0.0"
+ checksum: 10c0/253c1f59e80bb476cf0dde8ff5284505d90c3bdb762983c3514d36414290475fe3fd6f574929d84de2a8eec00d35cf07cb6776205ff32efd7c50719125f00236
+ languageName: node
+ linkType: hard
+
+"has-proto@npm:^1.2.0":
+ version: 1.2.0
+ resolution: "has-proto@npm:1.2.0"
+ dependencies:
+ dunder-proto: "npm:^1.0.0"
+ checksum: 10c0/46538dddab297ec2f43923c3d35237df45d8c55a6fc1067031e04c13ed8a9a8f94954460632fd4da84c31a1721eefee16d901cbb1ae9602bab93bb6e08f93b95
+ languageName: node
+ linkType: hard
+
+"has-symbols@npm:^1.0.3, has-symbols@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "has-symbols@npm:1.1.0"
+ checksum: 10c0/dde0a734b17ae51e84b10986e651c664379018d10b91b6b0e9b293eddb32f0f069688c841fb40f19e9611546130153e0a2a48fd7f512891fb000ddfa36f5a20e
+ languageName: node
+ linkType: hard
+
+"has-tostringtag@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "has-tostringtag@npm:1.0.2"
+ dependencies:
+ has-symbols: "npm:^1.0.3"
+ checksum: 10c0/a8b166462192bafe3d9b6e420a1d581d93dd867adb61be223a17a8d6dad147aa77a8be32c961bb2f27b3ef893cae8d36f564ab651f5e9b7938ae86f74027c48c
+ languageName: node
+ linkType: hard
+
+"hasown@npm:^2.0.2":
+ version: 2.0.2
+ resolution: "hasown@npm:2.0.2"
+ dependencies:
+ function-bind: "npm:^1.1.2"
+ checksum: 10c0/3769d434703b8ac66b209a4cca0737519925bbdb61dd887f93a16372b14694c63ff4e797686d87c90f08168e81082248b9b028bad60d4da9e0d1148766f56eb9
+ languageName: node
+ linkType: hard
+
+"hast-util-is-element@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "hast-util-is-element@npm:3.0.0"
+ dependencies:
+ "@types/hast": "npm:^3.0.0"
+ checksum: 10c0/f5361e4c9859c587ca8eb0d8343492f3077ccaa0f58a44cd09f35d5038f94d65152288dcd0c19336ef2c9491ec4d4e45fde2176b05293437021570aa0bc3613b
+ languageName: node
+ linkType: hard
+
+"hast-util-to-jsx-runtime@npm:^2.0.0":
+ version: 2.3.6
+ resolution: "hast-util-to-jsx-runtime@npm:2.3.6"
+ dependencies:
+ "@types/estree": "npm:^1.0.0"
+ "@types/hast": "npm:^3.0.0"
+ "@types/unist": "npm:^3.0.0"
+ comma-separated-tokens: "npm:^2.0.0"
+ devlop: "npm:^1.0.0"
+ estree-util-is-identifier-name: "npm:^3.0.0"
+ hast-util-whitespace: "npm:^3.0.0"
+ mdast-util-mdx-expression: "npm:^2.0.0"
+ mdast-util-mdx-jsx: "npm:^3.0.0"
+ mdast-util-mdxjs-esm: "npm:^2.0.0"
+ property-information: "npm:^7.0.0"
+ space-separated-tokens: "npm:^2.0.0"
+ style-to-js: "npm:^1.0.0"
+ unist-util-position: "npm:^5.0.0"
+ vfile-message: "npm:^4.0.0"
+ checksum: 10c0/27297e02848fe37ef219be04a26ce708d17278a175a807689e94a821dcffc88aa506d62c3a85beed1f9a8544f7211bdcbcde0528b7b456a57c2e342c3fd11056
+ languageName: node
+ linkType: hard
+
+"hast-util-to-text@npm:^4.0.0":
+ version: 4.0.2
+ resolution: "hast-util-to-text@npm:4.0.2"
+ dependencies:
+ "@types/hast": "npm:^3.0.0"
+ "@types/unist": "npm:^3.0.0"
+ hast-util-is-element: "npm:^3.0.0"
+ unist-util-find-after: "npm:^5.0.0"
+ checksum: 10c0/93ecc10e68fe5391c6e634140eb330942e71dea2724c8e0c647c73ed74a8ec930a4b77043b5081284808c96f73f2bee64ee416038ece75a63a467e8d14f09946
+ languageName: node
+ linkType: hard
+
+"hast-util-whitespace@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "hast-util-whitespace@npm:3.0.0"
+ dependencies:
+ "@types/hast": "npm:^3.0.0"
+ checksum: 10c0/b898bc9fe27884b272580d15260b6bbdabe239973a147e97fa98c45fa0ffec967a481aaa42291ec34fb56530dc2d484d473d7e2bae79f39c83f3762307edfea8
+ languageName: node
+ linkType: hard
+
+"highlight.js@npm:~11.11.0":
+ version: 11.11.1
+ resolution: "highlight.js@npm:11.11.1"
+ checksum: 10c0/40f53ac19dac079891fcefd5bd8a21cf2e8931fd47da5bd1dca73b7e4375c1defed0636fc39120c639b9c44119b7d110f7f0c15aa899557a5a1c8910f3c0144c
+ languageName: node
+ linkType: hard
+
+"html-url-attributes@npm:^3.0.0":
+ version: 3.0.1
+ resolution: "html-url-attributes@npm:3.0.1"
+ checksum: 10c0/496e4908aa8b77665f348b4b03521901794f648b8ac34a581022cd6f2c97934d5c910cd91bc6593bbf2994687549037bc2520fcdc769b31484f29ffdd402acd0
+ languageName: node
+ linkType: hard
+
+"http-cache-semantics@npm:^4.1.1":
+ version: 4.2.0
+ resolution: "http-cache-semantics@npm:4.2.0"
+ checksum: 10c0/45b66a945cf13ec2d1f29432277201313babf4a01d9e52f44b31ca923434083afeca03f18417f599c9ab3d0e7b618ceb21257542338b57c54b710463b4a53e37
+ languageName: node
+ linkType: hard
+
+"http-proxy-agent@npm:^7.0.0":
+ version: 7.0.2
+ resolution: "http-proxy-agent@npm:7.0.2"
+ dependencies:
+ agent-base: "npm:^7.1.0"
+ debug: "npm:^4.3.4"
+ checksum: 10c0/4207b06a4580fb85dd6dff521f0abf6db517489e70863dca1a0291daa7f2d3d2d6015a57bd702af068ea5cf9f1f6ff72314f5f5b4228d299c0904135d2aef921
+ languageName: node
+ linkType: hard
+
+"http-proxy@npm:^1.18.1":
+ version: 1.18.1
+ resolution: "http-proxy@npm:1.18.1"
+ dependencies:
+ eventemitter3: "npm:^4.0.0"
+ follow-redirects: "npm:^1.0.0"
+ requires-port: "npm:^1.0.0"
+ checksum: 10c0/148dfa700a03fb421e383aaaf88ac1d94521dfc34072f6c59770528c65250983c2e4ec996f2f03aa9f3fe46cd1270a593126068319311e3e8d9e610a37533e94
+ languageName: node
+ linkType: hard
+
+"https-proxy-agent@npm:^7.0.1":
+ version: 7.0.6
+ resolution: "https-proxy-agent@npm:7.0.6"
+ dependencies:
+ agent-base: "npm:^7.1.2"
+ debug: "npm:4"
+ checksum: 10c0/f729219bc735edb621fa30e6e84e60ee5d00802b8247aac0d7b79b0bd6d4b3294737a337b93b86a0bd9e68099d031858a39260c976dc14cdbba238ba1f8779ac
+ languageName: node
+ linkType: hard
+
+"iconv-lite@npm:^0.7.2":
+ version: 0.7.2
+ resolution: "iconv-lite@npm:0.7.2"
+ dependencies:
+ safer-buffer: "npm:>= 2.1.2 < 3.0.0"
+ checksum: 10c0/3c228920f3bd307f56bf8363706a776f4a060eb042f131cd23855ceca962951b264d0997ab38a1ad340e1c5df8499ed26e1f4f0db6b2a2ad9befaff22f14b722
+ languageName: node
+ linkType: hard
+
+"ignore@npm:^5.2.0":
+ version: 5.3.2
+ resolution: "ignore@npm:5.3.2"
+ checksum: 10c0/f9f652c957983634ded1e7f02da3b559a0d4cc210fca3792cb67f1b153623c9c42efdc1c4121af171e295444459fc4a9201101fb041b1104a3c000bccb188337
+ languageName: node
+ linkType: hard
+
+"ignore@npm:^7.0.5":
+ version: 7.0.5
+ resolution: "ignore@npm:7.0.5"
+ checksum: 10c0/ae00db89fe873064a093b8999fe4cc284b13ef2a178636211842cceb650b9c3e390d3339191acb145d81ed5379d2074840cf0c33a20bdbd6f32821f79eb4ad5d
+ languageName: node
+ linkType: hard
+
+"immer@npm:^10.1.1":
+ version: 10.2.0
+ resolution: "immer@npm:10.2.0"
+ checksum: 10c0/35e66b0585b2aec4e85ae7a993f049405f170799ba89d79205bc3fdae2c5bdaa2b1d35f62803d8beee42b7e85c7f7315a6e93b6a5a510c5a46f03dbe63619e87
+ languageName: node
+ linkType: hard
+
+"immer@npm:^11.0.0":
+ version: 11.1.4
+ resolution: "immer@npm:11.1.4"
+ checksum: 10c0/77beca6b0a4e361b30414189d63c64beb7df40ac1d8cbf524308fcbabe755e9aa49db3c6e95a6e412911416fec621f2c8470be5ec79feedc6abd6e4f7f18a9ce
+ languageName: node
+ linkType: hard
+
+"import-fresh@npm:^3.2.1":
+ version: 3.3.1
+ resolution: "import-fresh@npm:3.3.1"
+ dependencies:
+ parent-module: "npm:^1.0.0"
+ resolve-from: "npm:^4.0.0"
+ checksum: 10c0/bf8cc494872fef783249709385ae883b447e3eb09db0ebd15dcead7d9afe7224dad7bd7591c6b73b0b19b3c0f9640eb8ee884f01cfaf2887ab995b0b36a0cbec
+ languageName: node
+ linkType: hard
+
+"imurmurhash@npm:^0.1.4":
+ version: 0.1.4
+ resolution: "imurmurhash@npm:0.1.4"
+ checksum: 10c0/8b51313850dd33605c6c9d3fd9638b714f4c4c40250cff658209f30d40da60f78992fb2df5dabee4acf589a6a82bbc79ad5486550754bd9ec4e3fc0d4a57d6a6
+ languageName: node
+ linkType: hard
+
+"inline-style-parser@npm:0.2.7":
+ version: 0.2.7
+ resolution: "inline-style-parser@npm:0.2.7"
+ checksum: 10c0/d884d76f84959517430ae6c22f0bda59bb3f58f539f99aac75a8d786199ec594ed648c6ab4640531f9fc244b0ed5cd8c458078e592d016ef06de793beb1debff
+ languageName: node
+ linkType: hard
+
+"internal-slot@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "internal-slot@npm:1.1.0"
+ dependencies:
+ es-errors: "npm:^1.3.0"
+ hasown: "npm:^2.0.2"
+ side-channel: "npm:^1.1.0"
+ checksum: 10c0/03966f5e259b009a9bf1a78d60da920df198af4318ec004f57b8aef1dd3fe377fbc8cce63a96e8c810010302654de89f9e19de1cd8ad0061d15be28a695465c7
+ languageName: node
+ linkType: hard
+
+"internmap@npm:1 - 2":
+ version: 2.0.3
+ resolution: "internmap@npm:2.0.3"
+ checksum: 10c0/8cedd57f07bbc22501516fbfc70447f0c6812871d471096fad9ea603516eacc2137b633633daf432c029712df0baefd793686388ddf5737e3ea15074b877f7ed
+ languageName: node
+ linkType: hard
+
+"ip-address@npm:^10.0.1":
+ version: 10.1.0
+ resolution: "ip-address@npm:10.1.0"
+ checksum: 10c0/0103516cfa93f6433b3bd7333fa876eb21263912329bfa47010af5e16934eeeff86f3d2ae700a3744a137839ddfad62b900c7a445607884a49b5d1e32a3d7566
+ languageName: node
+ linkType: hard
+
+"is-alphabetical@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "is-alphabetical@npm:2.0.1"
+ checksum: 10c0/932367456f17237533fd1fc9fe179df77957271020b83ea31da50e5cc472d35ef6b5fb8147453274ffd251134472ce24eb6f8d8398d96dee98237cdb81a6c9a7
+ languageName: node
+ linkType: hard
+
+"is-alphanumerical@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "is-alphanumerical@npm:2.0.1"
+ dependencies:
+ is-alphabetical: "npm:^2.0.0"
+ is-decimal: "npm:^2.0.0"
+ checksum: 10c0/4b35c42b18e40d41378293f82a3ecd9de77049b476f748db5697c297f686e1e05b072a6aaae2d16f54d2a57f85b00cbbe755c75f6d583d1c77d6657bd0feb5a2
+ languageName: node
+ linkType: hard
+
+"is-array-buffer@npm:^3.0.4, is-array-buffer@npm:^3.0.5":
+ version: 3.0.5
+ resolution: "is-array-buffer@npm:3.0.5"
+ dependencies:
+ call-bind: "npm:^1.0.8"
+ call-bound: "npm:^1.0.3"
+ get-intrinsic: "npm:^1.2.6"
+ checksum: 10c0/c5c9f25606e86dbb12e756694afbbff64bc8b348d1bc989324c037e1068695131930199d6ad381952715dad3a9569333817f0b1a72ce5af7f883ce802e49c83d
+ languageName: node
+ linkType: hard
+
+"is-async-function@npm:^2.0.0":
+ version: 2.1.1
+ resolution: "is-async-function@npm:2.1.1"
+ dependencies:
+ async-function: "npm:^1.0.0"
+ call-bound: "npm:^1.0.3"
+ get-proto: "npm:^1.0.1"
+ has-tostringtag: "npm:^1.0.2"
+ safe-regex-test: "npm:^1.1.0"
+ checksum: 10c0/d70c236a5e82de6fc4d44368ffd0c2fee2b088b893511ce21e679da275a5ecc6015ff59a7d7e1bdd7ca39f71a8dbdd253cf8cce5c6b3c91cdd5b42b5ce677298
+ languageName: node
+ linkType: hard
+
+"is-bigint@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "is-bigint@npm:1.1.0"
+ dependencies:
+ has-bigints: "npm:^1.0.2"
+ checksum: 10c0/f4f4b905ceb195be90a6ea7f34323bf1c18e3793f18922e3e9a73c684c29eeeeff5175605c3a3a74cc38185fe27758f07efba3dbae812e5c5afbc0d2316b40e4
+ languageName: node
+ linkType: hard
+
+"is-boolean-object@npm:^1.2.1":
+ version: 1.2.2
+ resolution: "is-boolean-object@npm:1.2.2"
+ dependencies:
+ call-bound: "npm:^1.0.3"
+ has-tostringtag: "npm:^1.0.2"
+ checksum: 10c0/36ff6baf6bd18b3130186990026f5a95c709345c39cd368468e6c1b6ab52201e9fd26d8e1f4c066357b4938b0f0401e1a5000e08257787c1a02f3a719457001e
+ languageName: node
+ linkType: hard
+
+"is-bun-module@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "is-bun-module@npm:2.0.0"
+ dependencies:
+ semver: "npm:^7.7.1"
+ checksum: 10c0/7d27a0679cfa5be1f5052650391f9b11040cd70c48d45112e312c56bc6b6ca9c9aea70dcce6cc40b1e8947bfff8567a5c5715d3b066fb478522dab46ea379240
+ languageName: node
+ linkType: hard
+
+"is-callable@npm:^1.2.7":
+ version: 1.2.7
+ resolution: "is-callable@npm:1.2.7"
+ checksum: 10c0/ceebaeb9d92e8adee604076971dd6000d38d6afc40bb843ea8e45c5579b57671c3f3b50d7f04869618242c6cee08d1b67806a8cb8edaaaf7c0748b3720d6066f
+ languageName: node
+ linkType: hard
+
+"is-core-module@npm:^2.13.0, is-core-module@npm:^2.16.1":
+ version: 2.16.1
+ resolution: "is-core-module@npm:2.16.1"
+ dependencies:
+ hasown: "npm:^2.0.2"
+ checksum: 10c0/898443c14780a577e807618aaae2b6f745c8538eca5c7bc11388a3f2dc6de82b9902bcc7eb74f07be672b11bbe82dd6a6edded44a00cb3d8f933d0459905eedd
+ languageName: node
+ linkType: hard
+
+"is-data-view@npm:^1.0.1, is-data-view@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "is-data-view@npm:1.0.2"
+ dependencies:
+ call-bound: "npm:^1.0.2"
+ get-intrinsic: "npm:^1.2.6"
+ is-typed-array: "npm:^1.1.13"
+ checksum: 10c0/ef3548a99d7e7f1370ce21006baca6d40c73e9f15c941f89f0049c79714c873d03b02dae1c64b3f861f55163ecc16da06506c5b8a1d4f16650b3d9351c380153
+ languageName: node
+ linkType: hard
+
+"is-date-object@npm:^1.0.5, is-date-object@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "is-date-object@npm:1.1.0"
+ dependencies:
+ call-bound: "npm:^1.0.2"
+ has-tostringtag: "npm:^1.0.2"
+ checksum: 10c0/1a4d199c8e9e9cac5128d32e6626fa7805175af9df015620ac0d5d45854ccf348ba494679d872d37301032e35a54fc7978fba1687e8721b2139aea7870cafa2f
+ languageName: node
+ linkType: hard
+
+"is-decimal@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "is-decimal@npm:2.0.1"
+ checksum: 10c0/8085dd66f7d82f9de818fba48b9e9c0429cb4291824e6c5f2622e96b9680b54a07a624cfc663b24148b8e853c62a1c987cfe8b0b5a13f5156991afaf6736e334
+ languageName: node
+ linkType: hard
+
+"is-extglob@npm:^2.1.1":
+ version: 2.1.1
+ resolution: "is-extglob@npm:2.1.1"
+ checksum: 10c0/5487da35691fbc339700bbb2730430b07777a3c21b9ebaecb3072512dfd7b4ba78ac2381a87e8d78d20ea08affb3f1971b4af629173a6bf435ff8a4c47747912
+ languageName: node
+ linkType: hard
+
+"is-finalizationregistry@npm:^1.1.0":
+ version: 1.1.1
+ resolution: "is-finalizationregistry@npm:1.1.1"
+ dependencies:
+ call-bound: "npm:^1.0.3"
+ checksum: 10c0/818dff679b64f19e228a8205a1e2d09989a98e98def3a817f889208cfcbf918d321b251aadf2c05918194803ebd2eb01b14fc9d0b2bea53d984f4137bfca5e97
+ languageName: node
+ linkType: hard
+
+"is-generator-function@npm:^1.0.10":
+ version: 1.1.2
+ resolution: "is-generator-function@npm:1.1.2"
+ dependencies:
+ call-bound: "npm:^1.0.4"
+ generator-function: "npm:^2.0.0"
+ get-proto: "npm:^1.0.1"
+ has-tostringtag: "npm:^1.0.2"
+ safe-regex-test: "npm:^1.1.0"
+ checksum: 10c0/83da102e89c3e3b71d67b51d47c9f9bc862bceb58f87201727e27f7fa19d1d90b0ab223644ecaee6fc6e3d2d622bb25c966fbdaf87c59158b01ce7c0fe2fa372
+ languageName: node
+ linkType: hard
+
+"is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3":
+ version: 4.0.3
+ resolution: "is-glob@npm:4.0.3"
+ dependencies:
+ is-extglob: "npm:^2.1.1"
+ checksum: 10c0/17fb4014e22be3bbecea9b2e3a76e9e34ff645466be702f1693e8f1ee1adac84710d0be0bd9f967d6354036fd51ab7c2741d954d6e91dae6bb69714de92c197a
+ languageName: node
+ linkType: hard
+
+"is-hexadecimal@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "is-hexadecimal@npm:2.0.1"
+ checksum: 10c0/3eb60fe2f1e2bbc760b927dcad4d51eaa0c60138cf7fc671803f66353ad90c301605b502c7ea4c6bb0548e1c7e79dfd37b73b632652e3b76030bba603a7e9626
+ languageName: node
+ linkType: hard
+
+"is-map@npm:^2.0.3":
+ version: 2.0.3
+ resolution: "is-map@npm:2.0.3"
+ checksum: 10c0/2c4d431b74e00fdda7162cd8e4b763d6f6f217edf97d4f8538b94b8702b150610e2c64961340015fe8df5b1fcee33ccd2e9b62619c4a8a3a155f8de6d6d355fc
+ languageName: node
+ linkType: hard
+
+"is-negative-zero@npm:^2.0.3":
+ version: 2.0.3
+ resolution: "is-negative-zero@npm:2.0.3"
+ checksum: 10c0/bcdcf6b8b9714063ffcfa9929c575ac69bfdabb8f4574ff557dfc086df2836cf07e3906f5bbc4f2a5c12f8f3ba56af640c843cdfc74da8caed86c7c7d66fd08e
+ languageName: node
+ linkType: hard
+
+"is-number-object@npm:^1.1.1":
+ version: 1.1.1
+ resolution: "is-number-object@npm:1.1.1"
+ dependencies:
+ call-bound: "npm:^1.0.3"
+ has-tostringtag: "npm:^1.0.2"
+ checksum: 10c0/97b451b41f25135ff021d85c436ff0100d84a039bb87ffd799cbcdbea81ef30c464ced38258cdd34f080be08fc3b076ca1f472086286d2aa43521d6ec6a79f53
+ languageName: node
+ linkType: hard
+
+"is-number@npm:^7.0.0":
+ version: 7.0.0
+ resolution: "is-number@npm:7.0.0"
+ checksum: 10c0/b4686d0d3053146095ccd45346461bc8e53b80aeb7671cc52a4de02dbbf7dc0d1d2a986e2fe4ae206984b4d34ef37e8b795ebc4f4295c978373e6575e295d811
+ languageName: node
+ linkType: hard
+
+"is-plain-obj@npm:^4.0.0":
+ version: 4.1.0
+ resolution: "is-plain-obj@npm:4.1.0"
+ checksum: 10c0/32130d651d71d9564dc88ba7e6fda0e91a1010a3694648e9f4f47bb6080438140696d3e3e15c741411d712e47ac9edc1a8a9de1fe76f3487b0d90be06ac9975e
+ languageName: node
+ linkType: hard
+
+"is-regex@npm:^1.2.1":
+ version: 1.2.1
+ resolution: "is-regex@npm:1.2.1"
+ dependencies:
+ call-bound: "npm:^1.0.2"
+ gopd: "npm:^1.2.0"
+ has-tostringtag: "npm:^1.0.2"
+ hasown: "npm:^2.0.2"
+ checksum: 10c0/1d3715d2b7889932349241680032e85d0b492cfcb045acb75ffc2c3085e8d561184f1f7e84b6f8321935b4aea39bc9c6ba74ed595b57ce4881a51dfdbc214e04
+ languageName: node
+ linkType: hard
+
+"is-set@npm:^2.0.3":
+ version: 2.0.3
+ resolution: "is-set@npm:2.0.3"
+ checksum: 10c0/f73732e13f099b2dc879c2a12341cfc22ccaca8dd504e6edae26484bd5707a35d503fba5b4daad530a9b088ced1ae6c9d8200fd92e09b428fe14ea79ce8080b7
+ languageName: node
+ linkType: hard
+
+"is-shared-array-buffer@npm:^1.0.4":
+ version: 1.0.4
+ resolution: "is-shared-array-buffer@npm:1.0.4"
+ dependencies:
+ call-bound: "npm:^1.0.3"
+ checksum: 10c0/65158c2feb41ff1edd6bbd6fd8403a69861cf273ff36077982b5d4d68e1d59278c71691216a4a64632bd76d4792d4d1d2553901b6666d84ade13bba5ea7bc7db
+ languageName: node
+ linkType: hard
+
+"is-string@npm:^1.1.1":
+ version: 1.1.1
+ resolution: "is-string@npm:1.1.1"
+ dependencies:
+ call-bound: "npm:^1.0.3"
+ has-tostringtag: "npm:^1.0.2"
+ checksum: 10c0/2f518b4e47886bb81567faba6ffd0d8a8333cf84336e2e78bf160693972e32ad00fe84b0926491cc598dee576fdc55642c92e62d0cbe96bf36f643b6f956f94d
+ languageName: node
+ linkType: hard
+
+"is-symbol@npm:^1.0.4, is-symbol@npm:^1.1.1":
+ version: 1.1.1
+ resolution: "is-symbol@npm:1.1.1"
+ dependencies:
+ call-bound: "npm:^1.0.2"
+ has-symbols: "npm:^1.1.0"
+ safe-regex-test: "npm:^1.1.0"
+ checksum: 10c0/f08f3e255c12442e833f75a9e2b84b2d4882fdfd920513cf2a4a2324f0a5b076c8fd913778e3ea5d258d5183e9d92c0cd20e04b03ab3df05316b049b2670af1e
+ languageName: node
+ linkType: hard
+
+"is-typed-array@npm:^1.1.13, is-typed-array@npm:^1.1.14, is-typed-array@npm:^1.1.15":
+ version: 1.1.15
+ resolution: "is-typed-array@npm:1.1.15"
+ dependencies:
+ which-typed-array: "npm:^1.1.16"
+ checksum: 10c0/415511da3669e36e002820584e264997ffe277ff136643a3126cc949197e6ca3334d0f12d084e83b1994af2e9c8141275c741cf2b7da5a2ff62dd0cac26f76c4
+ languageName: node
+ linkType: hard
+
+"is-weakmap@npm:^2.0.2":
+ version: 2.0.2
+ resolution: "is-weakmap@npm:2.0.2"
+ checksum: 10c0/443c35bb86d5e6cc5929cd9c75a4024bb0fff9586ed50b092f94e700b89c43a33b186b76dbc6d54f3d3d09ece689ab38dcdc1af6a482cbe79c0f2da0a17f1299
+ languageName: node
+ linkType: hard
+
+"is-weakref@npm:^1.0.2, is-weakref@npm:^1.1.1":
+ version: 1.1.1
+ resolution: "is-weakref@npm:1.1.1"
+ dependencies:
+ call-bound: "npm:^1.0.3"
+ checksum: 10c0/8e0a9c07b0c780949a100e2cab2b5560a48ecd4c61726923c1a9b77b6ab0aa0046c9e7fb2206042296817045376dee2c8ab1dabe08c7c3dfbf195b01275a085b
+ languageName: node
+ linkType: hard
+
+"is-weakset@npm:^2.0.3":
+ version: 2.0.4
+ resolution: "is-weakset@npm:2.0.4"
+ dependencies:
+ call-bound: "npm:^1.0.3"
+ get-intrinsic: "npm:^1.2.6"
+ checksum: 10c0/6491eba08acb8dc9532da23cb226b7d0192ede0b88f16199e592e4769db0a077119c1f5d2283d1e0d16d739115f70046e887e477eb0e66cd90e1bb29f28ba647
+ languageName: node
+ linkType: hard
+
+"isarray@npm:^2.0.5":
+ version: 2.0.5
+ resolution: "isarray@npm:2.0.5"
+ checksum: 10c0/4199f14a7a13da2177c66c31080008b7124331956f47bca57dd0b6ea9f11687aa25e565a2c7a2b519bc86988d10398e3049a1f5df13c9f6b7664154690ae79fd
+ languageName: node
+ linkType: hard
+
+"isexe@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "isexe@npm:2.0.0"
+ checksum: 10c0/228cfa503fadc2c31596ab06ed6aa82c9976eec2bfd83397e7eaf06d0ccf42cd1dfd6743bf9aeb01aebd4156d009994c5f76ea898d2832c1fe342da923ca457d
+ languageName: node
+ linkType: hard
+
+"isexe@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "isexe@npm:4.0.0"
+ checksum: 10c0/5884815115bceac452877659a9c7726382531592f43dc29e5d48b7c4100661aed54018cb90bd36cb2eaeba521092570769167acbb95c18d39afdccbcca06c5ce
+ languageName: node
+ linkType: hard
+
+"iterator.prototype@npm:^1.1.5":
+ version: 1.1.5
+ resolution: "iterator.prototype@npm:1.1.5"
+ dependencies:
+ define-data-property: "npm:^1.1.4"
+ es-object-atoms: "npm:^1.0.0"
+ get-intrinsic: "npm:^1.2.6"
+ get-proto: "npm:^1.0.0"
+ has-symbols: "npm:^1.1.0"
+ set-function-name: "npm:^2.0.2"
+ checksum: 10c0/f7a262808e1b41049ab55f1e9c29af7ec1025a000d243b83edf34ce2416eedd56079b117fa59376bb4a724110690f13aa8427f2ee29a09eec63a7e72367626d0
+ languageName: node
+ linkType: hard
+
+"jiti@npm:^2.6.1":
+ version: 2.6.1
+ resolution: "jiti@npm:2.6.1"
+ bin:
+ jiti: lib/jiti-cli.mjs
+ checksum: 10c0/79b2e96a8e623f66c1b703b98ec1b8be4500e1d217e09b09e343471bbb9c105381b83edbb979d01cef18318cc45ce6e153571b6c83122170eefa531c64b6789b
+ languageName: node
+ linkType: hard
+
+"jose@npm:^6.1.0":
+ version: 6.2.1
+ resolution: "jose@npm:6.2.1"
+ checksum: 10c0/456822e00a2ee6b1470fabadd694b237af64b9977aa8a47844aae2841298daefd79bb04ff328cbc3aa3c886761aa72b33bc5c1ad797b31b8368e77a89d09b779
+ languageName: node
+ linkType: hard
+
+"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "js-tokens@npm:4.0.0"
+ checksum: 10c0/e248708d377aa058eacf2037b07ded847790e6de892bbad3dac0abba2e759cb9f121b00099a65195616badcb6eca8d14d975cb3e89eb1cfda644756402c8aeed
+ languageName: node
+ linkType: hard
+
+"js-tokens@npm:^9.0.1":
+ version: 9.0.1
+ resolution: "js-tokens@npm:9.0.1"
+ checksum: 10c0/68dcab8f233dde211a6b5fd98079783cbcd04b53617c1250e3553ee16ab3e6134f5e65478e41d82f6d351a052a63d71024553933808570f04dbf828d7921e80e
+ languageName: node
+ linkType: hard
+
+"js-yaml@npm:^4.1.1":
+ version: 4.1.1
+ resolution: "js-yaml@npm:4.1.1"
+ dependencies:
+ argparse: "npm:^2.0.1"
+ bin:
+ js-yaml: bin/js-yaml.js
+ checksum: 10c0/561c7d7088c40a9bb53cc75becbfb1df6ae49b34b5e6e5a81744b14ae8667ec564ad2527709d1a6e7d5e5fa6d483aa0f373a50ad98d42fde368ec4a190d4fae7
+ languageName: node
+ linkType: hard
+
+"jsesc@npm:^3.0.2":
+ version: 3.1.0
+ resolution: "jsesc@npm:3.1.0"
+ bin:
+ jsesc: bin/jsesc
+ checksum: 10c0/531779df5ec94f47e462da26b4cbf05eb88a83d9f08aac2ba04206508fc598527a153d08bd462bae82fc78b3eaa1a908e1a4a79f886e9238641c4cdefaf118b1
+ languageName: node
+ linkType: hard
+
+"json-buffer@npm:3.0.1":
+ version: 3.0.1
+ resolution: "json-buffer@npm:3.0.1"
+ checksum: 10c0/0d1c91569d9588e7eef2b49b59851f297f3ab93c7b35c7c221e288099322be6b562767d11e4821da500f3219542b9afd2e54c5dc573107c1126ed1080f8e96d7
+ languageName: node
+ linkType: hard
+
+"json-schema-traverse@npm:^0.4.1":
+ version: 0.4.1
+ resolution: "json-schema-traverse@npm:0.4.1"
+ checksum: 10c0/108fa90d4cc6f08243aedc6da16c408daf81793bf903e9fd5ab21983cda433d5d2da49e40711da016289465ec2e62e0324dcdfbc06275a607fe3233fde4942ce
+ languageName: node
+ linkType: hard
+
+"json-stable-stringify-without-jsonify@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "json-stable-stringify-without-jsonify@npm:1.0.1"
+ checksum: 10c0/cb168b61fd4de83e58d09aaa6425ef71001bae30d260e2c57e7d09a5fd82223e2f22a042dedaab8db23b7d9ae46854b08bb1f91675a8be11c5cffebef5fb66a5
+ languageName: node
+ linkType: hard
+
+"json5@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "json5@npm:1.0.2"
+ dependencies:
+ minimist: "npm:^1.2.0"
+ bin:
+ json5: lib/cli.js
+ checksum: 10c0/9ee316bf21f000b00752e6c2a3b79ecf5324515a5c60ee88983a1910a45426b643a4f3461657586e8aeca87aaf96f0a519b0516d2ae527a6c3e7eed80f68717f
+ languageName: node
+ linkType: hard
+
+"json5@npm:^2.2.3":
+ version: 2.2.3
+ resolution: "json5@npm:2.2.3"
+ bin:
+ json5: lib/cli.js
+ checksum: 10c0/5a04eed94810fa55c5ea138b2f7a5c12b97c3750bc63d11e511dcecbfef758003861522a070c2272764ee0f4e3e323862f386945aeb5b85b87ee43f084ba586c
+ languageName: node
+ linkType: hard
+
+"jsx-ast-utils@npm:^2.4.1 || ^3.0.0, jsx-ast-utils@npm:^3.3.5":
+ version: 3.3.5
+ resolution: "jsx-ast-utils@npm:3.3.5"
+ dependencies:
+ array-includes: "npm:^3.1.6"
+ array.prototype.flat: "npm:^1.3.1"
+ object.assign: "npm:^4.1.4"
+ object.values: "npm:^1.1.6"
+ checksum: 10c0/a32679e9cb55469cb6d8bbc863f7d631b2c98b7fc7bf172629261751a6e7bc8da6ae374ddb74d5fbd8b06cf0eb4572287b259813d92b36e384024ed35e4c13e1
+ languageName: node
+ linkType: hard
+
+"keyv@npm:^4.5.4":
+ version: 4.5.4
+ resolution: "keyv@npm:4.5.4"
+ dependencies:
+ json-buffer: "npm:3.0.1"
+ checksum: 10c0/aa52f3c5e18e16bb6324876bb8b59dd02acf782a4b789c7b2ae21107fab95fab3890ed448d4f8dba80ce05391eeac4bfabb4f02a20221342982f806fa2cf271e
+ languageName: node
+ linkType: hard
+
+"kysely@npm:^0.28.5":
+ version: 0.28.12
+ resolution: "kysely@npm:0.28.12"
+ checksum: 10c0/93fa290209f80f7324581a66476bb951e35a9226eaceb64069fddaa31ef6f4712ae307448d32734b985c4d7d6e79e3ff92b985c1d8efae0159d06964bea3bb62
+ languageName: node
+ linkType: hard
+
+"language-subtag-registry@npm:^0.3.20":
+ version: 0.3.23
+ resolution: "language-subtag-registry@npm:0.3.23"
+ checksum: 10c0/e9b05190421d2cd36dd6c95c28673019c927947cb6d94f40ba7e77a838629ee9675c94accf897fbebb07923187deb843b8fbb8935762df6edafe6c28dcb0b86c
+ languageName: node
+ linkType: hard
+
+"language-tags@npm:^1.0.9":
+ version: 1.0.9
+ resolution: "language-tags@npm:1.0.9"
+ dependencies:
+ language-subtag-registry: "npm:^0.3.20"
+ checksum: 10c0/9ab911213c4bd8bd583c850201c17794e52cb0660d1ab6e32558aadc8324abebf6844e46f92b80a5d600d0fbba7eface2c207bfaf270a1c7fd539e4c3a880bff
+ languageName: node
+ linkType: hard
+
+"levn@npm:^0.4.1":
+ version: 0.4.1
+ resolution: "levn@npm:0.4.1"
+ dependencies:
+ prelude-ls: "npm:^1.2.1"
+ type-check: "npm:~0.4.0"
+ checksum: 10c0/effb03cad7c89dfa5bd4f6989364bfc79994c2042ec5966cb9b95990e2edee5cd8969ddf42616a0373ac49fac1403437deaf6e9050fbbaa3546093a59b9ac94e
+ languageName: node
+ linkType: hard
+
+"lightningcss-android-arm64@npm:1.31.1":
+ version: 1.31.1
+ resolution: "lightningcss-android-arm64@npm:1.31.1"
+ conditions: os=android & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"lightningcss-darwin-arm64@npm:1.31.1":
+ version: 1.31.1
+ resolution: "lightningcss-darwin-arm64@npm:1.31.1"
+ conditions: os=darwin & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"lightningcss-darwin-x64@npm:1.31.1":
+ version: 1.31.1
+ resolution: "lightningcss-darwin-x64@npm:1.31.1"
+ conditions: os=darwin & cpu=x64
+ languageName: node
+ linkType: hard
+
+"lightningcss-freebsd-x64@npm:1.31.1":
+ version: 1.31.1
+ resolution: "lightningcss-freebsd-x64@npm:1.31.1"
+ conditions: os=freebsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"lightningcss-linux-arm-gnueabihf@npm:1.31.1":
+ version: 1.31.1
+ resolution: "lightningcss-linux-arm-gnueabihf@npm:1.31.1"
+ conditions: os=linux & cpu=arm
+ languageName: node
+ linkType: hard
+
+"lightningcss-linux-arm64-gnu@npm:1.31.1":
+ version: 1.31.1
+ resolution: "lightningcss-linux-arm64-gnu@npm:1.31.1"
+ conditions: os=linux & cpu=arm64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"lightningcss-linux-arm64-musl@npm:1.31.1":
+ version: 1.31.1
+ resolution: "lightningcss-linux-arm64-musl@npm:1.31.1"
+ conditions: os=linux & cpu=arm64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"lightningcss-linux-x64-gnu@npm:1.31.1":
+ version: 1.31.1
+ resolution: "lightningcss-linux-x64-gnu@npm:1.31.1"
+ conditions: os=linux & cpu=x64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"lightningcss-linux-x64-musl@npm:1.31.1":
+ version: 1.31.1
+ resolution: "lightningcss-linux-x64-musl@npm:1.31.1"
+ conditions: os=linux & cpu=x64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"lightningcss-win32-arm64-msvc@npm:1.31.1":
+ version: 1.31.1
+ resolution: "lightningcss-win32-arm64-msvc@npm:1.31.1"
+ conditions: os=win32 & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"lightningcss-win32-x64-msvc@npm:1.31.1":
+ version: 1.31.1
+ resolution: "lightningcss-win32-x64-msvc@npm:1.31.1"
+ conditions: os=win32 & cpu=x64
+ languageName: node
+ linkType: hard
+
+"lightningcss@npm:1.31.1":
+ version: 1.31.1
+ resolution: "lightningcss@npm:1.31.1"
+ dependencies:
+ detect-libc: "npm:^2.0.3"
+ lightningcss-android-arm64: "npm:1.31.1"
+ lightningcss-darwin-arm64: "npm:1.31.1"
+ lightningcss-darwin-x64: "npm:1.31.1"
+ lightningcss-freebsd-x64: "npm:1.31.1"
+ lightningcss-linux-arm-gnueabihf: "npm:1.31.1"
+ lightningcss-linux-arm64-gnu: "npm:1.31.1"
+ lightningcss-linux-arm64-musl: "npm:1.31.1"
+ lightningcss-linux-x64-gnu: "npm:1.31.1"
+ lightningcss-linux-x64-musl: "npm:1.31.1"
+ lightningcss-win32-arm64-msvc: "npm:1.31.1"
+ lightningcss-win32-x64-msvc: "npm:1.31.1"
+ dependenciesMeta:
+ lightningcss-android-arm64:
+ optional: true
+ lightningcss-darwin-arm64:
+ optional: true
+ lightningcss-darwin-x64:
+ optional: true
+ lightningcss-freebsd-x64:
+ optional: true
+ lightningcss-linux-arm-gnueabihf:
+ optional: true
+ lightningcss-linux-arm64-gnu:
+ optional: true
+ lightningcss-linux-arm64-musl:
+ optional: true
+ lightningcss-linux-x64-gnu:
+ optional: true
+ lightningcss-linux-x64-musl:
+ optional: true
+ lightningcss-win32-arm64-msvc:
+ optional: true
+ lightningcss-win32-x64-msvc:
+ optional: true
+ checksum: 10c0/c6754b305d4a73652e472fc0d7d65384a6e16c336ea61068eca60de2a45bd5c30abbf012358b82eac56ee98b5d88028932cda5268ff61967cffa400b9e7ee2ba
+ languageName: node
+ linkType: hard
+
+"locate-path@npm:^6.0.0":
+ version: 6.0.0
+ resolution: "locate-path@npm:6.0.0"
+ dependencies:
+ p-locate: "npm:^5.0.0"
+ checksum: 10c0/d3972ab70dfe58ce620e64265f90162d247e87159b6126b01314dd67be43d50e96a50b517bce2d9452a79409c7614054c277b5232377de50416564a77ac7aad3
+ languageName: node
+ linkType: hard
+
+"lodash.merge@npm:^4.6.2":
+ version: 4.6.2
+ resolution: "lodash.merge@npm:4.6.2"
+ checksum: 10c0/402fa16a1edd7538de5b5903a90228aa48eb5533986ba7fa26606a49db2572bf414ff73a2c9f5d5fd36b31c46a5d5c7e1527749c07cbcf965ccff5fbdf32c506
+ languageName: node
+ linkType: hard
+
+"longest-streak@npm:^3.0.0":
+ version: 3.1.0
+ resolution: "longest-streak@npm:3.1.0"
+ checksum: 10c0/7c2f02d0454b52834d1bcedef79c557bd295ee71fdabb02d041ff3aa9da48a90b5df7c0409156dedbc4df9b65da18742652aaea4759d6ece01f08971af6a7eaa
+ languageName: node
+ linkType: hard
+
+"loose-envify@npm:^1.4.0":
+ version: 1.4.0
+ resolution: "loose-envify@npm:1.4.0"
+ dependencies:
+ js-tokens: "npm:^3.0.0 || ^4.0.0"
+ bin:
+ loose-envify: cli.js
+ checksum: 10c0/655d110220983c1a4b9c0c679a2e8016d4b67f6e9c7b5435ff5979ecdb20d0813f4dec0a08674fcbdd4846a3f07edbb50a36811fd37930b94aaa0d9daceb017e
+ languageName: node
+ linkType: hard
+
+"loupe@npm:^3.1.0, loupe@npm:^3.1.4":
+ version: 3.2.1
+ resolution: "loupe@npm:3.2.1"
+ checksum: 10c0/910c872cba291309664c2d094368d31a68907b6f5913e989d301b5c25f30e97d76d77f23ab3bf3b46d0f601ff0b6af8810c10c31b91d2c6b2f132809ca2cc705
+ languageName: node
+ linkType: hard
+
+"lowlight@npm:^3.0.0":
+ version: 3.3.0
+ resolution: "lowlight@npm:3.3.0"
+ dependencies:
+ "@types/hast": "npm:^3.0.0"
+ devlop: "npm:^1.0.0"
+ highlight.js: "npm:~11.11.0"
+ checksum: 10c0/9b796fa8443b0334ebf18bc57387c9ee31432d8c263cf2089d23e1087c653d708447284e0647bf993cb2cdc810e0b268a28f51ea27b4a624893b97bdd3f025f4
+ languageName: node
+ linkType: hard
+
+"lru-cache@npm:^11.0.0, lru-cache@npm:^11.1.0, lru-cache@npm:^11.2.1":
+ version: 11.2.7
+ resolution: "lru-cache@npm:11.2.7"
+ checksum: 10c0/549cdb59488baa617135fc12159cafb1a97f91079f35093bb3bcad72e849fc64ace636d244212c181dfdf1a99bbfa90757ff303f98561958ee4d0f885d9bd5f7
+ languageName: node
+ linkType: hard
+
+"lru-cache@npm:^5.1.1":
+ version: 5.1.1
+ resolution: "lru-cache@npm:5.1.1"
+ dependencies:
+ yallist: "npm:^3.0.2"
+ checksum: 10c0/89b2ef2ef45f543011e38737b8a8622a2f8998cddf0e5437174ef8f1f70a8b9d14a918ab3e232cb3ba343b7abddffa667f0b59075b2b80e6b4d63c3de6127482
+ languageName: node
+ linkType: hard
+
+"lucide-react@npm:^0.475.0":
+ version: 0.475.0
+ resolution: "lucide-react@npm:0.475.0"
+ peerDependencies:
+ react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
+ checksum: 10c0/9cb17bd4e70da4db104874b6b2e9d9c7e2be9438e9d1c0b2565df0c4d0bdd1add41b7dff3cb60840699ecbd29870c453878b42b69a7c46480def0c9370a852a9
+ languageName: node
+ linkType: hard
+
+"magic-string@npm:^0.30.17, magic-string@npm:^0.30.21":
+ version: 0.30.21
+ resolution: "magic-string@npm:0.30.21"
+ dependencies:
+ "@jridgewell/sourcemap-codec": "npm:^1.5.5"
+ checksum: 10c0/299378e38f9a270069fc62358522ddfb44e94244baa0d6a8980ab2a9b2490a1d03b236b447eee309e17eb3bddfa482c61259d47960eb018a904f0ded52780c4a
+ languageName: node
+ linkType: hard
+
+"make-fetch-happen@npm:^15.0.0":
+ version: 15.0.5
+ resolution: "make-fetch-happen@npm:15.0.5"
+ dependencies:
+ "@gar/promise-retry": "npm:^1.0.0"
+ "@npmcli/agent": "npm:^4.0.0"
+ "@npmcli/redact": "npm:^4.0.0"
+ cacache: "npm:^20.0.1"
+ http-cache-semantics: "npm:^4.1.1"
+ minipass: "npm:^7.0.2"
+ minipass-fetch: "npm:^5.0.0"
+ minipass-flush: "npm:^1.0.5"
+ minipass-pipeline: "npm:^1.2.4"
+ negotiator: "npm:^1.0.0"
+ proc-log: "npm:^6.0.0"
+ ssri: "npm:^13.0.0"
+ checksum: 10c0/527580eb5e5476e6ad07a4e3bd017d13e935f4be815674b442081ae5a721c13d3af5715006619e6be79a85723067e047f83a0c9e699f41d8cec43609a8de4f7b
+ languageName: node
+ linkType: hard
+
+"markdown-table@npm:^3.0.0":
+ version: 3.0.4
+ resolution: "markdown-table@npm:3.0.4"
+ checksum: 10c0/1257b31827629a54c24a5030a3dac952256c559174c95ce3ef89bebd6bff0cb1444b1fd667b1a1bb53307f83278111505b3e26f0c4e7b731e0060d435d2d930b
+ languageName: node
+ linkType: hard
+
+"math-intrinsics@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "math-intrinsics@npm:1.1.0"
+ checksum: 10c0/7579ff94e899e2f76ab64491d76cf606274c874d8f2af4a442c016bd85688927fcfca157ba6bf74b08e9439dc010b248ce05b96cc7c126a354c3bae7fcb48b7f
+ languageName: node
+ linkType: hard
+
+"mdast-util-find-and-replace@npm:^3.0.0":
+ version: 3.0.2
+ resolution: "mdast-util-find-and-replace@npm:3.0.2"
+ dependencies:
+ "@types/mdast": "npm:^4.0.0"
+ escape-string-regexp: "npm:^5.0.0"
+ unist-util-is: "npm:^6.0.0"
+ unist-util-visit-parents: "npm:^6.0.0"
+ checksum: 10c0/c8417a35605d567772ff5c1aa08363ff3010b0d60c8ea68c53cba09bf25492e3dd261560425c1756535f3b7107f62e7ff3857cdd8fb1e62d1b2cc2ea6e074ca2
+ languageName: node
+ linkType: hard
+
+"mdast-util-from-markdown@npm:^2.0.0":
+ version: 2.0.3
+ resolution: "mdast-util-from-markdown@npm:2.0.3"
+ dependencies:
+ "@types/mdast": "npm:^4.0.0"
+ "@types/unist": "npm:^3.0.0"
+ decode-named-character-reference: "npm:^1.0.0"
+ devlop: "npm:^1.0.0"
+ mdast-util-to-string: "npm:^4.0.0"
+ micromark: "npm:^4.0.0"
+ micromark-util-decode-numeric-character-reference: "npm:^2.0.0"
+ micromark-util-decode-string: "npm:^2.0.0"
+ micromark-util-normalize-identifier: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ unist-util-stringify-position: "npm:^4.0.0"
+ checksum: 10c0/d3eac9ac2b88e3b41fb85aa81c7bfd1f4f8a2fde497ad805e66fea7b2abfe486ffd94d2a20f9fd2951dcdebe4916f3bdcf851319891dd62d343e26c2f02583ba
+ languageName: node
+ linkType: hard
+
+"mdast-util-gfm-autolink-literal@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "mdast-util-gfm-autolink-literal@npm:2.0.1"
+ dependencies:
+ "@types/mdast": "npm:^4.0.0"
+ ccount: "npm:^2.0.0"
+ devlop: "npm:^1.0.0"
+ mdast-util-find-and-replace: "npm:^3.0.0"
+ micromark-util-character: "npm:^2.0.0"
+ checksum: 10c0/963cd22bd42aebdec7bdd0a527c9494d024d1ad0739c43dc040fee35bdfb5e29c22564330a7418a72b5eab51d47a6eff32bc0255ef3ccb5cebfe8970e91b81b6
+ languageName: node
+ linkType: hard
+
+"mdast-util-gfm-footnote@npm:^2.0.0":
+ version: 2.1.0
+ resolution: "mdast-util-gfm-footnote@npm:2.1.0"
+ dependencies:
+ "@types/mdast": "npm:^4.0.0"
+ devlop: "npm:^1.1.0"
+ mdast-util-from-markdown: "npm:^2.0.0"
+ mdast-util-to-markdown: "npm:^2.0.0"
+ micromark-util-normalize-identifier: "npm:^2.0.0"
+ checksum: 10c0/8ab965ee6be3670d76ec0e95b2ba3101fc7444eec47564943ab483d96ac17d29da2a4e6146a2a288be30c21b48c4f3938a1e54b9a46fbdd321d49a5bc0077ed0
+ languageName: node
+ linkType: hard
+
+"mdast-util-gfm-strikethrough@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "mdast-util-gfm-strikethrough@npm:2.0.0"
+ dependencies:
+ "@types/mdast": "npm:^4.0.0"
+ mdast-util-from-markdown: "npm:^2.0.0"
+ mdast-util-to-markdown: "npm:^2.0.0"
+ checksum: 10c0/b053e93d62c7545019bd914271ea9e5667ad3b3b57d16dbf68e56fea39a7e19b4a345e781312714eb3d43fdd069ff7ee22a3ca7f6149dfa774554f19ce3ac056
+ languageName: node
+ linkType: hard
+
+"mdast-util-gfm-table@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "mdast-util-gfm-table@npm:2.0.0"
+ dependencies:
+ "@types/mdast": "npm:^4.0.0"
+ devlop: "npm:^1.0.0"
+ markdown-table: "npm:^3.0.0"
+ mdast-util-from-markdown: "npm:^2.0.0"
+ mdast-util-to-markdown: "npm:^2.0.0"
+ checksum: 10c0/128af47c503a53bd1c79f20642561e54a510ad5e2db1e418d28fefaf1294ab839e6c838e341aef5d7e404f9170b9ca3d1d89605f234efafde93ee51174a6e31e
+ languageName: node
+ linkType: hard
+
+"mdast-util-gfm-task-list-item@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "mdast-util-gfm-task-list-item@npm:2.0.0"
+ dependencies:
+ "@types/mdast": "npm:^4.0.0"
+ devlop: "npm:^1.0.0"
+ mdast-util-from-markdown: "npm:^2.0.0"
+ mdast-util-to-markdown: "npm:^2.0.0"
+ checksum: 10c0/258d725288482b636c0a376c296431390c14b4f29588675297cb6580a8598ed311fc73ebc312acfca12cc8546f07a3a285a53a3b082712e2cbf5c190d677d834
+ languageName: node
+ linkType: hard
+
+"mdast-util-gfm@npm:^3.0.0":
+ version: 3.1.0
+ resolution: "mdast-util-gfm@npm:3.1.0"
+ dependencies:
+ mdast-util-from-markdown: "npm:^2.0.0"
+ mdast-util-gfm-autolink-literal: "npm:^2.0.0"
+ mdast-util-gfm-footnote: "npm:^2.0.0"
+ mdast-util-gfm-strikethrough: "npm:^2.0.0"
+ mdast-util-gfm-table: "npm:^2.0.0"
+ mdast-util-gfm-task-list-item: "npm:^2.0.0"
+ mdast-util-to-markdown: "npm:^2.0.0"
+ checksum: 10c0/4bedcfb6a20e39901c8772f0d2bb2d7a64ae87a54c13cbd92eec062cf470fbb68c2ad754e149af5b30794e2de61c978ab1de1ace03c0c40f443ca9b9b8044f81
+ languageName: node
+ linkType: hard
+
+"mdast-util-mdx-expression@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "mdast-util-mdx-expression@npm:2.0.1"
+ dependencies:
+ "@types/estree-jsx": "npm:^1.0.0"
+ "@types/hast": "npm:^3.0.0"
+ "@types/mdast": "npm:^4.0.0"
+ devlop: "npm:^1.0.0"
+ mdast-util-from-markdown: "npm:^2.0.0"
+ mdast-util-to-markdown: "npm:^2.0.0"
+ checksum: 10c0/9a1e57940f66431f10312fa239096efa7627f375e7933b5d3162c0b5c1712a72ac87447aff2b6838d2bbd5c1311b188718cc90b33b67dc67a88550e0a6ef6183
+ languageName: node
+ linkType: hard
+
+"mdast-util-mdx-jsx@npm:^3.0.0":
+ version: 3.2.0
+ resolution: "mdast-util-mdx-jsx@npm:3.2.0"
+ dependencies:
+ "@types/estree-jsx": "npm:^1.0.0"
+ "@types/hast": "npm:^3.0.0"
+ "@types/mdast": "npm:^4.0.0"
+ "@types/unist": "npm:^3.0.0"
+ ccount: "npm:^2.0.0"
+ devlop: "npm:^1.1.0"
+ mdast-util-from-markdown: "npm:^2.0.0"
+ mdast-util-to-markdown: "npm:^2.0.0"
+ parse-entities: "npm:^4.0.0"
+ stringify-entities: "npm:^4.0.0"
+ unist-util-stringify-position: "npm:^4.0.0"
+ vfile-message: "npm:^4.0.0"
+ checksum: 10c0/3acadaf3b962254f7ad2990fed4729961dc0217ca31fde9917986e880843f3ecf3392b1f22d569235cacd180d50894ad266db7af598aedca69d330d33c7ac613
+ languageName: node
+ linkType: hard
+
+"mdast-util-mdxjs-esm@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "mdast-util-mdxjs-esm@npm:2.0.1"
+ dependencies:
+ "@types/estree-jsx": "npm:^1.0.0"
+ "@types/hast": "npm:^3.0.0"
+ "@types/mdast": "npm:^4.0.0"
+ devlop: "npm:^1.0.0"
+ mdast-util-from-markdown: "npm:^2.0.0"
+ mdast-util-to-markdown: "npm:^2.0.0"
+ checksum: 10c0/5bda92fc154141705af2b804a534d891f28dac6273186edf1a4c5e3f045d5b01dbcac7400d27aaf91b7e76e8dce007c7b2fdf136c11ea78206ad00bdf9db46bc
+ languageName: node
+ linkType: hard
+
+"mdast-util-phrasing@npm:^4.0.0":
+ version: 4.1.0
+ resolution: "mdast-util-phrasing@npm:4.1.0"
+ dependencies:
+ "@types/mdast": "npm:^4.0.0"
+ unist-util-is: "npm:^6.0.0"
+ checksum: 10c0/bf6c31d51349aa3d74603d5e5a312f59f3f65662ed16c58017169a5fb0f84ca98578f626c5ee9e4aa3e0a81c996db8717096705521bddb4a0185f98c12c9b42f
+ languageName: node
+ linkType: hard
+
+"mdast-util-to-hast@npm:^13.0.0":
+ version: 13.2.1
+ resolution: "mdast-util-to-hast@npm:13.2.1"
+ dependencies:
+ "@types/hast": "npm:^3.0.0"
+ "@types/mdast": "npm:^4.0.0"
+ "@ungap/structured-clone": "npm:^1.0.0"
+ devlop: "npm:^1.0.0"
+ micromark-util-sanitize-uri: "npm:^2.0.0"
+ trim-lines: "npm:^3.0.0"
+ unist-util-position: "npm:^5.0.0"
+ unist-util-visit: "npm:^5.0.0"
+ vfile: "npm:^6.0.0"
+ checksum: 10c0/3eeaf28a5e84e1e08e6d54a1a8a06c0fca88cb5d36f4cf8086f0177248d1ce6e4e751f4ad0da19a3dea1c6ea61bd80784acc3ae021e44ceeb21aa5413a375e43
+ languageName: node
+ linkType: hard
+
+"mdast-util-to-markdown@npm:^2.0.0":
+ version: 2.1.2
+ resolution: "mdast-util-to-markdown@npm:2.1.2"
+ dependencies:
+ "@types/mdast": "npm:^4.0.0"
+ "@types/unist": "npm:^3.0.0"
+ longest-streak: "npm:^3.0.0"
+ mdast-util-phrasing: "npm:^4.0.0"
+ mdast-util-to-string: "npm:^4.0.0"
+ micromark-util-classify-character: "npm:^2.0.0"
+ micromark-util-decode-string: "npm:^2.0.0"
+ unist-util-visit: "npm:^5.0.0"
+ zwitch: "npm:^2.0.0"
+ checksum: 10c0/4649722a6099f12e797bd8d6469b2b43b44e526b5182862d9c7766a3431caad2c0112929c538a972f214e63c015395e5d3f54bd81d9ac1b16e6d8baaf582f749
+ languageName: node
+ linkType: hard
+
+"mdast-util-to-string@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "mdast-util-to-string@npm:4.0.0"
+ dependencies:
+ "@types/mdast": "npm:^4.0.0"
+ checksum: 10c0/2d3c1af29bf3fe9c20f552ee9685af308002488f3b04b12fa66652c9718f66f41a32f8362aa2d770c3ff464c034860b41715902ada2306bb0a055146cef064d7
+ languageName: node
+ linkType: hard
+
+"merge2@npm:^1.3.0":
+ version: 1.4.1
+ resolution: "merge2@npm:1.4.1"
+ checksum: 10c0/254a8a4605b58f450308fc474c82ac9a094848081bf4c06778200207820e5193726dc563a0d2c16468810516a5c97d9d3ea0ca6585d23c58ccfff2403e8dbbeb
+ languageName: node
+ linkType: hard
+
+"micromark-core-commonmark@npm:^2.0.0":
+ version: 2.0.3
+ resolution: "micromark-core-commonmark@npm:2.0.3"
+ dependencies:
+ decode-named-character-reference: "npm:^1.0.0"
+ devlop: "npm:^1.0.0"
+ micromark-factory-destination: "npm:^2.0.0"
+ micromark-factory-label: "npm:^2.0.0"
+ micromark-factory-space: "npm:^2.0.0"
+ micromark-factory-title: "npm:^2.0.0"
+ micromark-factory-whitespace: "npm:^2.0.0"
+ micromark-util-character: "npm:^2.0.0"
+ micromark-util-chunked: "npm:^2.0.0"
+ micromark-util-classify-character: "npm:^2.0.0"
+ micromark-util-html-tag-name: "npm:^2.0.0"
+ micromark-util-normalize-identifier: "npm:^2.0.0"
+ micromark-util-resolve-all: "npm:^2.0.0"
+ micromark-util-subtokenize: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ checksum: 10c0/bd4a794fdc9e88dbdf59eaf1c507ddf26e5f7ddf4e52566c72239c0f1b66adbcd219ba2cd42350debbe24471434d5f5e50099d2b3f4e5762ca222ba8e5b549ee
+ languageName: node
+ linkType: hard
+
+"micromark-extension-gfm-autolink-literal@npm:^2.0.0":
+ version: 2.1.0
+ resolution: "micromark-extension-gfm-autolink-literal@npm:2.1.0"
+ dependencies:
+ micromark-util-character: "npm:^2.0.0"
+ micromark-util-sanitize-uri: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ checksum: 10c0/84e6fbb84ea7c161dfa179665dc90d51116de4c28f3e958260c0423e5a745372b7dcbc87d3cde98213b532e6812f847eef5ae561c9397d7f7da1e59872ef3efe
+ languageName: node
+ linkType: hard
+
+"micromark-extension-gfm-footnote@npm:^2.0.0":
+ version: 2.1.0
+ resolution: "micromark-extension-gfm-footnote@npm:2.1.0"
+ dependencies:
+ devlop: "npm:^1.0.0"
+ micromark-core-commonmark: "npm:^2.0.0"
+ micromark-factory-space: "npm:^2.0.0"
+ micromark-util-character: "npm:^2.0.0"
+ micromark-util-normalize-identifier: "npm:^2.0.0"
+ micromark-util-sanitize-uri: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ checksum: 10c0/d172e4218968b7371b9321af5cde8c77423f73b233b2b0fcf3ff6fd6f61d2e0d52c49123a9b7910612478bf1f0d5e88c75a3990dd68f70f3933fe812b9f77edc
+ languageName: node
+ linkType: hard
+
+"micromark-extension-gfm-strikethrough@npm:^2.0.0":
+ version: 2.1.0
+ resolution: "micromark-extension-gfm-strikethrough@npm:2.1.0"
+ dependencies:
+ devlop: "npm:^1.0.0"
+ micromark-util-chunked: "npm:^2.0.0"
+ micromark-util-classify-character: "npm:^2.0.0"
+ micromark-util-resolve-all: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ checksum: 10c0/ef4f248b865bdda71303b494671b7487808a340b25552b11ca6814dff3fcfaab9be8d294643060bbdb50f79313e4a686ab18b99cbe4d3ee8a4170fcd134234fb
+ languageName: node
+ linkType: hard
+
+"micromark-extension-gfm-table@npm:^2.0.0":
+ version: 2.1.1
+ resolution: "micromark-extension-gfm-table@npm:2.1.1"
+ dependencies:
+ devlop: "npm:^1.0.0"
+ micromark-factory-space: "npm:^2.0.0"
+ micromark-util-character: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ checksum: 10c0/04bc00e19b435fa0add62cd029d8b7eb6137522f77832186b1d5ef34544a9bd030c9cf85e92ddfcc5c31f6f0a58a43d4b96dba4fc21316037c734630ee12c912
+ languageName: node
+ linkType: hard
+
+"micromark-extension-gfm-tagfilter@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "micromark-extension-gfm-tagfilter@npm:2.0.0"
+ dependencies:
+ micromark-util-types: "npm:^2.0.0"
+ checksum: 10c0/995558843fff137ae4e46aecb878d8a4691cdf23527dcf1e2f0157d66786be9f7bea0109c52a8ef70e68e3f930af811828ba912239438e31a9cfb9981f44d34d
+ languageName: node
+ linkType: hard
+
+"micromark-extension-gfm-task-list-item@npm:^2.0.0":
+ version: 2.1.0
+ resolution: "micromark-extension-gfm-task-list-item@npm:2.1.0"
+ dependencies:
+ devlop: "npm:^1.0.0"
+ micromark-factory-space: "npm:^2.0.0"
+ micromark-util-character: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ checksum: 10c0/78aa537d929e9309f076ba41e5edc99f78d6decd754b6734519ccbbfca8abd52e1c62df68d41a6ae64d2a3fc1646cea955893c79680b0b4385ced4c52296181f
+ languageName: node
+ linkType: hard
+
+"micromark-extension-gfm@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "micromark-extension-gfm@npm:3.0.0"
+ dependencies:
+ micromark-extension-gfm-autolink-literal: "npm:^2.0.0"
+ micromark-extension-gfm-footnote: "npm:^2.0.0"
+ micromark-extension-gfm-strikethrough: "npm:^2.0.0"
+ micromark-extension-gfm-table: "npm:^2.0.0"
+ micromark-extension-gfm-tagfilter: "npm:^2.0.0"
+ micromark-extension-gfm-task-list-item: "npm:^2.0.0"
+ micromark-util-combine-extensions: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ checksum: 10c0/970e28df6ebdd7c7249f52a0dda56e0566fbfa9ae56c8eeeb2445d77b6b89d44096880cd57a1c01e7821b1f4e31009109fbaca4e89731bff7b83b8519690e5d9
+ languageName: node
+ linkType: hard
+
+"micromark-factory-destination@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "micromark-factory-destination@npm:2.0.1"
+ dependencies:
+ micromark-util-character: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ checksum: 10c0/bbafcf869cee5bf511161354cb87d61c142592fbecea051000ff116068dc85216e6d48519d147890b9ea5d7e2864a6341c0c09d9948c203bff624a80a476023c
+ languageName: node
+ linkType: hard
+
+"micromark-factory-label@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "micromark-factory-label@npm:2.0.1"
+ dependencies:
+ devlop: "npm:^1.0.0"
+ micromark-util-character: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ checksum: 10c0/0137716b4ecb428114165505e94a2f18855c8bbea21b07a8b5ce514b32a595ed789d2b967125718fc44c4197ceaa48f6609d58807a68e778138d2e6b91b824e8
+ languageName: node
+ linkType: hard
+
+"micromark-factory-space@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "micromark-factory-space@npm:2.0.1"
+ dependencies:
+ micromark-util-character: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ checksum: 10c0/f9ed43f1c0652d8d898de0ac2be3f77f776fffe7dd96bdbba1e02d7ce33d3853c6ff5daa52568fc4fa32cdf3a62d86b85ead9b9189f7211e1d69ff2163c450fb
+ languageName: node
+ linkType: hard
+
+"micromark-factory-title@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "micromark-factory-title@npm:2.0.1"
+ dependencies:
+ micromark-factory-space: "npm:^2.0.0"
+ micromark-util-character: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ checksum: 10c0/e72fad8d6e88823514916890099a5af20b6a9178ccf78e7e5e05f4de99bb8797acb756257d7a3a57a53854cb0086bf8aab15b1a9e9db8982500dd2c9ff5948b6
+ languageName: node
+ linkType: hard
+
+"micromark-factory-whitespace@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "micromark-factory-whitespace@npm:2.0.1"
+ dependencies:
+ micromark-factory-space: "npm:^2.0.0"
+ micromark-util-character: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ checksum: 10c0/20a1ec58698f24b766510a309b23a10175034fcf1551eaa9da3adcbed3e00cd53d1ebe5f030cf873f76a1cec3c34eb8c50cc227be3344caa9ed25d56cf611224
+ languageName: node
+ linkType: hard
+
+"micromark-util-character@npm:^2.0.0":
+ version: 2.1.1
+ resolution: "micromark-util-character@npm:2.1.1"
+ dependencies:
+ micromark-util-symbol: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ checksum: 10c0/d3fe7a5e2c4060fc2a076f9ce699c82a2e87190a3946e1e5eea77f563869b504961f5668d9c9c014724db28ac32fa909070ea8b30c3a39bd0483cc6c04cc76a1
+ languageName: node
+ linkType: hard
+
+"micromark-util-chunked@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "micromark-util-chunked@npm:2.0.1"
+ dependencies:
+ micromark-util-symbol: "npm:^2.0.0"
+ checksum: 10c0/b68c0c16fe8106949537bdcfe1be9cf36c0ccd3bc54c4007003cb0984c3750b6cdd0fd77d03f269a3382b85b0de58bde4f6eedbe7ecdf7244759112289b1ab56
+ languageName: node
+ linkType: hard
+
+"micromark-util-classify-character@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "micromark-util-classify-character@npm:2.0.1"
+ dependencies:
+ micromark-util-character: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ checksum: 10c0/8a02e59304005c475c332f581697e92e8c585bcd45d5d225a66c1c1b14ab5a8062705188c2ccec33cc998d33502514121478b2091feddbc751887fc9c290ed08
+ languageName: node
+ linkType: hard
+
+"micromark-util-combine-extensions@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "micromark-util-combine-extensions@npm:2.0.1"
+ dependencies:
+ micromark-util-chunked: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ checksum: 10c0/f15e282af24c8372cbb10b9b0b3e2c0aa681fea0ca323a44d6bc537dc1d9382c819c3689f14eaa000118f5a163245358ce6276b2cda9a84439cdb221f5d86ae7
+ languageName: node
+ linkType: hard
+
+"micromark-util-decode-numeric-character-reference@npm:^2.0.0":
+ version: 2.0.2
+ resolution: "micromark-util-decode-numeric-character-reference@npm:2.0.2"
+ dependencies:
+ micromark-util-symbol: "npm:^2.0.0"
+ checksum: 10c0/9c8a9f2c790e5593ffe513901c3a110e9ec8882a08f466da014112a25e5059b51551ca0aeb7ff494657d86eceb2f02ee556c6558b8d66aadc61eae4a240da0df
+ languageName: node
+ linkType: hard
+
+"micromark-util-decode-string@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "micromark-util-decode-string@npm:2.0.1"
+ dependencies:
+ decode-named-character-reference: "npm:^1.0.0"
+ micromark-util-character: "npm:^2.0.0"
+ micromark-util-decode-numeric-character-reference: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ checksum: 10c0/f24d75b2e5310be6e7b6dee532e0d17d3bf46996841d6295f2a9c87a2046fff4ab603c52ab9d7a7a6430a8b787b1574ae895849c603d262d1b22eef71736b5cb
+ languageName: node
+ linkType: hard
+
+"micromark-util-encode@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "micromark-util-encode@npm:2.0.1"
+ checksum: 10c0/b2b29f901093845da8a1bf997ea8b7f5e061ffdba85070dfe14b0197c48fda64ffcf82bfe53c90cf9dc185e69eef8c5d41cae3ba918b96bc279326921b59008a
+ languageName: node
+ linkType: hard
+
+"micromark-util-html-tag-name@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "micromark-util-html-tag-name@npm:2.0.1"
+ checksum: 10c0/ae80444db786fde908e9295f19a27a4aa304171852c77414516418650097b8afb401961c9edb09d677b06e97e8370cfa65638dde8438ebd41d60c0a8678b85b9
+ languageName: node
+ linkType: hard
+
+"micromark-util-normalize-identifier@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "micromark-util-normalize-identifier@npm:2.0.1"
+ dependencies:
+ micromark-util-symbol: "npm:^2.0.0"
+ checksum: 10c0/5299265fa360769fc499a89f40142f10a9d4a5c3dd8e6eac8a8ef3c2e4a6570e4c009cf75ea46dce5ee31c01f25587bde2f4a5cc0a935584ae86dd857f2babbd
+ languageName: node
+ linkType: hard
+
+"micromark-util-resolve-all@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "micromark-util-resolve-all@npm:2.0.1"
+ dependencies:
+ micromark-util-types: "npm:^2.0.0"
+ checksum: 10c0/bb6ca28764696bb479dc44a2d5b5fe003e7177aeae1d6b0d43f24cc223bab90234092d9c3ce4a4d2b8df095ccfd820537b10eb96bb7044d635f385d65a4c984a
+ languageName: node
+ linkType: hard
+
+"micromark-util-sanitize-uri@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "micromark-util-sanitize-uri@npm:2.0.1"
+ dependencies:
+ micromark-util-character: "npm:^2.0.0"
+ micromark-util-encode: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ checksum: 10c0/60e92166e1870fd4f1961468c2651013ff760617342918e0e0c3c4e872433aa2e60c1e5a672bfe5d89dc98f742d6b33897585cf86ae002cda23e905a3c02527c
+ languageName: node
+ linkType: hard
+
+"micromark-util-subtokenize@npm:^2.0.0":
+ version: 2.1.0
+ resolution: "micromark-util-subtokenize@npm:2.1.0"
+ dependencies:
+ devlop: "npm:^1.0.0"
+ micromark-util-chunked: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ checksum: 10c0/bee69eece4393308e657c293ba80d92ebcb637e5f55e21dcf9c3fa732b91a8eda8ac248d76ff375e675175bfadeae4712e5158ef97eef1111789da1ce7ab5067
+ languageName: node
+ linkType: hard
+
+"micromark-util-symbol@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "micromark-util-symbol@npm:2.0.1"
+ checksum: 10c0/f2d1b207771e573232436618e78c5e46cd4b5c560dd4a6d63863d58018abbf49cb96ec69f7007471e51434c60de3c9268ef2bf46852f26ff4aacd10f9da16fe9
+ languageName: node
+ linkType: hard
+
+"micromark-util-types@npm:^2.0.0":
+ version: 2.0.2
+ resolution: "micromark-util-types@npm:2.0.2"
+ checksum: 10c0/c8c15b96c858db781c4393f55feec10004bf7df95487636c9a9f7209e51002a5cca6a047c5d2a5dc669ff92da20e57aaa881e81a268d9ccadb647f9dce305298
+ languageName: node
+ linkType: hard
+
+"micromark@npm:^4.0.0":
+ version: 4.0.2
+ resolution: "micromark@npm:4.0.2"
+ dependencies:
+ "@types/debug": "npm:^4.0.0"
+ debug: "npm:^4.0.0"
+ decode-named-character-reference: "npm:^1.0.0"
+ devlop: "npm:^1.0.0"
+ micromark-core-commonmark: "npm:^2.0.0"
+ micromark-factory-space: "npm:^2.0.0"
+ micromark-util-character: "npm:^2.0.0"
+ micromark-util-chunked: "npm:^2.0.0"
+ micromark-util-combine-extensions: "npm:^2.0.0"
+ micromark-util-decode-numeric-character-reference: "npm:^2.0.0"
+ micromark-util-encode: "npm:^2.0.0"
+ micromark-util-normalize-identifier: "npm:^2.0.0"
+ micromark-util-resolve-all: "npm:^2.0.0"
+ micromark-util-sanitize-uri: "npm:^2.0.0"
+ micromark-util-subtokenize: "npm:^2.0.0"
+ micromark-util-symbol: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ checksum: 10c0/07462287254219d6eda6eac8a3cebaff2994e0575499e7088027b825105e096e4f51e466b14b2a81b71933a3b6c48ee069049d87bc2c2127eee50d9cc69e8af6
+ languageName: node
+ linkType: hard
+
+"micromatch@npm:^4.0.4":
+ version: 4.0.8
+ resolution: "micromatch@npm:4.0.8"
+ dependencies:
+ braces: "npm:^3.0.3"
+ picomatch: "npm:^2.3.1"
+ checksum: 10c0/166fa6eb926b9553f32ef81f5f531d27b4ce7da60e5baf8c021d043b27a388fb95e46a8038d5045877881e673f8134122b59624d5cecbd16eb50a42e7a6b5ca8
+ languageName: node
+ linkType: hard
+
+"minimatch@npm:^10.2.2":
+ version: 10.2.4
+ resolution: "minimatch@npm:10.2.4"
+ dependencies:
+ brace-expansion: "npm:^5.0.2"
+ checksum: 10c0/35f3dfb7b99b51efd46afd378486889f590e7efb10e0f6a10ba6800428cf65c9a8dedb74427d0570b318d749b543dc4e85f06d46d2858bc8cac7e1eb49a95945
+ languageName: node
+ linkType: hard
+
+"minimatch@npm:^3.1.2, minimatch@npm:^3.1.5":
+ version: 3.1.5
+ resolution: "minimatch@npm:3.1.5"
+ dependencies:
+ brace-expansion: "npm:^1.1.7"
+ checksum: 10c0/2ecbdc0d33f07bddb0315a8b5afbcb761307a8778b48f0b312418ccbced99f104a2d17d8aca7573433c70e8ccd1c56823a441897a45e384ea76ef401a26ace70
+ languageName: node
+ linkType: hard
+
+"minimist@npm:^1.2.0, minimist@npm:^1.2.6":
+ version: 1.2.8
+ resolution: "minimist@npm:1.2.8"
+ checksum: 10c0/19d3fcdca050087b84c2029841a093691a91259a47def2f18222f41e7645a0b7c44ef4b40e88a1e58a40c84d2ef0ee6047c55594d298146d0eb3f6b737c20ce6
+ languageName: node
+ linkType: hard
+
+"minipass-collect@npm:^2.0.1":
+ version: 2.0.1
+ resolution: "minipass-collect@npm:2.0.1"
+ dependencies:
+ minipass: "npm:^7.0.3"
+ checksum: 10c0/5167e73f62bb74cc5019594709c77e6a742051a647fe9499abf03c71dca75515b7959d67a764bdc4f8b361cf897fbf25e2d9869ee039203ed45240f48b9aa06e
+ languageName: node
+ linkType: hard
+
+"minipass-fetch@npm:^5.0.0":
+ version: 5.0.2
+ resolution: "minipass-fetch@npm:5.0.2"
+ dependencies:
+ iconv-lite: "npm:^0.7.2"
+ minipass: "npm:^7.0.3"
+ minipass-sized: "npm:^2.0.0"
+ minizlib: "npm:^3.0.1"
+ dependenciesMeta:
+ iconv-lite:
+ optional: true
+ checksum: 10c0/ce4ab9f21cfabaead2097d95dd33f485af8072fbc6b19611bce694965393453a1639d641c2bcf1c48f2ea7d41ea7fab8278373f1d0bee4e63b0a5b2cdd0ef649
+ languageName: node
+ linkType: hard
+
+"minipass-flush@npm:^1.0.5":
+ version: 1.0.5
+ resolution: "minipass-flush@npm:1.0.5"
+ dependencies:
+ minipass: "npm:^3.0.0"
+ checksum: 10c0/2a51b63feb799d2bb34669205eee7c0eaf9dce01883261a5b77410c9408aa447e478efd191b4de6fc1101e796ff5892f8443ef20d9544385819093dbb32d36bd
+ languageName: node
+ linkType: hard
+
+"minipass-pipeline@npm:^1.2.4":
+ version: 1.2.4
+ resolution: "minipass-pipeline@npm:1.2.4"
+ dependencies:
+ minipass: "npm:^3.0.0"
+ checksum: 10c0/cbda57cea20b140b797505dc2cac71581a70b3247b84480c1fed5ca5ba46c25ecc25f68bfc9e6dcb1a6e9017dab5c7ada5eab73ad4f0a49d84e35093e0c643f2
+ languageName: node
+ linkType: hard
+
+"minipass-sized@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "minipass-sized@npm:2.0.0"
+ dependencies:
+ minipass: "npm:^7.1.2"
+ checksum: 10c0/f9201696a6f6d68610d04c9c83e3d2e5cb9c026aae1c8cbf7e17f386105cb79c1bb088dbc21bf0b1eb4f3fb5df384fd1e7aa3bf1f33868c416ae8c8a92679db8
+ languageName: node
+ linkType: hard
+
+"minipass@npm:^3.0.0":
+ version: 3.3.6
+ resolution: "minipass@npm:3.3.6"
+ dependencies:
+ yallist: "npm:^4.0.0"
+ checksum: 10c0/a114746943afa1dbbca8249e706d1d38b85ed1298b530f5808ce51f8e9e941962e2a5ad2e00eae7dd21d8a4aae6586a66d4216d1a259385e9d0358f0c1eba16c
+ languageName: node
+ linkType: hard
+
+"minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4, minipass@npm:^7.1.2, minipass@npm:^7.1.3":
+ version: 7.1.3
+ resolution: "minipass@npm:7.1.3"
+ checksum: 10c0/539da88daca16533211ea5a9ee98dc62ff5742f531f54640dd34429e621955e91cc280a91a776026264b7f9f6735947629f920944e9c1558369e8bf22eb33fbb
+ languageName: node
+ linkType: hard
+
+"minizlib@npm:^3.0.1, minizlib@npm:^3.1.0":
+ version: 3.1.0
+ resolution: "minizlib@npm:3.1.0"
+ dependencies:
+ minipass: "npm:^7.1.2"
+ checksum: 10c0/5aad75ab0090b8266069c9aabe582c021ae53eb33c6c691054a13a45db3b4f91a7fb1bd79151e6b4e9e9a86727b522527c0a06ec7d45206b745d54cd3097bcec
+ languageName: node
+ linkType: hard
+
+"ms@npm:^2.1.1, ms@npm:^2.1.3":
+ version: 2.1.3
+ resolution: "ms@npm:2.1.3"
+ checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48
+ languageName: node
+ linkType: hard
+
+"nanoid@npm:^3.3.11, nanoid@npm:^3.3.6":
+ version: 3.3.11
+ resolution: "nanoid@npm:3.3.11"
+ bin:
+ nanoid: bin/nanoid.cjs
+ checksum: 10c0/40e7f70b3d15f725ca072dfc4f74e81fcf1fbb02e491cf58ac0c79093adc9b0a73b152bcde57df4b79cd097e13023d7504acb38404a4da7bc1cd8e887b82fe0b
+ languageName: node
+ linkType: hard
+
+"nanostores@npm:^1.0.1":
+ version: 1.2.0
+ resolution: "nanostores@npm:1.2.0"
+ checksum: 10c0/282ca01dacc3679358268fcd3ef6b9eb3ad76fd8b0f476789573b3215dd8af7a83191b29819c4d489c20891eb47493c67a49a05aca938c3ad215c14452179be5
+ languageName: node
+ linkType: hard
+
+"napi-postinstall@npm:^0.3.0":
+ version: 0.3.4
+ resolution: "napi-postinstall@npm:0.3.4"
+ bin:
+ napi-postinstall: lib/cli.js
+ checksum: 10c0/b33d64150828bdade3a5d07368a8b30da22ee393f8dd8432f1b9e5486867be21c84ec443dd875dd3ef3c7401a079a7ab7e2aa9d3538a889abbcd96495d5104fe
+ languageName: node
+ linkType: hard
+
+"natural-compare@npm:^1.4.0":
+ version: 1.4.0
+ resolution: "natural-compare@npm:1.4.0"
+ checksum: 10c0/f5f9a7974bfb28a91afafa254b197f0f22c684d4a1731763dda960d2c8e375b36c7d690e0d9dc8fba774c537af14a7e979129bca23d88d052fbeb9466955e447
+ languageName: node
+ linkType: hard
+
+"negotiator@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "negotiator@npm:1.0.0"
+ checksum: 10c0/4c559dd52669ea48e1914f9d634227c561221dd54734070791f999c52ed0ff36e437b2e07d5c1f6e32909fc625fe46491c16e4a8f0572567d4dd15c3a4fda04b
+ languageName: node
+ linkType: hard
+
+"next@npm:^15.3.1":
+ version: 15.5.13
+ resolution: "next@npm:15.5.13"
+ dependencies:
+ "@next/env": "npm:15.5.13"
+ "@next/swc-darwin-arm64": "npm:15.5.13"
+ "@next/swc-darwin-x64": "npm:15.5.13"
+ "@next/swc-linux-arm64-gnu": "npm:15.5.13"
+ "@next/swc-linux-arm64-musl": "npm:15.5.13"
+ "@next/swc-linux-x64-gnu": "npm:15.5.13"
+ "@next/swc-linux-x64-musl": "npm:15.5.13"
+ "@next/swc-win32-arm64-msvc": "npm:15.5.13"
+ "@next/swc-win32-x64-msvc": "npm:15.5.13"
+ "@swc/helpers": "npm:0.5.15"
+ caniuse-lite: "npm:^1.0.30001579"
+ postcss: "npm:8.4.31"
+ sharp: "npm:^0.34.3"
+ styled-jsx: "npm:5.1.6"
+ peerDependencies:
+ "@opentelemetry/api": ^1.1.0
+ "@playwright/test": ^1.51.1
+ babel-plugin-react-compiler: "*"
+ react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0
+ react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0
+ sass: ^1.3.0
+ dependenciesMeta:
+ "@next/swc-darwin-arm64":
+ optional: true
+ "@next/swc-darwin-x64":
+ optional: true
+ "@next/swc-linux-arm64-gnu":
+ optional: true
+ "@next/swc-linux-arm64-musl":
+ optional: true
+ "@next/swc-linux-x64-gnu":
+ optional: true
+ "@next/swc-linux-x64-musl":
+ optional: true
+ "@next/swc-win32-arm64-msvc":
+ optional: true
+ "@next/swc-win32-x64-msvc":
+ optional: true
+ sharp:
+ optional: true
+ peerDependenciesMeta:
+ "@opentelemetry/api":
+ optional: true
+ "@playwright/test":
+ optional: true
+ babel-plugin-react-compiler:
+ optional: true
+ sass:
+ optional: true
+ bin:
+ next: dist/bin/next
+ checksum: 10c0/67b8c31e0bda950de54d37de3ecc7c740207f16cce32a052845e5bd9ec9be1634d48ad782981d114fa930c347b21031116ef0d5dca2abe71e0b67812c3f41163
+ languageName: node
+ linkType: hard
+
+"node-exports-info@npm:^1.6.0":
+ version: 1.6.0
+ resolution: "node-exports-info@npm:1.6.0"
+ dependencies:
+ array.prototype.flatmap: "npm:^1.3.3"
+ es-errors: "npm:^1.3.0"
+ object.entries: "npm:^1.1.9"
+ semver: "npm:^6.3.1"
+ checksum: 10c0/3613f21c60b047e66f168d3499a6be0060d89fb01ddceaa7032c2fb318aff12e4b9b111449c1a9aeb3b848bfdc1d4b6bc8fab327af692319597d21a1e7063692
+ languageName: node
+ linkType: hard
+
+"node-gyp@npm:latest":
+ version: 12.2.0
+ resolution: "node-gyp@npm:12.2.0"
+ dependencies:
+ env-paths: "npm:^2.2.0"
+ exponential-backoff: "npm:^3.1.1"
+ graceful-fs: "npm:^4.2.6"
+ make-fetch-happen: "npm:^15.0.0"
+ nopt: "npm:^9.0.0"
+ proc-log: "npm:^6.0.0"
+ semver: "npm:^7.3.5"
+ tar: "npm:^7.5.4"
+ tinyglobby: "npm:^0.2.12"
+ which: "npm:^6.0.0"
+ bin:
+ node-gyp: bin/node-gyp.js
+ checksum: 10c0/3ed046746a5a7d90950cd8b0547332b06598443f31fe213ef4332a7174c7b7d259e1704835feda79b87d3f02e59d7791842aac60642ede4396ab25fdf0f8f759
+ languageName: node
+ linkType: hard
+
+"node-releases@npm:^2.0.27":
+ version: 2.0.36
+ resolution: "node-releases@npm:2.0.36"
+ checksum: 10c0/85d8d7f4b6248c8372831cbcc3829ce634cb2b01dbd85e55705cefc8a9eda4ce8121bd218b9629cf2579aef8a360541bad409f3925a35675c825b9471a49d7e9
+ languageName: node
+ linkType: hard
+
+"nopt@npm:^9.0.0":
+ version: 9.0.0
+ resolution: "nopt@npm:9.0.0"
+ dependencies:
+ abbrev: "npm:^4.0.0"
+ bin:
+ nopt: bin/nopt.js
+ checksum: 10c0/1822eb6f9b020ef6f7a7516d7b64a8036e09666ea55ac40416c36e4b2b343122c3cff0e2f085675f53de1d2db99a2a89a60ccea1d120bcd6a5347bf6ceb4a7fd
+ languageName: node
+ linkType: hard
+
+"object-assign@npm:^4.1.1":
+ version: 4.1.1
+ resolution: "object-assign@npm:4.1.1"
+ checksum: 10c0/1f4df9945120325d041ccf7b86f31e8bcc14e73d29171e37a7903050e96b81323784ec59f93f102ec635bcf6fa8034ba3ea0a8c7e69fa202b87ae3b6cec5a414
+ languageName: node
+ linkType: hard
+
+"object-inspect@npm:^1.13.3, object-inspect@npm:^1.13.4":
+ version: 1.13.4
+ resolution: "object-inspect@npm:1.13.4"
+ checksum: 10c0/d7f8711e803b96ea3191c745d6f8056ce1f2496e530e6a19a0e92d89b0fa3c76d910c31f0aa270432db6bd3b2f85500a376a83aaba849a8d518c8845b3211692
+ languageName: node
+ linkType: hard
+
+"object-keys@npm:^1.1.1":
+ version: 1.1.1
+ resolution: "object-keys@npm:1.1.1"
+ checksum: 10c0/b11f7ccdbc6d406d1f186cdadb9d54738e347b2692a14439ca5ac70c225fa6db46db809711b78589866d47b25fc3e8dee0b4c722ac751e11180f9380e3d8601d
+ languageName: node
+ linkType: hard
+
+"object.assign@npm:^4.1.4, object.assign@npm:^4.1.7":
+ version: 4.1.7
+ resolution: "object.assign@npm:4.1.7"
+ dependencies:
+ call-bind: "npm:^1.0.8"
+ call-bound: "npm:^1.0.3"
+ define-properties: "npm:^1.2.1"
+ es-object-atoms: "npm:^1.0.0"
+ has-symbols: "npm:^1.1.0"
+ object-keys: "npm:^1.1.1"
+ checksum: 10c0/3b2732bd860567ea2579d1567525168de925a8d852638612846bd8082b3a1602b7b89b67b09913cbb5b9bd6e95923b2ae73580baa9d99cb4e990564e8cbf5ddc
+ languageName: node
+ linkType: hard
+
+"object.entries@npm:^1.1.9":
+ version: 1.1.9
+ resolution: "object.entries@npm:1.1.9"
+ dependencies:
+ call-bind: "npm:^1.0.8"
+ call-bound: "npm:^1.0.4"
+ define-properties: "npm:^1.2.1"
+ es-object-atoms: "npm:^1.1.1"
+ checksum: 10c0/d4b8c1e586650407da03370845f029aa14076caca4e4d4afadbc69cfb5b78035fd3ee7be417141abdb0258fa142e59b11923b4c44d8b1255b28f5ffcc50da7db
+ languageName: node
+ linkType: hard
+
+"object.fromentries@npm:^2.0.8":
+ version: 2.0.8
+ resolution: "object.fromentries@npm:2.0.8"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.23.2"
+ es-object-atoms: "npm:^1.0.0"
+ checksum: 10c0/cd4327e6c3369cfa805deb4cbbe919bfb7d3aeebf0bcaba291bb568ea7169f8f8cdbcabe2f00b40db0c20cd20f08e11b5f3a5a36fb7dd3fe04850c50db3bf83b
+ languageName: node
+ linkType: hard
+
+"object.groupby@npm:^1.0.3":
+ version: 1.0.3
+ resolution: "object.groupby@npm:1.0.3"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.23.2"
+ checksum: 10c0/60d0455c85c736fbfeda0217d1a77525956f76f7b2495edeca9e9bbf8168a45783199e77b894d30638837c654d0cc410e0e02cbfcf445bc8de71c3da1ede6a9c
+ languageName: node
+ linkType: hard
+
+"object.values@npm:^1.1.6, object.values@npm:^1.2.1":
+ version: 1.2.1
+ resolution: "object.values@npm:1.2.1"
+ dependencies:
+ call-bind: "npm:^1.0.8"
+ call-bound: "npm:^1.0.3"
+ define-properties: "npm:^1.2.1"
+ es-object-atoms: "npm:^1.0.0"
+ checksum: 10c0/3c47814fdc64842ae3d5a74bc9d06bdd8d21563c04d9939bf6716a9c00596a4ebc342552f8934013d1ec991c74e3671b26710a0c51815f0b603795605ab6b2c9
+ languageName: node
+ linkType: hard
+
+"optionator@npm:^0.9.3":
+ version: 0.9.4
+ resolution: "optionator@npm:0.9.4"
+ dependencies:
+ deep-is: "npm:^0.1.3"
+ fast-levenshtein: "npm:^2.0.6"
+ levn: "npm:^0.4.1"
+ prelude-ls: "npm:^1.2.1"
+ type-check: "npm:^0.4.0"
+ word-wrap: "npm:^1.2.5"
+ checksum: 10c0/4afb687a059ee65b61df74dfe87d8d6815cd6883cb8b3d5883a910df72d0f5d029821f37025e4bccf4048873dbdb09acc6d303d27b8f76b1a80dd5a7d5334675
+ languageName: node
+ linkType: hard
+
+"own-keys@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "own-keys@npm:1.0.1"
+ dependencies:
+ get-intrinsic: "npm:^1.2.6"
+ object-keys: "npm:^1.1.1"
+ safe-push-apply: "npm:^1.0.0"
+ checksum: 10c0/6dfeb3455bff92ec3f16a982d4e3e65676345f6902d9f5ded1d8265a6318d0200ce461956d6d1c70053c7fe9f9fe65e552faac03f8140d37ef0fdd108e67013a
+ languageName: node
+ linkType: hard
+
+"p-limit@npm:^3.0.2":
+ version: 3.1.0
+ resolution: "p-limit@npm:3.1.0"
+ dependencies:
+ yocto-queue: "npm:^0.1.0"
+ checksum: 10c0/9db675949dbdc9c3763c89e748d0ef8bdad0afbb24d49ceaf4c46c02c77d30db4e0652ed36d0a0a7a95154335fab810d95c86153105bb73b3a90448e2bb14e1a
+ languageName: node
+ linkType: hard
+
+"p-locate@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "p-locate@npm:5.0.0"
+ dependencies:
+ p-limit: "npm:^3.0.2"
+ checksum: 10c0/2290d627ab7903b8b70d11d384fee714b797f6040d9278932754a6860845c4d3190603a0772a663c8cb5a7b21d1b16acb3a6487ebcafa9773094edc3dfe6009a
+ languageName: node
+ linkType: hard
+
+"p-map@npm:^7.0.2":
+ version: 7.0.4
+ resolution: "p-map@npm:7.0.4"
+ checksum: 10c0/a5030935d3cb2919d7e89454d1ce82141e6f9955413658b8c9403cfe379283770ed3048146b44cde168aa9e8c716505f196d5689db0ae3ce9a71521a2fef3abd
+ languageName: node
+ linkType: hard
+
+"parent-module@npm:^1.0.0":
+ version: 1.0.1
+ resolution: "parent-module@npm:1.0.1"
+ dependencies:
+ callsites: "npm:^3.0.0"
+ checksum: 10c0/c63d6e80000d4babd11978e0d3fee386ca7752a02b035fd2435960ffaa7219dc42146f07069fb65e6e8bf1caef89daf9af7535a39bddf354d78bf50d8294f556
+ languageName: node
+ linkType: hard
+
+"parse-entities@npm:^4.0.0":
+ version: 4.0.2
+ resolution: "parse-entities@npm:4.0.2"
+ dependencies:
+ "@types/unist": "npm:^2.0.0"
+ character-entities-legacy: "npm:^3.0.0"
+ character-reference-invalid: "npm:^2.0.0"
+ decode-named-character-reference: "npm:^1.0.0"
+ is-alphanumerical: "npm:^2.0.0"
+ is-decimal: "npm:^2.0.0"
+ is-hexadecimal: "npm:^2.0.0"
+ checksum: 10c0/a13906b1151750b78ed83d386294066daf5fb559e08c5af9591b2d98cc209123103016a01df776f65f8219ad26652d6d6b210d0974d452049cddfc53a8916c34
+ languageName: node
+ linkType: hard
+
+"path-exists@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "path-exists@npm:4.0.0"
+ checksum: 10c0/8c0bd3f5238188197dc78dced15207a4716c51cc4e3624c44fc97acf69558f5ebb9a2afff486fe1b4ee148e0c133e96c5e11a9aa5c48a3006e3467da070e5e1b
+ languageName: node
+ linkType: hard
+
+"path-key@npm:^3.1.0":
+ version: 3.1.1
+ resolution: "path-key@npm:3.1.1"
+ checksum: 10c0/748c43efd5a569c039d7a00a03b58eecd1d75f3999f5a28303d75f521288df4823bc057d8784eb72358b2895a05f29a070bc9f1f17d28226cc4e62494cc58c4c
+ languageName: node
+ linkType: hard
+
+"path-parse@npm:^1.0.7":
+ version: 1.0.7
+ resolution: "path-parse@npm:1.0.7"
+ checksum: 10c0/11ce261f9d294cc7a58d6a574b7f1b935842355ec66fba3c3fd79e0f036462eaf07d0aa95bb74ff432f9afef97ce1926c720988c6a7451d8a584930ae7de86e1
+ languageName: node
+ linkType: hard
+
+"path-scurry@npm:^2.0.2":
+ version: 2.0.2
+ resolution: "path-scurry@npm:2.0.2"
+ dependencies:
+ lru-cache: "npm:^11.0.0"
+ minipass: "npm:^7.1.2"
+ checksum: 10c0/b35ad37cf6557a87fd057121ce2be7695380c9138d93e87ae928609da259ea0a170fac6f3ef1eb3ece8a068e8b7f2f3adf5bb2374cf4d4a57fe484954fcc9482
+ languageName: node
+ linkType: hard
+
+"pathe@npm:^2.0.3":
+ version: 2.0.3
+ resolution: "pathe@npm:2.0.3"
+ checksum: 10c0/c118dc5a8b5c4166011b2b70608762e260085180bb9e33e80a50dcdb1e78c010b1624f4280c492c92b05fc276715a4c357d1f9edc570f8f1b3d90b6839ebaca1
+ languageName: node
+ linkType: hard
+
+"pathval@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "pathval@npm:2.0.1"
+ checksum: 10c0/460f4709479fbf2c45903a65655fc8f0a5f6d808f989173aeef5fdea4ff4f303dc13f7870303999add60ec49d4c14733895c0a869392e9866f1091fa64fd7581
+ languageName: node
+ linkType: hard
+
+"picocolors@npm:^1.0.0, picocolors@npm:^1.1.1":
+ version: 1.1.1
+ resolution: "picocolors@npm:1.1.1"
+ checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58
+ languageName: node
+ linkType: hard
+
+"picomatch@npm:^2.3.1":
+ version: 2.3.1
+ resolution: "picomatch@npm:2.3.1"
+ checksum: 10c0/26c02b8d06f03206fc2ab8d16f19960f2ff9e81a658f831ecb656d8f17d9edc799e8364b1f4a7873e89d9702dff96204be0fa26fe4181f6843f040f819dac4be
+ languageName: node
+ linkType: hard
+
+"picomatch@npm:^4.0.2, picomatch@npm:^4.0.3":
+ version: 4.0.3
+ resolution: "picomatch@npm:4.0.3"
+ checksum: 10c0/9582c951e95eebee5434f59e426cddd228a7b97a0161a375aed4be244bd3fe8e3a31b846808ea14ef2c8a2527a6eeab7b3946a67d5979e81694654f939473ae2
+ languageName: node
+ linkType: hard
+
+"possible-typed-array-names@npm:^1.0.0":
+ version: 1.1.0
+ resolution: "possible-typed-array-names@npm:1.1.0"
+ checksum: 10c0/c810983414142071da1d644662ce4caebce890203eb2bc7bf119f37f3fe5796226e117e6cca146b521921fa6531072674174a3325066ac66fce089a53e1e5196
+ languageName: node
+ linkType: hard
+
+"postcss@npm:8.4.31":
+ version: 8.4.31
+ resolution: "postcss@npm:8.4.31"
+ dependencies:
+ nanoid: "npm:^3.3.6"
+ picocolors: "npm:^1.0.0"
+ source-map-js: "npm:^1.0.2"
+ checksum: 10c0/748b82e6e5fc34034dcf2ae88ea3d11fd09f69b6c50ecdd3b4a875cfc7cdca435c958b211e2cb52355422ab6fccb7d8f2f2923161d7a1b281029e4a913d59acf
+ languageName: node
+ linkType: hard
+
+"postcss@npm:^8.5.6":
+ version: 8.5.8
+ resolution: "postcss@npm:8.5.8"
+ dependencies:
+ nanoid: "npm:^3.3.11"
+ picocolors: "npm:^1.1.1"
+ source-map-js: "npm:^1.2.1"
+ checksum: 10c0/dd918f7127ee7c60a0295bae2e72b3787892296e1d1c3c564d7a2a00c68d8df83cadc3178491259daa19ccc54804fb71ed8c937c6787e08d8bd4bedf8d17044c
+ languageName: node
+ linkType: hard
+
+"prdforge-frontend@workspace:.":
+ version: 0.0.0-use.local
+ resolution: "prdforge-frontend@workspace:."
+ dependencies:
+ "@eslint/eslintrc": "npm:^3.3.5"
+ "@prisma/client": "npm:5.22.0"
+ "@radix-ui/react-avatar": "npm:^1.1.11"
+ "@radix-ui/react-dialog": "npm:^1.1.15"
+ "@radix-ui/react-dropdown-menu": "npm:^2.1.16"
+ "@radix-ui/react-select": "npm:^2.2.6"
+ "@radix-ui/react-slot": "npm:^1.2.4"
+ "@radix-ui/react-tabs": "npm:^1.1.13"
+ "@radix-ui/react-tooltip": "npm:^1.2.8"
+ "@tailwindcss/postcss": "npm:^4.1.3"
+ "@types/bcryptjs": "npm:^3.0.0"
+ "@types/http-proxy": "npm:^1.17.17"
+ "@types/node": "npm:^22.13.10"
+ "@types/react": "npm:^19.1.0"
+ "@types/react-dom": "npm:^19.1.0"
+ "@vitejs/plugin-react": "npm:^4.3.4"
+ bcryptjs: "npm:^3.0.3"
+ better-auth: "npm:1.4.7"
+ class-variance-authority: "npm:^0.7.1"
+ clsx: "npm:^2.1.1"
+ eslint: "npm:^9.0.0"
+ eslint-config-next: "npm:^15.3.1"
+ http-proxy: "npm:^1.18.1"
+ lucide-react: "npm:^0.475.0"
+ next: "npm:^15.3.1"
+ prisma: "npm:5.22.0"
+ react: "npm:^19.1.0"
+ react-dom: "npm:^19.1.0"
+ react-markdown: "npm:^10.1.0"
+ recharts: "npm:^3.8.0"
+ rehype-highlight: "npm:^7.0.2"
+ remark-gfm: "npm:^4.0.1"
+ sonner: "npm:^2.0.7"
+ tailwind-merge: "npm:^3.0.2"
+ tailwindcss: "npm:^4.1.3"
+ typescript: "npm:^5.8.2"
+ vitest: "npm:^3.1.1"
+ languageName: unknown
+ linkType: soft
+
+"prelude-ls@npm:^1.2.1":
+ version: 1.2.1
+ resolution: "prelude-ls@npm:1.2.1"
+ checksum: 10c0/b00d617431e7886c520a6f498a2e14c75ec58f6d93ba48c3b639cf241b54232d90daa05d83a9e9b9fef6baa63cb7e1e4602c2372fea5bc169668401eb127d0cd
+ languageName: node
+ linkType: hard
+
+"prisma@npm:5.22.0":
+ version: 5.22.0
+ resolution: "prisma@npm:5.22.0"
+ dependencies:
+ "@prisma/engines": "npm:5.22.0"
+ fsevents: "npm:2.3.3"
+ dependenciesMeta:
+ fsevents:
+ optional: true
+ bin:
+ prisma: build/index.js
+ checksum: 10c0/63d1fe828394d1a1fabc0d29245ae35be53c1bdb26da4dbcfaf17fba3733c1c120b72f28b548dba47b2b80ff7fad670717be1316c1ea4bb12ebe1937415a1ddb
+ languageName: node
+ linkType: hard
+
+"proc-log@npm:^6.0.0":
+ version: 6.1.0
+ resolution: "proc-log@npm:6.1.0"
+ checksum: 10c0/4f178d4062733ead9d71a9b1ab24ebcecdfe2250916a5b1555f04fe2eda972a0ec76fbaa8df1ad9c02707add6749219d118a4fc46dc56bdfe4dde4b47d80bb82
+ languageName: node
+ linkType: hard
+
+"prop-types@npm:^15.8.1":
+ version: 15.8.1
+ resolution: "prop-types@npm:15.8.1"
+ dependencies:
+ loose-envify: "npm:^1.4.0"
+ object-assign: "npm:^4.1.1"
+ react-is: "npm:^16.13.1"
+ checksum: 10c0/59ece7ca2fb9838031d73a48d4becb9a7cc1ed10e610517c7d8f19a1e02fa47f7c27d557d8a5702bec3cfeccddc853579832b43f449e54635803f277b1c78077
+ languageName: node
+ linkType: hard
+
+"property-information@npm:^7.0.0":
+ version: 7.1.0
+ resolution: "property-information@npm:7.1.0"
+ checksum: 10c0/e0fe22cff26103260ad0e82959229106563fa115a54c4d6c183f49d88054e489cc9f23452d3ad584179dc13a8b7b37411a5df873746b5e4086c865874bfa968e
+ languageName: node
+ linkType: hard
+
+"punycode@npm:^2.1.0":
+ version: 2.3.1
+ resolution: "punycode@npm:2.3.1"
+ checksum: 10c0/14f76a8206bc3464f794fb2e3d3cc665ae416c01893ad7a02b23766eb07159144ee612ad67af5e84fa4479ccfe67678c4feb126b0485651b302babf66f04f9e9
+ languageName: node
+ linkType: hard
+
+"queue-microtask@npm:^1.2.2":
+ version: 1.2.3
+ resolution: "queue-microtask@npm:1.2.3"
+ checksum: 10c0/900a93d3cdae3acd7d16f642c29a642aea32c2026446151f0778c62ac089d4b8e6c986811076e1ae180a694cedf077d453a11b58ff0a865629a4f82ab558e102
+ languageName: node
+ linkType: hard
+
+"react-dom@npm:^19.1.0":
+ version: 19.2.4
+ resolution: "react-dom@npm:19.2.4"
+ dependencies:
+ scheduler: "npm:^0.27.0"
+ peerDependencies:
+ react: ^19.2.4
+ checksum: 10c0/f0c63f1794dedb154136d4d0f59af00b41907f4859571c155940296808f4b94bf9c0c20633db75b5b2112ec13d8d7dd4f9bf57362ed48782f317b11d05a44f35
+ languageName: node
+ linkType: hard
+
+"react-is@npm:^16.13.1":
+ version: 16.13.1
+ resolution: "react-is@npm:16.13.1"
+ checksum: 10c0/33977da7a5f1a287936a0c85639fec6ca74f4f15ef1e59a6bc20338fc73dc69555381e211f7a3529b8150a1f71e4225525b41b60b52965bda53ce7d47377ada1
+ languageName: node
+ linkType: hard
+
+"react-markdown@npm:^10.1.0":
+ version: 10.1.0
+ resolution: "react-markdown@npm:10.1.0"
+ dependencies:
+ "@types/hast": "npm:^3.0.0"
+ "@types/mdast": "npm:^4.0.0"
+ devlop: "npm:^1.0.0"
+ hast-util-to-jsx-runtime: "npm:^2.0.0"
+ html-url-attributes: "npm:^3.0.0"
+ mdast-util-to-hast: "npm:^13.0.0"
+ remark-parse: "npm:^11.0.0"
+ remark-rehype: "npm:^11.0.0"
+ unified: "npm:^11.0.0"
+ unist-util-visit: "npm:^5.0.0"
+ vfile: "npm:^6.0.0"
+ peerDependencies:
+ "@types/react": ">=18"
+ react: ">=18"
+ checksum: 10c0/4a5dc7d15ca6d05e9ee95318c1904f83b111a76f7588c44f50f1d54d4c97193b84e4f64c4b592057c989228238a2590306cedd0c4d398e75da49262b2b5ae1bf
+ languageName: node
+ linkType: hard
+
+"react-redux@npm:8.x.x || 9.x.x":
+ version: 9.2.0
+ resolution: "react-redux@npm:9.2.0"
+ dependencies:
+ "@types/use-sync-external-store": "npm:^0.0.6"
+ use-sync-external-store: "npm:^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
+ checksum: 10c0/00d485f9d9219ca1507b4d30dde5f6ff8fb68ba642458f742e0ec83af052f89e65cd668249b99299e1053cc6ad3d2d8ac6cb89e2f70d2ac5585ae0d7fa0ef259
+ languageName: node
+ linkType: hard
+
+"react-refresh@npm:^0.17.0":
+ version: 0.17.0
+ resolution: "react-refresh@npm:0.17.0"
+ checksum: 10c0/002cba940384c9930008c0bce26cac97a9d5682bc623112c2268ba0c155127d9c178a9a5cc2212d560088d60dfd503edd808669a25f9b377f316a32361d0b23c
+ languageName: node
+ linkType: hard
+
+"react-remove-scroll-bar@npm:^2.3.7":
+ version: 2.3.8
+ resolution: "react-remove-scroll-bar@npm:2.3.8"
+ dependencies:
+ react-style-singleton: "npm:^2.2.2"
+ tslib: "npm:^2.0.0"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/9a0675c66cbb52c325bdbfaed80987a829c4504cefd8ff2dd3b6b3afc9a1500b8ec57b212e92c1fb654396d07bbe18830a8146fe77677d2a29ce40b5e1f78654
+ languageName: node
+ linkType: hard
+
+"react-remove-scroll@npm:^2.6.3":
+ version: 2.7.2
+ resolution: "react-remove-scroll@npm:2.7.2"
+ dependencies:
+ react-remove-scroll-bar: "npm:^2.3.7"
+ react-style-singleton: "npm:^2.2.3"
+ tslib: "npm:^2.1.0"
+ use-callback-ref: "npm:^1.3.3"
+ use-sidecar: "npm:^1.1.3"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/b5f3315bead75e72853f492c0b51ba8fb4fa09a4534d7fc42d6fcd59ca3e047cf213279ffc1e35b337e314ef5a04cb2b12544c85e0078802271731c27c09e5aa
+ languageName: node
+ linkType: hard
+
+"react-style-singleton@npm:^2.2.2, react-style-singleton@npm:^2.2.3":
+ version: 2.2.3
+ resolution: "react-style-singleton@npm:2.2.3"
+ dependencies:
+ get-nonce: "npm:^1.0.0"
+ tslib: "npm:^2.0.0"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/841938ff16d16a6b76895f4cb2e1fea957e5fe3b30febbf03a54892dae1c9153f2383e231dea0b3ba41192ad2f2849448fa859caccd288943bce32639e971bee
+ languageName: node
+ linkType: hard
+
+"react@npm:^19.1.0":
+ version: 19.2.4
+ resolution: "react@npm:19.2.4"
+ checksum: 10c0/cd2c9ff67a720799cc3b38a516009986f7fc4cb8d3e15716c6211cf098d1357ee3e348ab05ad0600042bbb0fd888530ba92e329198c92eafa0994f5213396596
+ languageName: node
+ linkType: hard
+
+"recharts@npm:^3.8.0":
+ version: 3.8.0
+ resolution: "recharts@npm:3.8.0"
+ dependencies:
+ "@reduxjs/toolkit": "npm:^1.9.0 || 2.x.x"
+ clsx: "npm:^2.1.1"
+ decimal.js-light: "npm:^2.5.1"
+ es-toolkit: "npm:^1.39.3"
+ eventemitter3: "npm:^5.0.1"
+ immer: "npm:^10.1.1"
+ react-redux: "npm:8.x.x || 9.x.x"
+ reselect: "npm:5.1.1"
+ tiny-invariant: "npm:^1.3.3"
+ use-sync-external-store: "npm:^1.2.2"
+ victory-vendor: "npm:^37.0.2"
+ 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
+ checksum: 10c0/ae8e60202138670211a9464ecd838600803044796570281978f3d79d02c3add39d6513fd943c29d62a1bdefe01c0b98287e12a2a6685da3617257969c6ef2290
+ languageName: node
+ linkType: hard
+
+"redux-thunk@npm:^3.1.0":
+ version: 3.1.0
+ resolution: "redux-thunk@npm:3.1.0"
+ peerDependencies:
+ redux: ^5.0.0
+ checksum: 10c0/21557f6a30e1b2e3e470933247e51749be7f1d5a9620069a3125778675ce4d178d84bdee3e2a0903427a5c429e3aeec6d4df57897faf93eb83455bc1ef7b66fd
+ languageName: node
+ linkType: hard
+
+"redux@npm:^5.0.1":
+ version: 5.0.1
+ resolution: "redux@npm:5.0.1"
+ checksum: 10c0/b10c28357194f38e7d53b760ed5e64faa317cc63de1fb95bc5d9e127fab956392344368c357b8e7a9bedb0c35b111e7efa522210cfdc3b3c75e5074718e9069c
+ languageName: node
+ linkType: hard
+
+"reflect.getprototypeof@npm:^1.0.6, reflect.getprototypeof@npm:^1.0.9":
+ version: 1.0.10
+ resolution: "reflect.getprototypeof@npm:1.0.10"
+ dependencies:
+ call-bind: "npm:^1.0.8"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.23.9"
+ es-errors: "npm:^1.3.0"
+ es-object-atoms: "npm:^1.0.0"
+ get-intrinsic: "npm:^1.2.7"
+ get-proto: "npm:^1.0.1"
+ which-builtin-type: "npm:^1.2.1"
+ checksum: 10c0/7facec28c8008876f8ab98e80b7b9cb4b1e9224353fd4756dda5f2a4ab0d30fa0a5074777c6df24e1e0af463a2697513b0a11e548d99cf52f21f7bc6ba48d3ac
+ languageName: node
+ linkType: hard
+
+"regexp.prototype.flags@npm:^1.5.3, regexp.prototype.flags@npm:^1.5.4":
+ version: 1.5.4
+ resolution: "regexp.prototype.flags@npm:1.5.4"
+ dependencies:
+ call-bind: "npm:^1.0.8"
+ define-properties: "npm:^1.2.1"
+ es-errors: "npm:^1.3.0"
+ get-proto: "npm:^1.0.1"
+ gopd: "npm:^1.2.0"
+ set-function-name: "npm:^2.0.2"
+ checksum: 10c0/83b88e6115b4af1c537f8dabf5c3744032cb875d63bc05c288b1b8c0ef37cbe55353f95d8ca817e8843806e3e150b118bc624e4279b24b4776b4198232735a77
+ languageName: node
+ linkType: hard
+
+"rehype-highlight@npm:^7.0.2":
+ version: 7.0.2
+ resolution: "rehype-highlight@npm:7.0.2"
+ dependencies:
+ "@types/hast": "npm:^3.0.0"
+ hast-util-to-text: "npm:^4.0.0"
+ lowlight: "npm:^3.0.0"
+ unist-util-visit: "npm:^5.0.0"
+ vfile: "npm:^6.0.0"
+ checksum: 10c0/b62effff554f9a3f2ad8688c675bc7580e6dcf20a6988f86a25e95f1adea2f4900f8a13f96ec7db6a543314aed28267e4057f8dbc71c02a76a9511a716e88da2
+ languageName: node
+ linkType: hard
+
+"remark-gfm@npm:^4.0.1":
+ version: 4.0.1
+ resolution: "remark-gfm@npm:4.0.1"
+ dependencies:
+ "@types/mdast": "npm:^4.0.0"
+ mdast-util-gfm: "npm:^3.0.0"
+ micromark-extension-gfm: "npm:^3.0.0"
+ remark-parse: "npm:^11.0.0"
+ remark-stringify: "npm:^11.0.0"
+ unified: "npm:^11.0.0"
+ checksum: 10c0/427ecc6af3e76222662061a5f670a3e4e33ec5fffe2cabf04034da6a3f9a1bda1fc023e838a636385ba314e66e2bebbf017ca61ebea357eb0f5200fe0625a4b7
+ languageName: node
+ linkType: hard
+
+"remark-parse@npm:^11.0.0":
+ version: 11.0.0
+ resolution: "remark-parse@npm:11.0.0"
+ dependencies:
+ "@types/mdast": "npm:^4.0.0"
+ mdast-util-from-markdown: "npm:^2.0.0"
+ micromark-util-types: "npm:^2.0.0"
+ unified: "npm:^11.0.0"
+ checksum: 10c0/6eed15ddb8680eca93e04fcb2d1b8db65a743dcc0023f5007265dda558b09db595a087f622062ccad2630953cd5cddc1055ce491d25a81f3317c858348a8dd38
+ languageName: node
+ linkType: hard
+
+"remark-rehype@npm:^11.0.0":
+ version: 11.1.2
+ resolution: "remark-rehype@npm:11.1.2"
+ dependencies:
+ "@types/hast": "npm:^3.0.0"
+ "@types/mdast": "npm:^4.0.0"
+ mdast-util-to-hast: "npm:^13.0.0"
+ unified: "npm:^11.0.0"
+ vfile: "npm:^6.0.0"
+ checksum: 10c0/f9eccacfb596d9605581dc05bfad28635d6ded5dd0a18e88af5fd4df0d3fcf9612e1501d4513bc2164d833cfe9636dab20400080b09e53f155c6e1442a1231fb
+ languageName: node
+ linkType: hard
+
+"remark-stringify@npm:^11.0.0":
+ version: 11.0.0
+ resolution: "remark-stringify@npm:11.0.0"
+ dependencies:
+ "@types/mdast": "npm:^4.0.0"
+ mdast-util-to-markdown: "npm:^2.0.0"
+ unified: "npm:^11.0.0"
+ checksum: 10c0/0cdb37ce1217578f6f847c7ec9f50cbab35df5b9e3903d543e74b405404e67c07defcb23cd260a567b41b769400f6de03c2c3d9cd6ae7a6707d5c8d89ead489f
+ languageName: node
+ linkType: hard
+
+"requires-port@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "requires-port@npm:1.0.0"
+ checksum: 10c0/b2bfdd09db16c082c4326e573a82c0771daaf7b53b9ce8ad60ea46aa6e30aaf475fe9b164800b89f93b748d2c234d8abff945d2551ba47bf5698e04cd7713267
+ languageName: node
+ linkType: hard
+
+"reselect@npm:5.1.1, reselect@npm:^5.1.0":
+ version: 5.1.1
+ resolution: "reselect@npm:5.1.1"
+ checksum: 10c0/219c30da122980f61853db3aebd173524a2accd4b3baec770e3d51941426c87648a125ca08d8c57daa6b8b086f2fdd2703cb035dd6231db98cdbe1176a71f489
+ languageName: node
+ linkType: hard
+
+"resolve-from@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "resolve-from@npm:4.0.0"
+ checksum: 10c0/8408eec31a3112ef96e3746c37be7d64020cda07c03a920f5024e77290a218ea758b26ca9529fd7b1ad283947f34b2291c1c0f6aa0ed34acfdda9c6014c8d190
+ languageName: node
+ linkType: hard
+
+"resolve-pkg-maps@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "resolve-pkg-maps@npm:1.0.0"
+ checksum: 10c0/fb8f7bbe2ca281a73b7ef423a1cbc786fb244bd7a95cbe5c3fba25b27d327150beca8ba02f622baea65919a57e061eb5005204daa5f93ed590d9b77463a567ab
+ languageName: node
+ linkType: hard
+
+"resolve@npm:^1.22.4":
+ version: 1.22.11
+ resolution: "resolve@npm:1.22.11"
+ dependencies:
+ is-core-module: "npm:^2.16.1"
+ path-parse: "npm:^1.0.7"
+ supports-preserve-symlinks-flag: "npm:^1.0.0"
+ bin:
+ resolve: bin/resolve
+ checksum: 10c0/f657191507530f2cbecb5815b1ee99b20741ea6ee02a59c57028e9ec4c2c8d7681afcc35febbd554ac0ded459db6f2d8153382c53a2f266cee2575e512674409
+ languageName: node
+ linkType: hard
+
+"resolve@npm:^2.0.0-next.5":
+ version: 2.0.0-next.6
+ resolution: "resolve@npm:2.0.0-next.6"
+ dependencies:
+ es-errors: "npm:^1.3.0"
+ is-core-module: "npm:^2.16.1"
+ node-exports-info: "npm:^1.6.0"
+ object-keys: "npm:^1.1.1"
+ path-parse: "npm:^1.0.7"
+ supports-preserve-symlinks-flag: "npm:^1.0.0"
+ bin:
+ resolve: bin/resolve
+ checksum: 10c0/4e44cb84aa9a3c7c82d4a98e8111879671150496160a53ca6cdbed6101bf239f19105f8b8b84e40c0b76d46b0d9626813510b19a80e01f4ae18692e9d0b47749
+ languageName: node
+ linkType: hard
+
+"resolve@patch:resolve@npm%3A^1.22.4#optional!builtin":
+ version: 1.22.11
+ resolution: "resolve@patch:resolve@npm%3A1.22.11#optional!builtin::version=1.22.11&hash=c3c19d"
+ dependencies:
+ is-core-module: "npm:^2.16.1"
+ path-parse: "npm:^1.0.7"
+ supports-preserve-symlinks-flag: "npm:^1.0.0"
+ bin:
+ resolve: bin/resolve
+ checksum: 10c0/ee5b182f2e37cb1165465e58c6abc797fec0a80b5ba3231607beb4677db0c9291ac010c47cf092b6daa2b7f518d69a0e21888e7e2b633f68d501a874212a8c63
+ languageName: node
+ linkType: hard
+
+"resolve@patch:resolve@npm%3A^2.0.0-next.5#optional!builtin":
+ version: 2.0.0-next.6
+ resolution: "resolve@patch:resolve@npm%3A2.0.0-next.6#optional!builtin::version=2.0.0-next.6&hash=c3c19d"
+ dependencies:
+ es-errors: "npm:^1.3.0"
+ is-core-module: "npm:^2.16.1"
+ node-exports-info: "npm:^1.6.0"
+ object-keys: "npm:^1.1.1"
+ path-parse: "npm:^1.0.7"
+ supports-preserve-symlinks-flag: "npm:^1.0.0"
+ bin:
+ resolve: bin/resolve
+ checksum: 10c0/dca533e38820b0d8d636f269824cef3b7435802ab7401211c6f10af03be0e2f7e216047234e1623046c0a6791577079767e0c04f0d36e42c7f567b1bff7b0742
+ languageName: node
+ linkType: hard
+
+"retry@npm:^0.13.1":
+ version: 0.13.1
+ resolution: "retry@npm:0.13.1"
+ checksum: 10c0/9ae822ee19db2163497e074ea919780b1efa00431d197c7afdb950e42bf109196774b92a49fc9821f0b8b328a98eea6017410bfc5e8a0fc19c85c6d11adb3772
+ languageName: node
+ linkType: hard
+
+"reusify@npm:^1.0.4":
+ version: 1.1.0
+ resolution: "reusify@npm:1.1.0"
+ checksum: 10c0/4eff0d4a5f9383566c7d7ec437b671cc51b25963bd61bf127c3f3d3f68e44a026d99b8d2f1ad344afff8d278a8fe70a8ea092650a716d22287e8bef7126bb2fa
+ languageName: node
+ linkType: hard
+
+"rollup@npm:^4.43.0":
+ version: 4.59.0
+ resolution: "rollup@npm:4.59.0"
+ dependencies:
+ "@rollup/rollup-android-arm-eabi": "npm:4.59.0"
+ "@rollup/rollup-android-arm64": "npm:4.59.0"
+ "@rollup/rollup-darwin-arm64": "npm:4.59.0"
+ "@rollup/rollup-darwin-x64": "npm:4.59.0"
+ "@rollup/rollup-freebsd-arm64": "npm:4.59.0"
+ "@rollup/rollup-freebsd-x64": "npm:4.59.0"
+ "@rollup/rollup-linux-arm-gnueabihf": "npm:4.59.0"
+ "@rollup/rollup-linux-arm-musleabihf": "npm:4.59.0"
+ "@rollup/rollup-linux-arm64-gnu": "npm:4.59.0"
+ "@rollup/rollup-linux-arm64-musl": "npm:4.59.0"
+ "@rollup/rollup-linux-loong64-gnu": "npm:4.59.0"
+ "@rollup/rollup-linux-loong64-musl": "npm:4.59.0"
+ "@rollup/rollup-linux-ppc64-gnu": "npm:4.59.0"
+ "@rollup/rollup-linux-ppc64-musl": "npm:4.59.0"
+ "@rollup/rollup-linux-riscv64-gnu": "npm:4.59.0"
+ "@rollup/rollup-linux-riscv64-musl": "npm:4.59.0"
+ "@rollup/rollup-linux-s390x-gnu": "npm:4.59.0"
+ "@rollup/rollup-linux-x64-gnu": "npm:4.59.0"
+ "@rollup/rollup-linux-x64-musl": "npm:4.59.0"
+ "@rollup/rollup-openbsd-x64": "npm:4.59.0"
+ "@rollup/rollup-openharmony-arm64": "npm:4.59.0"
+ "@rollup/rollup-win32-arm64-msvc": "npm:4.59.0"
+ "@rollup/rollup-win32-ia32-msvc": "npm:4.59.0"
+ "@rollup/rollup-win32-x64-gnu": "npm:4.59.0"
+ "@rollup/rollup-win32-x64-msvc": "npm:4.59.0"
+ "@types/estree": "npm:1.0.8"
+ fsevents: "npm:~2.3.2"
+ dependenciesMeta:
+ "@rollup/rollup-android-arm-eabi":
+ optional: true
+ "@rollup/rollup-android-arm64":
+ optional: true
+ "@rollup/rollup-darwin-arm64":
+ optional: true
+ "@rollup/rollup-darwin-x64":
+ optional: true
+ "@rollup/rollup-freebsd-arm64":
+ optional: true
+ "@rollup/rollup-freebsd-x64":
+ optional: true
+ "@rollup/rollup-linux-arm-gnueabihf":
+ optional: true
+ "@rollup/rollup-linux-arm-musleabihf":
+ optional: true
+ "@rollup/rollup-linux-arm64-gnu":
+ optional: true
+ "@rollup/rollup-linux-arm64-musl":
+ optional: true
+ "@rollup/rollup-linux-loong64-gnu":
+ optional: true
+ "@rollup/rollup-linux-loong64-musl":
+ optional: true
+ "@rollup/rollup-linux-ppc64-gnu":
+ optional: true
+ "@rollup/rollup-linux-ppc64-musl":
+ optional: true
+ "@rollup/rollup-linux-riscv64-gnu":
+ optional: true
+ "@rollup/rollup-linux-riscv64-musl":
+ optional: true
+ "@rollup/rollup-linux-s390x-gnu":
+ optional: true
+ "@rollup/rollup-linux-x64-gnu":
+ optional: true
+ "@rollup/rollup-linux-x64-musl":
+ optional: true
+ "@rollup/rollup-openbsd-x64":
+ optional: true
+ "@rollup/rollup-openharmony-arm64":
+ optional: true
+ "@rollup/rollup-win32-arm64-msvc":
+ optional: true
+ "@rollup/rollup-win32-ia32-msvc":
+ optional: true
+ "@rollup/rollup-win32-x64-gnu":
+ optional: true
+ "@rollup/rollup-win32-x64-msvc":
+ optional: true
+ fsevents:
+ optional: true
+ bin:
+ rollup: dist/bin/rollup
+ checksum: 10c0/f38742da34cfee5e899302615fa157aa77cb6a2a1495e5e3ce4cc9c540d3262e235bbe60caa31562bbfe492b01fdb3e7a8c43c39d842d3293bcf843123b766fc
+ languageName: node
+ linkType: hard
+
+"rou3@npm:^0.7.10":
+ version: 0.7.12
+ resolution: "rou3@npm:0.7.12"
+ checksum: 10c0/2ea87ddd91a5d0f9d9671fa2bb714f57566eae33ecb24e8a61bb298aca8c226483e59cafe1c60297ac9aa58b2b6ad506447374cdbff4e99cf0f9f72a9dae09dc
+ languageName: node
+ linkType: hard
+
+"run-parallel@npm:^1.1.9":
+ version: 1.2.0
+ resolution: "run-parallel@npm:1.2.0"
+ dependencies:
+ queue-microtask: "npm:^1.2.2"
+ checksum: 10c0/200b5ab25b5b8b7113f9901bfe3afc347e19bb7475b267d55ad0eb86a62a46d77510cb0f232507c9e5d497ebda569a08a9867d0d14f57a82ad5564d991588b39
+ languageName: node
+ linkType: hard
+
+"safe-array-concat@npm:^1.1.3":
+ version: 1.1.3
+ resolution: "safe-array-concat@npm:1.1.3"
+ dependencies:
+ call-bind: "npm:^1.0.8"
+ call-bound: "npm:^1.0.2"
+ get-intrinsic: "npm:^1.2.6"
+ has-symbols: "npm:^1.1.0"
+ isarray: "npm:^2.0.5"
+ checksum: 10c0/43c86ffdddc461fb17ff8a17c5324f392f4868f3c7dd2c6a5d9f5971713bc5fd755667212c80eab9567595f9a7509cc2f83e590ddaebd1bd19b780f9c79f9a8d
+ languageName: node
+ linkType: hard
+
+"safe-push-apply@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "safe-push-apply@npm:1.0.0"
+ dependencies:
+ es-errors: "npm:^1.3.0"
+ isarray: "npm:^2.0.5"
+ checksum: 10c0/831f1c9aae7436429e7862c7e46f847dfe490afac20d0ee61bae06108dbf5c745a0de3568ada30ccdd3eeb0864ca8331b2eef703abd69bfea0745b21fd320750
+ languageName: node
+ linkType: hard
+
+"safe-regex-test@npm:^1.0.3, safe-regex-test@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "safe-regex-test@npm:1.1.0"
+ dependencies:
+ call-bound: "npm:^1.0.2"
+ es-errors: "npm:^1.3.0"
+ is-regex: "npm:^1.2.1"
+ checksum: 10c0/f2c25281bbe5d39cddbbce7f86fca5ea9b3ce3354ea6cd7c81c31b006a5a9fff4286acc5450a3b9122c56c33eba69c56b9131ad751457b2b4a585825e6a10665
+ languageName: node
+ linkType: hard
+
+"safer-buffer@npm:>= 2.1.2 < 3.0.0":
+ version: 2.1.2
+ resolution: "safer-buffer@npm:2.1.2"
+ checksum: 10c0/7e3c8b2e88a1841c9671094bbaeebd94448111dd90a81a1f606f3f67708a6ec57763b3b47f06da09fc6054193e0e6709e77325415dc8422b04497a8070fa02d4
+ languageName: node
+ linkType: hard
+
+"scheduler@npm:^0.27.0":
+ version: 0.27.0
+ resolution: "scheduler@npm:0.27.0"
+ checksum: 10c0/4f03048cb05a3c8fddc45813052251eca00688f413a3cee236d984a161da28db28ba71bd11e7a3dd02f7af84ab28d39fb311431d3b3772fed557945beb00c452
+ languageName: node
+ linkType: hard
+
+"semver@npm:^6.3.1":
+ version: 6.3.1
+ resolution: "semver@npm:6.3.1"
+ bin:
+ semver: bin/semver.js
+ checksum: 10c0/e3d79b609071caa78bcb6ce2ad81c7966a46a7431d9d58b8800cfa9cb6a63699b3899a0e4bcce36167a284578212d9ae6942b6929ba4aa5015c079a67751d42d
+ languageName: node
+ linkType: hard
+
+"semver@npm:^7.3.5, semver@npm:^7.7.1, semver@npm:^7.7.3":
+ version: 7.7.4
+ resolution: "semver@npm:7.7.4"
+ bin:
+ semver: bin/semver.js
+ checksum: 10c0/5215ad0234e2845d4ea5bb9d836d42b03499546ddafb12075566899fc617f68794bb6f146076b6881d755de17d6c6cc73372555879ec7dce2c2feee947866ad2
+ languageName: node
+ linkType: hard
+
+"set-cookie-parser@npm:^2.7.1":
+ version: 2.7.2
+ resolution: "set-cookie-parser@npm:2.7.2"
+ checksum: 10c0/4381a9eb7ee951dfe393fe7aacf76b9a3b4e93a684d2162ab35594fa4053cc82a4d7d7582bf397718012c9adcf839b8cd8f57c6c42901ea9effe33c752da4a45
+ languageName: node
+ linkType: hard
+
+"set-function-length@npm:^1.2.2":
+ version: 1.2.2
+ resolution: "set-function-length@npm:1.2.2"
+ dependencies:
+ define-data-property: "npm:^1.1.4"
+ es-errors: "npm:^1.3.0"
+ function-bind: "npm:^1.1.2"
+ get-intrinsic: "npm:^1.2.4"
+ gopd: "npm:^1.0.1"
+ has-property-descriptors: "npm:^1.0.2"
+ checksum: 10c0/82850e62f412a258b71e123d4ed3873fa9377c216809551192bb6769329340176f109c2eeae8c22a8d386c76739855f78e8716515c818bcaef384b51110f0f3c
+ languageName: node
+ linkType: hard
+
+"set-function-name@npm:^2.0.2":
+ version: 2.0.2
+ resolution: "set-function-name@npm:2.0.2"
+ dependencies:
+ define-data-property: "npm:^1.1.4"
+ es-errors: "npm:^1.3.0"
+ functions-have-names: "npm:^1.2.3"
+ has-property-descriptors: "npm:^1.0.2"
+ checksum: 10c0/fce59f90696c450a8523e754abb305e2b8c73586452619c2bad5f7bf38c7b6b4651895c9db895679c5bef9554339cf3ef1c329b66ece3eda7255785fbe299316
+ languageName: node
+ linkType: hard
+
+"set-proto@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "set-proto@npm:1.0.0"
+ dependencies:
+ dunder-proto: "npm:^1.0.1"
+ es-errors: "npm:^1.3.0"
+ es-object-atoms: "npm:^1.0.0"
+ checksum: 10c0/ca5c3ccbba479d07c30460e367e66337cec825560b11e8ba9c5ebe13a2a0d6021ae34eddf94ff3dfe17a3104dc1f191519cb6c48378b503e5c3f36393938776a
+ languageName: node
+ linkType: hard
+
+"sharp@npm:^0.34.3":
+ version: 0.34.5
+ resolution: "sharp@npm:0.34.5"
+ dependencies:
+ "@img/colour": "npm:^1.0.0"
+ "@img/sharp-darwin-arm64": "npm:0.34.5"
+ "@img/sharp-darwin-x64": "npm:0.34.5"
+ "@img/sharp-libvips-darwin-arm64": "npm:1.2.4"
+ "@img/sharp-libvips-darwin-x64": "npm:1.2.4"
+ "@img/sharp-libvips-linux-arm": "npm:1.2.4"
+ "@img/sharp-libvips-linux-arm64": "npm:1.2.4"
+ "@img/sharp-libvips-linux-ppc64": "npm:1.2.4"
+ "@img/sharp-libvips-linux-riscv64": "npm:1.2.4"
+ "@img/sharp-libvips-linux-s390x": "npm:1.2.4"
+ "@img/sharp-libvips-linux-x64": "npm:1.2.4"
+ "@img/sharp-libvips-linuxmusl-arm64": "npm:1.2.4"
+ "@img/sharp-libvips-linuxmusl-x64": "npm:1.2.4"
+ "@img/sharp-linux-arm": "npm:0.34.5"
+ "@img/sharp-linux-arm64": "npm:0.34.5"
+ "@img/sharp-linux-ppc64": "npm:0.34.5"
+ "@img/sharp-linux-riscv64": "npm:0.34.5"
+ "@img/sharp-linux-s390x": "npm:0.34.5"
+ "@img/sharp-linux-x64": "npm:0.34.5"
+ "@img/sharp-linuxmusl-arm64": "npm:0.34.5"
+ "@img/sharp-linuxmusl-x64": "npm:0.34.5"
+ "@img/sharp-wasm32": "npm:0.34.5"
+ "@img/sharp-win32-arm64": "npm:0.34.5"
+ "@img/sharp-win32-ia32": "npm:0.34.5"
+ "@img/sharp-win32-x64": "npm:0.34.5"
+ detect-libc: "npm:^2.1.2"
+ semver: "npm:^7.7.3"
+ dependenciesMeta:
+ "@img/sharp-darwin-arm64":
+ optional: true
+ "@img/sharp-darwin-x64":
+ optional: true
+ "@img/sharp-libvips-darwin-arm64":
+ optional: true
+ "@img/sharp-libvips-darwin-x64":
+ optional: true
+ "@img/sharp-libvips-linux-arm":
+ optional: true
+ "@img/sharp-libvips-linux-arm64":
+ optional: true
+ "@img/sharp-libvips-linux-ppc64":
+ optional: true
+ "@img/sharp-libvips-linux-riscv64":
+ optional: true
+ "@img/sharp-libvips-linux-s390x":
+ optional: true
+ "@img/sharp-libvips-linux-x64":
+ optional: true
+ "@img/sharp-libvips-linuxmusl-arm64":
+ optional: true
+ "@img/sharp-libvips-linuxmusl-x64":
+ optional: true
+ "@img/sharp-linux-arm":
+ optional: true
+ "@img/sharp-linux-arm64":
+ optional: true
+ "@img/sharp-linux-ppc64":
+ optional: true
+ "@img/sharp-linux-riscv64":
+ optional: true
+ "@img/sharp-linux-s390x":
+ optional: true
+ "@img/sharp-linux-x64":
+ optional: true
+ "@img/sharp-linuxmusl-arm64":
+ optional: true
+ "@img/sharp-linuxmusl-x64":
+ optional: true
+ "@img/sharp-wasm32":
+ optional: true
+ "@img/sharp-win32-arm64":
+ optional: true
+ "@img/sharp-win32-ia32":
+ optional: true
+ "@img/sharp-win32-x64":
+ optional: true
+ checksum: 10c0/fd79e29df0597a7d5704b8461c51f944ead91a5243691697be6e8243b966402beda53ddc6f0a53b96ea3cb8221f0b244aa588114d3ebf8734fb4aefd41ab802f
+ languageName: node
+ linkType: hard
+
+"shebang-command@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "shebang-command@npm:2.0.0"
+ dependencies:
+ shebang-regex: "npm:^3.0.0"
+ checksum: 10c0/a41692e7d89a553ef21d324a5cceb5f686d1f3c040759c50aab69688634688c5c327f26f3ecf7001ebfd78c01f3c7c0a11a7c8bfd0a8bc9f6240d4f40b224e4e
+ languageName: node
+ linkType: hard
+
+"shebang-regex@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "shebang-regex@npm:3.0.0"
+ checksum: 10c0/1dbed0726dd0e1152a92696c76c7f06084eb32a90f0528d11acd764043aacf76994b2fb30aa1291a21bd019d6699164d048286309a278855ee7bec06cf6fb690
+ languageName: node
+ linkType: hard
+
+"side-channel-list@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "side-channel-list@npm:1.0.0"
+ dependencies:
+ es-errors: "npm:^1.3.0"
+ object-inspect: "npm:^1.13.3"
+ checksum: 10c0/644f4ac893456c9490ff388bf78aea9d333d5e5bfc64cfb84be8f04bf31ddc111a8d4b83b85d7e7e8a7b845bc185a9ad02c052d20e086983cf59f0be517d9b3d
+ languageName: node
+ linkType: hard
+
+"side-channel-map@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "side-channel-map@npm:1.0.1"
+ dependencies:
+ call-bound: "npm:^1.0.2"
+ es-errors: "npm:^1.3.0"
+ get-intrinsic: "npm:^1.2.5"
+ object-inspect: "npm:^1.13.3"
+ checksum: 10c0/010584e6444dd8a20b85bc926d934424bd809e1a3af941cace229f7fdcb751aada0fb7164f60c2e22292b7fa3c0ff0bce237081fd4cdbc80de1dc68e95430672
+ languageName: node
+ linkType: hard
+
+"side-channel-weakmap@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "side-channel-weakmap@npm:1.0.2"
+ dependencies:
+ call-bound: "npm:^1.0.2"
+ es-errors: "npm:^1.3.0"
+ get-intrinsic: "npm:^1.2.5"
+ object-inspect: "npm:^1.13.3"
+ side-channel-map: "npm:^1.0.1"
+ checksum: 10c0/71362709ac233e08807ccd980101c3e2d7efe849edc51455030327b059f6c4d292c237f94dc0685031dd11c07dd17a68afde235d6cf2102d949567f98ab58185
+ languageName: node
+ linkType: hard
+
+"side-channel@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "side-channel@npm:1.1.0"
+ dependencies:
+ es-errors: "npm:^1.3.0"
+ object-inspect: "npm:^1.13.3"
+ side-channel-list: "npm:^1.0.0"
+ side-channel-map: "npm:^1.0.1"
+ side-channel-weakmap: "npm:^1.0.2"
+ checksum: 10c0/cb20dad41eb032e6c24c0982e1e5a24963a28aa6122b4f05b3f3d6bf8ae7fd5474ef382c8f54a6a3ab86e0cac4d41a23bd64ede3970e5bfb50326ba02a7996e6
+ languageName: node
+ linkType: hard
+
+"siginfo@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "siginfo@npm:2.0.0"
+ checksum: 10c0/3def8f8e516fbb34cb6ae415b07ccc5d9c018d85b4b8611e3dc6f8be6d1899f693a4382913c9ed51a06babb5201639d76453ab297d1c54a456544acf5c892e34
+ languageName: node
+ linkType: hard
+
+"smart-buffer@npm:^4.2.0":
+ version: 4.2.0
+ resolution: "smart-buffer@npm:4.2.0"
+ checksum: 10c0/a16775323e1404dd43fabafe7460be13a471e021637bc7889468eb45ce6a6b207261f454e4e530a19500cc962c4cc5348583520843b363f4193cee5c00e1e539
+ languageName: node
+ linkType: hard
+
+"socks-proxy-agent@npm:^8.0.3":
+ version: 8.0.5
+ resolution: "socks-proxy-agent@npm:8.0.5"
+ dependencies:
+ agent-base: "npm:^7.1.2"
+ debug: "npm:^4.3.4"
+ socks: "npm:^2.8.3"
+ checksum: 10c0/5d2c6cecba6821389aabf18728325730504bf9bb1d9e342e7987a5d13badd7a98838cc9a55b8ed3cb866ad37cc23e1086f09c4d72d93105ce9dfe76330e9d2a6
+ languageName: node
+ linkType: hard
+
+"socks@npm:^2.8.3":
+ version: 2.8.7
+ resolution: "socks@npm:2.8.7"
+ dependencies:
+ ip-address: "npm:^10.0.1"
+ smart-buffer: "npm:^4.2.0"
+ checksum: 10c0/2805a43a1c4bcf9ebf6e018268d87b32b32b06fbbc1f9282573583acc155860dc361500f89c73bfbb157caa1b4ac78059eac0ef15d1811eb0ca75e0bdadbc9d2
+ languageName: node
+ linkType: hard
+
+"sonner@npm:^2.0.7":
+ version: 2.0.7
+ resolution: "sonner@npm:2.0.7"
+ peerDependencies:
+ react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
+ react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
+ checksum: 10c0/6966ab5e892ed6aab579a175e4a24f3b48747f0fc21cb68c3e33cb41caa7a0eebeb098c210545395e47a18d585eb8734ae7dd12d2bd18c8a3294a1ee73f997d9
+ languageName: node
+ linkType: hard
+
+"source-map-js@npm:^1.0.2, source-map-js@npm:^1.2.1":
+ version: 1.2.1
+ resolution: "source-map-js@npm:1.2.1"
+ checksum: 10c0/7bda1fc4c197e3c6ff17de1b8b2c20e60af81b63a52cb32ec5a5d67a20a7d42651e2cb34ebe93833c5a2a084377e17455854fee3e21e7925c64a51b6a52b0faf
+ languageName: node
+ linkType: hard
+
+"space-separated-tokens@npm:^2.0.0":
+ version: 2.0.2
+ resolution: "space-separated-tokens@npm:2.0.2"
+ checksum: 10c0/6173e1d903dca41dcab6a2deed8b4caf61bd13b6d7af8374713500570aa929ff9414ae09a0519f4f8772df993300305a395d4871f35bc4ca72b6db57e1f30af8
+ languageName: node
+ linkType: hard
+
+"ssri@npm:^13.0.0":
+ version: 13.0.1
+ resolution: "ssri@npm:13.0.1"
+ dependencies:
+ minipass: "npm:^7.0.3"
+ checksum: 10c0/cf6408a18676c57ff2ed06b8a20dc64bb3e748e5c7e095332e6aecaa2b8422b1e94a739a8453bf65156a8a47afe23757ba4ab52d3ea3b62322dc40875763e17a
+ languageName: node
+ linkType: hard
+
+"stable-hash@npm:^0.0.5":
+ version: 0.0.5
+ resolution: "stable-hash@npm:0.0.5"
+ checksum: 10c0/ca670cb6d172f1c834950e4ec661e2055885df32fee3ebf3647c5df94993b7c2666a5dbc1c9a62ee11fc5c24928579ec5e81bb5ad31971d355d5a341aab493b3
+ languageName: node
+ linkType: hard
+
+"stackback@npm:0.0.2":
+ version: 0.0.2
+ resolution: "stackback@npm:0.0.2"
+ checksum: 10c0/89a1416668f950236dd5ac9f9a6b2588e1b9b62b1b6ad8dff1bfc5d1a15dbf0aafc9b52d2226d00c28dffff212da464eaeebfc6b7578b9d180cef3e3782c5983
+ languageName: node
+ linkType: hard
+
+"std-env@npm:^3.9.0":
+ version: 3.10.0
+ resolution: "std-env@npm:3.10.0"
+ checksum: 10c0/1814927a45004d36dde6707eaf17552a546769bc79a6421be2c16ce77d238158dfe5de30910b78ec30d95135cc1c59ea73ee22d2ca170f8b9753f84da34c427f
+ languageName: node
+ linkType: hard
+
+"stop-iteration-iterator@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "stop-iteration-iterator@npm:1.1.0"
+ dependencies:
+ es-errors: "npm:^1.3.0"
+ internal-slot: "npm:^1.1.0"
+ checksum: 10c0/de4e45706bb4c0354a4b1122a2b8cc45a639e86206807ce0baf390ee9218d3ef181923fa4d2b67443367c491aa255c5fbaa64bb74648e3c5b48299928af86c09
+ languageName: node
+ linkType: hard
+
+"string.prototype.includes@npm:^2.0.1":
+ version: 2.0.1
+ resolution: "string.prototype.includes@npm:2.0.1"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.23.3"
+ checksum: 10c0/25ce9c9b49128352a2618fbe8758b46f945817a58a4420f4799419e40a8d28f116e176c7590d767d5327a61e75c8f32c86171063f48e389b9fdd325f1bd04ee5
+ languageName: node
+ linkType: hard
+
+"string.prototype.matchall@npm:^4.0.12":
+ version: 4.0.12
+ resolution: "string.prototype.matchall@npm:4.0.12"
+ dependencies:
+ call-bind: "npm:^1.0.8"
+ call-bound: "npm:^1.0.3"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.23.6"
+ es-errors: "npm:^1.3.0"
+ es-object-atoms: "npm:^1.0.0"
+ get-intrinsic: "npm:^1.2.6"
+ gopd: "npm:^1.2.0"
+ has-symbols: "npm:^1.1.0"
+ internal-slot: "npm:^1.1.0"
+ regexp.prototype.flags: "npm:^1.5.3"
+ set-function-name: "npm:^2.0.2"
+ side-channel: "npm:^1.1.0"
+ checksum: 10c0/1a53328ada73f4a77f1fdf1c79414700cf718d0a8ef6672af5603e709d26a24f2181208144aed7e858b1bcc1a0d08567a570abfb45567db4ae47637ed2c2f85c
+ languageName: node
+ linkType: hard
+
+"string.prototype.repeat@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "string.prototype.repeat@npm:1.0.0"
+ dependencies:
+ define-properties: "npm:^1.1.3"
+ es-abstract: "npm:^1.17.5"
+ checksum: 10c0/94c7978566cffa1327d470fd924366438af9b04b497c43a9805e476e2e908aa37a1fd34cc0911156c17556dab62159d12c7b92b3cc304c3e1281fe4c8e668f40
+ languageName: node
+ linkType: hard
+
+"string.prototype.trim@npm:^1.2.10":
+ version: 1.2.10
+ resolution: "string.prototype.trim@npm:1.2.10"
+ dependencies:
+ call-bind: "npm:^1.0.8"
+ call-bound: "npm:^1.0.2"
+ define-data-property: "npm:^1.1.4"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.23.5"
+ es-object-atoms: "npm:^1.0.0"
+ has-property-descriptors: "npm:^1.0.2"
+ checksum: 10c0/8a8854241c4b54a948e992eb7dd6b8b3a97185112deb0037a134f5ba57541d8248dd610c966311887b6c2fd1181a3877bffb14d873ce937a344535dabcc648f8
+ languageName: node
+ linkType: hard
+
+"string.prototype.trimend@npm:^1.0.9":
+ version: 1.0.9
+ resolution: "string.prototype.trimend@npm:1.0.9"
+ dependencies:
+ call-bind: "npm:^1.0.8"
+ call-bound: "npm:^1.0.2"
+ define-properties: "npm:^1.2.1"
+ es-object-atoms: "npm:^1.0.0"
+ checksum: 10c0/59e1a70bf9414cb4c536a6e31bef5553c8ceb0cf44d8b4d0ed65c9653358d1c64dd0ec203b100df83d0413bbcde38b8c5d49e14bc4b86737d74adc593a0d35b6
+ languageName: node
+ linkType: hard
+
+"string.prototype.trimstart@npm:^1.0.8":
+ version: 1.0.8
+ resolution: "string.prototype.trimstart@npm:1.0.8"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ define-properties: "npm:^1.2.1"
+ es-object-atoms: "npm:^1.0.0"
+ checksum: 10c0/d53af1899959e53c83b64a5fd120be93e067da740e7e75acb433849aa640782fb6c7d4cd5b84c954c84413745a3764df135a8afeb22908b86a835290788d8366
+ languageName: node
+ linkType: hard
+
+"stringify-entities@npm:^4.0.0":
+ version: 4.0.4
+ resolution: "stringify-entities@npm:4.0.4"
+ dependencies:
+ character-entities-html4: "npm:^2.0.0"
+ character-entities-legacy: "npm:^3.0.0"
+ checksum: 10c0/537c7e656354192406bdd08157d759cd615724e9d0873602d2c9b2f6a5c0a8d0b1d73a0a08677848105c5eebac6db037b57c0b3a4ec86331117fa7319ed50448
+ languageName: node
+ linkType: hard
+
+"strip-bom@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "strip-bom@npm:3.0.0"
+ checksum: 10c0/51201f50e021ef16672593d7434ca239441b7b760e905d9f33df6e4f3954ff54ec0e0a06f100d028af0982d6f25c35cd5cda2ce34eaebccd0250b8befb90d8f1
+ languageName: node
+ linkType: hard
+
+"strip-json-comments@npm:^3.1.1":
+ version: 3.1.1
+ resolution: "strip-json-comments@npm:3.1.1"
+ checksum: 10c0/9681a6257b925a7fa0f285851c0e613cc934a50661fa7bb41ca9cbbff89686bb4a0ee366e6ecedc4daafd01e83eee0720111ab294366fe7c185e935475ebcecd
+ languageName: node
+ linkType: hard
+
+"strip-literal@npm:^3.0.0":
+ version: 3.1.0
+ resolution: "strip-literal@npm:3.1.0"
+ dependencies:
+ js-tokens: "npm:^9.0.1"
+ checksum: 10c0/50918f669915d9ad0fe4b7599902b735f853f2201c97791ead00104a654259c0c61bc2bc8fa3db05109339b61f4cf09e47b94ecc874ffbd0e013965223893af8
+ languageName: node
+ linkType: hard
+
+"style-to-js@npm:^1.0.0":
+ version: 1.1.21
+ resolution: "style-to-js@npm:1.1.21"
+ dependencies:
+ style-to-object: "npm:1.0.14"
+ checksum: 10c0/94231aa80f58f442c3a5ae01a21d10701e5d62f96b4b3e52eab3499077ee52df203cc0df4a1a870707f5e99470859136ea8657b782a5f4ca7934e0ffe662a588
+ languageName: node
+ linkType: hard
+
+"style-to-object@npm:1.0.14":
+ version: 1.0.14
+ resolution: "style-to-object@npm:1.0.14"
+ dependencies:
+ inline-style-parser: "npm:0.2.7"
+ checksum: 10c0/854d9e9b77afc336e6d7b09348e7939f2617b34eb0895824b066d8cd1790284cb6d8b2ba36be88025b2595d715dba14b299ae76e4628a366541106f639e13679
+ languageName: node
+ linkType: hard
+
+"styled-jsx@npm:5.1.6":
+ version: 5.1.6
+ resolution: "styled-jsx@npm:5.1.6"
+ dependencies:
+ client-only: "npm:0.0.1"
+ peerDependencies:
+ react: ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0"
+ peerDependenciesMeta:
+ "@babel/core":
+ optional: true
+ babel-plugin-macros:
+ optional: true
+ checksum: 10c0/ace50e7ea5ae5ae6a3b65a50994c51fca6ae7df9c7ecfd0104c36be0b4b3a9c5c1a2374d16e2a11e256d0b20be6d47256d768ecb4f91ab390f60752a075780f5
+ languageName: node
+ linkType: hard
+
+"supports-color@npm:^7.1.0":
+ version: 7.2.0
+ resolution: "supports-color@npm:7.2.0"
+ dependencies:
+ has-flag: "npm:^4.0.0"
+ checksum: 10c0/afb4c88521b8b136b5f5f95160c98dee7243dc79d5432db7efc27efb219385bbc7d9427398e43dd6cc730a0f87d5085ce1652af7efbe391327bc0a7d0f7fc124
+ languageName: node
+ linkType: hard
+
+"supports-preserve-symlinks-flag@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "supports-preserve-symlinks-flag@npm:1.0.0"
+ checksum: 10c0/6c4032340701a9950865f7ae8ef38578d8d7053f5e10518076e6554a9381fa91bd9c6850193695c141f32b21f979c985db07265a758867bac95de05f7d8aeb39
+ languageName: node
+ linkType: hard
+
+"tailwind-merge@npm:^3.0.2":
+ version: 3.5.0
+ resolution: "tailwind-merge@npm:3.5.0"
+ checksum: 10c0/4dc588f5b5296ba3f38e1ebb41f02b6d24a8c5bb45e44b33748c118fb4b5767dd0efc464431ca3e75404056b618b5f67bec3708158baa65fed8a2fc9201e0c53
+ languageName: node
+ linkType: hard
+
+"tailwindcss@npm:4.2.1, tailwindcss@npm:^4.1.3":
+ version: 4.2.1
+ resolution: "tailwindcss@npm:4.2.1"
+ checksum: 10c0/482d734b582e9da509042ff59c1d7564d99e39e238c50ae907c20fa56177a8a00c3902f6971329971bd6a1c5357026ac76a849b8f2c69c94f0f59be99530ba54
+ languageName: node
+ linkType: hard
+
+"tapable@npm:^2.3.0":
+ version: 2.3.0
+ resolution: "tapable@npm:2.3.0"
+ checksum: 10c0/cb9d67cc2c6a74dedc812ef3085d9d681edd2c1fa18e4aef57a3c0605fdbe44e6b8ea00bd9ef21bc74dd45314e39d31227aa031ebf2f5e38164df514136f2681
+ languageName: node
+ linkType: hard
+
+"tar@npm:^7.5.4":
+ version: 7.5.11
+ resolution: "tar@npm:7.5.11"
+ dependencies:
+ "@isaacs/fs-minipass": "npm:^4.0.0"
+ chownr: "npm:^3.0.0"
+ minipass: "npm:^7.1.2"
+ minizlib: "npm:^3.1.0"
+ yallist: "npm:^5.0.0"
+ checksum: 10c0/b6bb420550ef50ef23356018155e956cd83282c97b6128d8d5cfe5740c57582d806a244b2ef0bf686a74ce526babe8b8b9061527623e935e850008d86d838929
+ languageName: node
+ linkType: hard
+
+"tiny-invariant@npm:^1.3.3":
+ version: 1.3.3
+ resolution: "tiny-invariant@npm:1.3.3"
+ checksum: 10c0/65af4a07324b591a059b35269cd696aba21bef2107f29b9f5894d83cc143159a204b299553435b03874ebb5b94d019afa8b8eff241c8a4cfee95872c2e1c1c4a
+ languageName: node
+ linkType: hard
+
+"tinybench@npm:^2.9.0":
+ version: 2.9.0
+ resolution: "tinybench@npm:2.9.0"
+ checksum: 10c0/c3500b0f60d2eb8db65250afe750b66d51623057ee88720b7f064894a6cb7eb93360ca824a60a31ab16dab30c7b1f06efe0795b352e37914a9d4bad86386a20c
+ languageName: node
+ linkType: hard
+
+"tinyexec@npm:^0.3.2":
+ version: 0.3.2
+ resolution: "tinyexec@npm:0.3.2"
+ checksum: 10c0/3efbf791a911be0bf0821eab37a3445c2ba07acc1522b1fa84ae1e55f10425076f1290f680286345ed919549ad67527d07281f1c19d584df3b74326909eb1f90
+ languageName: node
+ linkType: hard
+
+"tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.13, tinyglobby@npm:^0.2.14, tinyglobby@npm:^0.2.15":
+ version: 0.2.15
+ resolution: "tinyglobby@npm:0.2.15"
+ dependencies:
+ fdir: "npm:^6.5.0"
+ picomatch: "npm:^4.0.3"
+ checksum: 10c0/869c31490d0d88eedb8305d178d4c75e7463e820df5a9b9d388291daf93e8b1eb5de1dad1c1e139767e4269fe75f3b10d5009b2cc14db96ff98986920a186844
+ languageName: node
+ linkType: hard
+
+"tinypool@npm:^1.1.1":
+ version: 1.1.1
+ resolution: "tinypool@npm:1.1.1"
+ checksum: 10c0/bf26727d01443061b04fa863f571016950888ea994ba0cd8cba3a1c51e2458d84574341ab8dbc3664f1c3ab20885c8cf9ff1cc4b18201f04c2cde7d317fff69b
+ languageName: node
+ linkType: hard
+
+"tinyrainbow@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "tinyrainbow@npm:2.0.0"
+ checksum: 10c0/c83c52bef4e0ae7fb8ec6a722f70b5b6fa8d8be1c85792e829f56c0e1be94ab70b293c032dc5048d4d37cfe678f1f5babb04bdc65fd123098800148ca989184f
+ languageName: node
+ linkType: hard
+
+"tinyspy@npm:^4.0.3":
+ version: 4.0.4
+ resolution: "tinyspy@npm:4.0.4"
+ checksum: 10c0/a8020fc17799251e06a8398dcc352601d2770aa91c556b9531ecd7a12581161fd1c14e81cbdaff0c1306c93bfdde8ff6d1c1a3f9bbe6d91604f0fd4e01e2f1eb
+ languageName: node
+ linkType: hard
+
+"to-regex-range@npm:^5.0.1":
+ version: 5.0.1
+ resolution: "to-regex-range@npm:5.0.1"
+ dependencies:
+ is-number: "npm:^7.0.0"
+ checksum: 10c0/487988b0a19c654ff3e1961b87f471702e708fa8a8dd02a298ef16da7206692e8552a0250e8b3e8759270f62e9d8314616f6da274734d3b558b1fc7b7724e892
+ languageName: node
+ linkType: hard
+
+"trim-lines@npm:^3.0.0":
+ version: 3.0.1
+ resolution: "trim-lines@npm:3.0.1"
+ checksum: 10c0/3a1611fa9e52aa56a94c69951a9ea15b8aaad760eaa26c56a65330dc8adf99cb282fc07cc9d94968b7d4d88003beba220a7278bbe2063328eb23fb56f9509e94
+ languageName: node
+ linkType: hard
+
+"trough@npm:^2.0.0":
+ version: 2.2.0
+ resolution: "trough@npm:2.2.0"
+ checksum: 10c0/58b671fc970e7867a48514168894396dd94e6d9d6456aca427cc299c004fe67f35ed7172a36449086b2edde10e78a71a284ec0076809add6834fb8f857ccb9b0
+ languageName: node
+ linkType: hard
+
+"ts-api-utils@npm:^2.4.0":
+ version: 2.4.0
+ resolution: "ts-api-utils@npm:2.4.0"
+ peerDependencies:
+ typescript: ">=4.8.4"
+ checksum: 10c0/ed185861aef4e7124366a3f6561113557a57504267d4d452a51e0ba516a9b6e713b56b4aeaab9fa13de9db9ab755c65c8c13a777dba9133c214632cb7b65c083
+ languageName: node
+ linkType: hard
+
+"tsconfig-paths@npm:^3.15.0":
+ version: 3.15.0
+ resolution: "tsconfig-paths@npm:3.15.0"
+ dependencies:
+ "@types/json5": "npm:^0.0.29"
+ json5: "npm:^1.0.2"
+ minimist: "npm:^1.2.6"
+ strip-bom: "npm:^3.0.0"
+ checksum: 10c0/5b4f301a2b7a3766a986baf8fc0e177eb80bdba6e396792ff92dc23b5bca8bb279fc96517dcaaef63a3b49bebc6c4c833653ec58155780bc906bdbcf7dda0ef5
+ languageName: node
+ linkType: hard
+
+"tslib@npm:^2.0.0, tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.8.0, tslib@npm:^2.8.1":
+ version: 2.8.1
+ resolution: "tslib@npm:2.8.1"
+ checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62
+ languageName: node
+ linkType: hard
+
+"type-check@npm:^0.4.0, type-check@npm:~0.4.0":
+ version: 0.4.0
+ resolution: "type-check@npm:0.4.0"
+ dependencies:
+ prelude-ls: "npm:^1.2.1"
+ checksum: 10c0/7b3fd0ed43891e2080bf0c5c504b418fbb3e5c7b9708d3d015037ba2e6323a28152ec163bcb65212741fa5d2022e3075ac3c76440dbd344c9035f818e8ecee58
+ languageName: node
+ linkType: hard
+
+"typed-array-buffer@npm:^1.0.3":
+ version: 1.0.3
+ resolution: "typed-array-buffer@npm:1.0.3"
+ dependencies:
+ call-bound: "npm:^1.0.3"
+ es-errors: "npm:^1.3.0"
+ is-typed-array: "npm:^1.1.14"
+ checksum: 10c0/1105071756eb248774bc71646bfe45b682efcad93b55532c6ffa4518969fb6241354e4aa62af679ae83899ec296d69ef88f1f3763657cdb3a4d29321f7b83079
+ languageName: node
+ linkType: hard
+
+"typed-array-byte-length@npm:^1.0.3":
+ version: 1.0.3
+ resolution: "typed-array-byte-length@npm:1.0.3"
+ dependencies:
+ call-bind: "npm:^1.0.8"
+ for-each: "npm:^0.3.3"
+ gopd: "npm:^1.2.0"
+ has-proto: "npm:^1.2.0"
+ is-typed-array: "npm:^1.1.14"
+ checksum: 10c0/6ae083c6f0354f1fce18b90b243343b9982affd8d839c57bbd2c174a5d5dc71be9eb7019ffd12628a96a4815e7afa85d718d6f1e758615151d5f35df841ffb3e
+ languageName: node
+ linkType: hard
+
+"typed-array-byte-offset@npm:^1.0.4":
+ version: 1.0.4
+ resolution: "typed-array-byte-offset@npm:1.0.4"
+ dependencies:
+ available-typed-arrays: "npm:^1.0.7"
+ call-bind: "npm:^1.0.8"
+ for-each: "npm:^0.3.3"
+ gopd: "npm:^1.2.0"
+ has-proto: "npm:^1.2.0"
+ is-typed-array: "npm:^1.1.15"
+ reflect.getprototypeof: "npm:^1.0.9"
+ checksum: 10c0/3d805b050c0c33b51719ee52de17c1cd8e6a571abdf0fffb110e45e8dd87a657e8b56eee94b776b13006d3d347a0c18a730b903cf05293ab6d92e99ff8f77e53
+ languageName: node
+ linkType: hard
+
+"typed-array-length@npm:^1.0.7":
+ version: 1.0.7
+ resolution: "typed-array-length@npm:1.0.7"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ for-each: "npm:^0.3.3"
+ gopd: "npm:^1.0.1"
+ is-typed-array: "npm:^1.1.13"
+ possible-typed-array-names: "npm:^1.0.0"
+ reflect.getprototypeof: "npm:^1.0.6"
+ checksum: 10c0/e38f2ae3779584c138a2d8adfa8ecf749f494af3cd3cdafe4e688ce51418c7d2c5c88df1bd6be2bbea099c3f7cea58c02ca02ed438119e91f162a9de23f61295
+ languageName: node
+ linkType: hard
+
+"typescript@npm:^5.8.2":
+ version: 5.9.3
+ resolution: "typescript@npm:5.9.3"
+ bin:
+ tsc: bin/tsc
+ tsserver: bin/tsserver
+ checksum: 10c0/6bd7552ce39f97e711db5aa048f6f9995b53f1c52f7d8667c1abdc1700c68a76a308f579cd309ce6b53646deb4e9a1be7c813a93baaf0a28ccd536a30270e1c5
+ languageName: node
+ linkType: hard
+
+"typescript@patch:typescript@npm%3A^5.8.2#optional!builtin":
+ version: 5.9.3
+ resolution: "typescript@patch:typescript@npm%3A5.9.3#optional!builtin::version=5.9.3&hash=5786d5"
+ bin:
+ tsc: bin/tsc
+ tsserver: bin/tsserver
+ checksum: 10c0/ad09fdf7a756814dce65bc60c1657b40d44451346858eea230e10f2e95a289d9183b6e32e5c11e95acc0ccc214b4f36289dcad4bf1886b0adb84d711d336a430
+ languageName: node
+ linkType: hard
+
+"unbox-primitive@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "unbox-primitive@npm:1.1.0"
+ dependencies:
+ call-bound: "npm:^1.0.3"
+ has-bigints: "npm:^1.0.2"
+ has-symbols: "npm:^1.1.0"
+ which-boxed-primitive: "npm:^1.1.1"
+ checksum: 10c0/7dbd35ab02b0e05fe07136c72cb9355091242455473ec15057c11430129bab38b7b3624019b8778d02a881c13de44d63cd02d122ee782fb519e1de7775b5b982
+ languageName: node
+ linkType: hard
+
+"undici-types@npm:~6.21.0":
+ version: 6.21.0
+ resolution: "undici-types@npm:6.21.0"
+ checksum: 10c0/c01ed51829b10aa72fc3ce64b747f8e74ae9b60eafa19a7b46ef624403508a54c526ffab06a14a26b3120d055e1104d7abe7c9017e83ced038ea5cf52f8d5e04
+ languageName: node
+ linkType: hard
+
+"undici-types@npm:~7.18.0":
+ version: 7.18.2
+ resolution: "undici-types@npm:7.18.2"
+ checksum: 10c0/85a79189113a238959d7a647368e4f7c5559c3a404ebdb8fc4488145ce9426fcd82252a844a302798dfc0e37e6fb178ff481ed03bc4caf634c5757d9ef43521d
+ languageName: node
+ linkType: hard
+
+"unified@npm:^11.0.0":
+ version: 11.0.5
+ resolution: "unified@npm:11.0.5"
+ dependencies:
+ "@types/unist": "npm:^3.0.0"
+ bail: "npm:^2.0.0"
+ devlop: "npm:^1.0.0"
+ extend: "npm:^3.0.0"
+ is-plain-obj: "npm:^4.0.0"
+ trough: "npm:^2.0.0"
+ vfile: "npm:^6.0.0"
+ checksum: 10c0/53c8e685f56d11d9d458a43e0e74328a4d6386af51c8ac37a3dcabec74ce5026da21250590d4aff6733ccd7dc203116aae2b0769abc18cdf9639a54ae528dfc9
+ languageName: node
+ linkType: hard
+
+"unique-filename@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "unique-filename@npm:5.0.0"
+ dependencies:
+ unique-slug: "npm:^6.0.0"
+ checksum: 10c0/afb897e9cf4c2fb622ea716f7c2bb462001928fc5f437972213afdf1cc32101a230c0f1e9d96fc91ee5185eca0f2feb34127145874975f347be52eb91d6ccc2c
+ languageName: node
+ linkType: hard
+
+"unique-slug@npm:^6.0.0":
+ version: 6.0.0
+ resolution: "unique-slug@npm:6.0.0"
+ dependencies:
+ imurmurhash: "npm:^0.1.4"
+ checksum: 10c0/da7ade4cb04eb33ad0499861f82fe95ce9c7c878b7139dc54d140ecfb6a6541c18a5c8dac16188b8b379fe62c0c1f1b710814baac910cde5f4fec06212126c6a
+ languageName: node
+ linkType: hard
+
+"unist-util-find-after@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "unist-util-find-after@npm:5.0.0"
+ dependencies:
+ "@types/unist": "npm:^3.0.0"
+ unist-util-is: "npm:^6.0.0"
+ checksum: 10c0/a7cea473c4384df8de867c456b797ff1221b20f822e1af673ff5812ed505358b36f47f3b084ac14c3622cb879ed833b71b288e8aa71025352a2aab4c2925a6eb
+ languageName: node
+ linkType: hard
+
+"unist-util-is@npm:^6.0.0":
+ version: 6.0.1
+ resolution: "unist-util-is@npm:6.0.1"
+ dependencies:
+ "@types/unist": "npm:^3.0.0"
+ checksum: 10c0/5a487d390193811d37a68264e204dbc7c15c40b8fc29b5515a535d921d071134f571d7b5cbd59bcd58d5ce1c0ab08f20fc4a1f0df2287a249c979267fc32ce06
+ languageName: node
+ linkType: hard
+
+"unist-util-position@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "unist-util-position@npm:5.0.0"
+ dependencies:
+ "@types/unist": "npm:^3.0.0"
+ checksum: 10c0/dde3b31e314c98f12b4dc6402f9722b2bf35e96a4f2d463233dd90d7cde2d4928074a7a11eff0a5eb1f4e200f27fc1557e0a64a7e8e4da6558542f251b1b7400
+ languageName: node
+ linkType: hard
+
+"unist-util-stringify-position@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "unist-util-stringify-position@npm:4.0.0"
+ dependencies:
+ "@types/unist": "npm:^3.0.0"
+ checksum: 10c0/dfe1dbe79ba31f589108cb35e523f14029b6675d741a79dea7e5f3d098785045d556d5650ec6a8338af11e9e78d2a30df12b1ee86529cded1098da3f17ee999e
+ languageName: node
+ linkType: hard
+
+"unist-util-visit-parents@npm:^6.0.0":
+ version: 6.0.2
+ resolution: "unist-util-visit-parents@npm:6.0.2"
+ dependencies:
+ "@types/unist": "npm:^3.0.0"
+ unist-util-is: "npm:^6.0.0"
+ checksum: 10c0/f1e4019dbd930301825895e3737b1ee0cd682f7622ddd915062135cbb39f8c090aaece3a3b5eae1f2ea52ec33f0931abb8f8a8b5c48a511a4203e3d360a8cd49
+ languageName: node
+ linkType: hard
+
+"unist-util-visit@npm:^5.0.0":
+ version: 5.1.0
+ resolution: "unist-util-visit@npm:5.1.0"
+ dependencies:
+ "@types/unist": "npm:^3.0.0"
+ unist-util-is: "npm:^6.0.0"
+ unist-util-visit-parents: "npm:^6.0.0"
+ checksum: 10c0/a56e1bbbf63fcb55abe379e660b9a3367787e8be1e2473bdb7e86cfa6f32b6c1fa0092432d7040b8a30b2fc674bbbe024ffe6d03c3d6bf4839b064f584463a4e
+ languageName: node
+ linkType: hard
+
+"unrs-resolver@npm:^1.6.2":
+ version: 1.11.1
+ resolution: "unrs-resolver@npm:1.11.1"
+ dependencies:
+ "@unrs/resolver-binding-android-arm-eabi": "npm:1.11.1"
+ "@unrs/resolver-binding-android-arm64": "npm:1.11.1"
+ "@unrs/resolver-binding-darwin-arm64": "npm:1.11.1"
+ "@unrs/resolver-binding-darwin-x64": "npm:1.11.1"
+ "@unrs/resolver-binding-freebsd-x64": "npm:1.11.1"
+ "@unrs/resolver-binding-linux-arm-gnueabihf": "npm:1.11.1"
+ "@unrs/resolver-binding-linux-arm-musleabihf": "npm:1.11.1"
+ "@unrs/resolver-binding-linux-arm64-gnu": "npm:1.11.1"
+ "@unrs/resolver-binding-linux-arm64-musl": "npm:1.11.1"
+ "@unrs/resolver-binding-linux-ppc64-gnu": "npm:1.11.1"
+ "@unrs/resolver-binding-linux-riscv64-gnu": "npm:1.11.1"
+ "@unrs/resolver-binding-linux-riscv64-musl": "npm:1.11.1"
+ "@unrs/resolver-binding-linux-s390x-gnu": "npm:1.11.1"
+ "@unrs/resolver-binding-linux-x64-gnu": "npm:1.11.1"
+ "@unrs/resolver-binding-linux-x64-musl": "npm:1.11.1"
+ "@unrs/resolver-binding-wasm32-wasi": "npm:1.11.1"
+ "@unrs/resolver-binding-win32-arm64-msvc": "npm:1.11.1"
+ "@unrs/resolver-binding-win32-ia32-msvc": "npm:1.11.1"
+ "@unrs/resolver-binding-win32-x64-msvc": "npm:1.11.1"
+ napi-postinstall: "npm:^0.3.0"
+ dependenciesMeta:
+ "@unrs/resolver-binding-android-arm-eabi":
+ optional: true
+ "@unrs/resolver-binding-android-arm64":
+ optional: true
+ "@unrs/resolver-binding-darwin-arm64":
+ optional: true
+ "@unrs/resolver-binding-darwin-x64":
+ optional: true
+ "@unrs/resolver-binding-freebsd-x64":
+ optional: true
+ "@unrs/resolver-binding-linux-arm-gnueabihf":
+ optional: true
+ "@unrs/resolver-binding-linux-arm-musleabihf":
+ optional: true
+ "@unrs/resolver-binding-linux-arm64-gnu":
+ optional: true
+ "@unrs/resolver-binding-linux-arm64-musl":
+ optional: true
+ "@unrs/resolver-binding-linux-ppc64-gnu":
+ optional: true
+ "@unrs/resolver-binding-linux-riscv64-gnu":
+ optional: true
+ "@unrs/resolver-binding-linux-riscv64-musl":
+ optional: true
+ "@unrs/resolver-binding-linux-s390x-gnu":
+ optional: true
+ "@unrs/resolver-binding-linux-x64-gnu":
+ optional: true
+ "@unrs/resolver-binding-linux-x64-musl":
+ optional: true
+ "@unrs/resolver-binding-wasm32-wasi":
+ optional: true
+ "@unrs/resolver-binding-win32-arm64-msvc":
+ optional: true
+ "@unrs/resolver-binding-win32-ia32-msvc":
+ optional: true
+ "@unrs/resolver-binding-win32-x64-msvc":
+ optional: true
+ checksum: 10c0/c91b112c71a33d6b24e5c708dab43ab80911f2df8ee65b87cd7a18fb5af446708e98c4b415ca262026ad8df326debcc7ca6a801b2935504d87fd6f0b9d70dce1
+ languageName: node
+ linkType: hard
+
+"update-browserslist-db@npm:^1.2.0":
+ version: 1.2.3
+ resolution: "update-browserslist-db@npm:1.2.3"
+ dependencies:
+ escalade: "npm:^3.2.0"
+ picocolors: "npm:^1.1.1"
+ peerDependencies:
+ browserslist: ">= 4.21.0"
+ bin:
+ update-browserslist-db: cli.js
+ checksum: 10c0/13a00355ea822388f68af57410ce3255941d5fb9b7c49342c4709a07c9f230bbef7f7499ae0ca7e0de532e79a82cc0c4edbd125f1a323a1845bf914efddf8bec
+ languageName: node
+ linkType: hard
+
+"uri-js@npm:^4.2.2":
+ version: 4.4.1
+ resolution: "uri-js@npm:4.4.1"
+ dependencies:
+ punycode: "npm:^2.1.0"
+ checksum: 10c0/4ef57b45aa820d7ac6496e9208559986c665e49447cb072744c13b66925a362d96dd5a46c4530a6b8e203e5db5fe849369444440cb22ecfc26c679359e5dfa3c
+ languageName: node
+ linkType: hard
+
+"use-callback-ref@npm:^1.3.3":
+ version: 1.3.3
+ resolution: "use-callback-ref@npm:1.3.3"
+ dependencies:
+ tslib: "npm:^2.0.0"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/f887488c6e6075cdad4962979da1714b217bcb1ee009a9e57ce9a844bcfc4c3a99e93983dfc2e5af9e0913824d24e730090ff255e902c516dcb58d2d3837e01c
+ languageName: node
+ linkType: hard
+
+"use-sidecar@npm:^1.1.3":
+ version: 1.1.3
+ resolution: "use-sidecar@npm:1.1.3"
+ dependencies:
+ detect-node-es: "npm:^1.1.0"
+ tslib: "npm:^2.0.0"
+ peerDependencies:
+ "@types/react": "*"
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/161599bf921cfaa41c85d2b01c871975ee99260f3e874c2d41c05890d41170297bdcf314bc5185e7a700de2034ac5b888e3efc8e9f35724f4918f53538d717c9
+ languageName: node
+ linkType: hard
+
+"use-sync-external-store@npm:^1.2.2, use-sync-external-store@npm:^1.4.0, use-sync-external-store@npm:^1.5.0":
+ version: 1.6.0
+ resolution: "use-sync-external-store@npm:1.6.0"
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+ checksum: 10c0/35e1179f872a53227bdf8a827f7911da4c37c0f4091c29b76b1e32473d1670ebe7bcd880b808b7549ba9a5605c233350f800ffab963ee4a4ee346ee983b6019b
+ languageName: node
+ linkType: hard
+
+"vfile-message@npm:^4.0.0":
+ version: 4.0.3
+ resolution: "vfile-message@npm:4.0.3"
+ dependencies:
+ "@types/unist": "npm:^3.0.0"
+ unist-util-stringify-position: "npm:^4.0.0"
+ checksum: 10c0/33d9f219610d27987689bb14fa5573d2daa146941d1a05416dd7702c4215b23f44ed81d059e70d0e4e24f9a57d5f4dc9f18d35a993f04cf9446a7abe6d72d0c0
+ languageName: node
+ linkType: hard
+
+"vfile@npm:^6.0.0":
+ version: 6.0.3
+ resolution: "vfile@npm:6.0.3"
+ dependencies:
+ "@types/unist": "npm:^3.0.0"
+ vfile-message: "npm:^4.0.0"
+ checksum: 10c0/e5d9eb4810623f23758cfc2205323e33552fb5972e5c2e6587babe08fe4d24859866277404fb9e2a20afb71013860d96ec806cb257536ae463c87d70022ab9ef
+ languageName: node
+ linkType: hard
+
+"victory-vendor@npm:^37.0.2":
+ version: 37.3.6
+ resolution: "victory-vendor@npm:37.3.6"
+ dependencies:
+ "@types/d3-array": "npm:^3.0.3"
+ "@types/d3-ease": "npm:^3.0.0"
+ "@types/d3-interpolate": "npm:^3.0.1"
+ "@types/d3-scale": "npm:^4.0.2"
+ "@types/d3-shape": "npm:^3.1.0"
+ "@types/d3-time": "npm:^3.0.0"
+ "@types/d3-timer": "npm:^3.0.0"
+ d3-array: "npm:^3.1.6"
+ d3-ease: "npm:^3.0.1"
+ d3-interpolate: "npm:^3.0.1"
+ d3-scale: "npm:^4.0.2"
+ d3-shape: "npm:^3.1.0"
+ d3-time: "npm:^3.0.0"
+ d3-timer: "npm:^3.0.1"
+ checksum: 10c0/0a9628db30b898160409628f26d457ba15adc86472531817d73fbeb847de498d94f91dee5f4caa969195744e91be93e100eeff7a392b591ac5349343a36dec29
+ languageName: node
+ linkType: hard
+
+"vite-node@npm:3.2.4":
+ version: 3.2.4
+ resolution: "vite-node@npm:3.2.4"
+ dependencies:
+ cac: "npm:^6.7.14"
+ debug: "npm:^4.4.1"
+ es-module-lexer: "npm:^1.7.0"
+ pathe: "npm:^2.0.3"
+ vite: "npm:^5.0.0 || ^6.0.0 || ^7.0.0-0"
+ bin:
+ vite-node: vite-node.mjs
+ checksum: 10c0/6ceca67c002f8ef6397d58b9539f80f2b5d79e103a18367288b3f00a8ab55affa3d711d86d9112fce5a7fa658a212a087a005a045eb8f4758947dd99af2a6c6b
+ languageName: node
+ linkType: hard
+
+"vite@npm:^5.0.0 || ^6.0.0 || ^7.0.0-0":
+ version: 7.3.1
+ resolution: "vite@npm:7.3.1"
+ dependencies:
+ esbuild: "npm:^0.27.0"
+ fdir: "npm:^6.5.0"
+ fsevents: "npm:~2.3.3"
+ picomatch: "npm:^4.0.3"
+ postcss: "npm:^8.5.6"
+ rollup: "npm:^4.43.0"
+ tinyglobby: "npm:^0.2.15"
+ peerDependencies:
+ "@types/node": ^20.19.0 || >=22.12.0
+ jiti: ">=1.21.0"
+ less: ^4.0.0
+ lightningcss: ^1.21.0
+ sass: ^1.70.0
+ sass-embedded: ^1.70.0
+ stylus: ">=0.54.8"
+ sugarss: ^5.0.0
+ terser: ^5.16.0
+ tsx: ^4.8.1
+ yaml: ^2.4.2
+ dependenciesMeta:
+ fsevents:
+ optional: true
+ peerDependenciesMeta:
+ "@types/node":
+ optional: true
+ jiti:
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+ bin:
+ vite: bin/vite.js
+ checksum: 10c0/5c7548f5f43a23533e53324304db4ad85f1896b1bfd3ee32ae9b866bac2933782c77b350eb2b52a02c625c8ad1ddd4c000df077419410650c982cd97fde8d014
+ languageName: node
+ linkType: hard
+
+"vitest@npm:^3.1.1":
+ version: 3.2.4
+ resolution: "vitest@npm:3.2.4"
+ dependencies:
+ "@types/chai": "npm:^5.2.2"
+ "@vitest/expect": "npm:3.2.4"
+ "@vitest/mocker": "npm:3.2.4"
+ "@vitest/pretty-format": "npm:^3.2.4"
+ "@vitest/runner": "npm:3.2.4"
+ "@vitest/snapshot": "npm:3.2.4"
+ "@vitest/spy": "npm:3.2.4"
+ "@vitest/utils": "npm:3.2.4"
+ chai: "npm:^5.2.0"
+ debug: "npm:^4.4.1"
+ expect-type: "npm:^1.2.1"
+ magic-string: "npm:^0.30.17"
+ pathe: "npm:^2.0.3"
+ picomatch: "npm:^4.0.2"
+ std-env: "npm:^3.9.0"
+ tinybench: "npm:^2.9.0"
+ tinyexec: "npm:^0.3.2"
+ tinyglobby: "npm:^0.2.14"
+ tinypool: "npm:^1.1.1"
+ tinyrainbow: "npm:^2.0.0"
+ vite: "npm:^5.0.0 || ^6.0.0 || ^7.0.0-0"
+ vite-node: "npm:3.2.4"
+ why-is-node-running: "npm:^2.3.0"
+ peerDependencies:
+ "@edge-runtime/vm": "*"
+ "@types/debug": ^4.1.12
+ "@types/node": ^18.0.0 || ^20.0.0 || >=22.0.0
+ "@vitest/browser": 3.2.4
+ "@vitest/ui": 3.2.4
+ happy-dom: "*"
+ jsdom: "*"
+ peerDependenciesMeta:
+ "@edge-runtime/vm":
+ optional: true
+ "@types/debug":
+ optional: true
+ "@types/node":
+ optional: true
+ "@vitest/browser":
+ optional: true
+ "@vitest/ui":
+ optional: true
+ happy-dom:
+ optional: true
+ jsdom:
+ optional: true
+ bin:
+ vitest: vitest.mjs
+ checksum: 10c0/5bf53ede3ae6a0e08956d72dab279ae90503f6b5a05298a6a5e6ef47d2fd1ab386aaf48fafa61ed07a0ebfe9e371772f1ccbe5c258dd765206a8218bf2eb79eb
+ languageName: node
+ linkType: hard
+
+"which-boxed-primitive@npm:^1.1.0, which-boxed-primitive@npm:^1.1.1":
+ version: 1.1.1
+ resolution: "which-boxed-primitive@npm:1.1.1"
+ dependencies:
+ is-bigint: "npm:^1.1.0"
+ is-boolean-object: "npm:^1.2.1"
+ is-number-object: "npm:^1.1.1"
+ is-string: "npm:^1.1.1"
+ is-symbol: "npm:^1.1.1"
+ checksum: 10c0/aceea8ede3b08dede7dce168f3883323f7c62272b49801716e8332ff750e7ae59a511ae088840bc6874f16c1b7fd296c05c949b0e5b357bfe3c431b98c417abe
+ languageName: node
+ linkType: hard
+
+"which-builtin-type@npm:^1.2.1":
+ version: 1.2.1
+ resolution: "which-builtin-type@npm:1.2.1"
+ dependencies:
+ call-bound: "npm:^1.0.2"
+ function.prototype.name: "npm:^1.1.6"
+ has-tostringtag: "npm:^1.0.2"
+ is-async-function: "npm:^2.0.0"
+ is-date-object: "npm:^1.1.0"
+ is-finalizationregistry: "npm:^1.1.0"
+ is-generator-function: "npm:^1.0.10"
+ is-regex: "npm:^1.2.1"
+ is-weakref: "npm:^1.0.2"
+ isarray: "npm:^2.0.5"
+ which-boxed-primitive: "npm:^1.1.0"
+ which-collection: "npm:^1.0.2"
+ which-typed-array: "npm:^1.1.16"
+ checksum: 10c0/8dcf323c45e5c27887800df42fbe0431d0b66b1163849bb7d46b5a730ad6a96ee8bfe827d078303f825537844ebf20c02459de41239a0a9805e2fcb3cae0d471
+ languageName: node
+ linkType: hard
+
+"which-collection@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "which-collection@npm:1.0.2"
+ dependencies:
+ is-map: "npm:^2.0.3"
+ is-set: "npm:^2.0.3"
+ is-weakmap: "npm:^2.0.2"
+ is-weakset: "npm:^2.0.3"
+ checksum: 10c0/3345fde20964525a04cdf7c4a96821f85f0cc198f1b2ecb4576e08096746d129eb133571998fe121c77782ac8f21cbd67745a3d35ce100d26d4e684c142ea1f2
+ languageName: node
+ linkType: hard
+
+"which-typed-array@npm:^1.1.16, which-typed-array@npm:^1.1.19":
+ version: 1.1.20
+ resolution: "which-typed-array@npm:1.1.20"
+ dependencies:
+ available-typed-arrays: "npm:^1.0.7"
+ call-bind: "npm:^1.0.8"
+ call-bound: "npm:^1.0.4"
+ for-each: "npm:^0.3.5"
+ get-proto: "npm:^1.0.1"
+ gopd: "npm:^1.2.0"
+ has-tostringtag: "npm:^1.0.2"
+ checksum: 10c0/16fcdada95c8afb821cd1117f0ab50b4d8551677ac08187f21d4e444530913c9ffd2dac634f0c1183345f96344b69280f40f9a8bc52164ef409e555567c2604b
+ languageName: node
+ linkType: hard
+
+"which@npm:^2.0.1":
+ version: 2.0.2
+ resolution: "which@npm:2.0.2"
+ dependencies:
+ isexe: "npm:^2.0.0"
+ bin:
+ node-which: ./bin/node-which
+ checksum: 10c0/66522872a768b60c2a65a57e8ad184e5372f5b6a9ca6d5f033d4b0dc98aff63995655a7503b9c0a2598936f532120e81dd8cc155e2e92ed662a2b9377cc4374f
+ languageName: node
+ linkType: hard
+
+"which@npm:^6.0.0":
+ version: 6.0.1
+ resolution: "which@npm:6.0.1"
+ dependencies:
+ isexe: "npm:^4.0.0"
+ bin:
+ node-which: bin/which.js
+ checksum: 10c0/7e710e54ea36d2d6183bee2f9caa27a3b47b9baf8dee55a199b736fcf85eab3b9df7556fca3d02b50af7f3dfba5ea3a45644189836df06267df457e354da66d5
+ languageName: node
+ linkType: hard
+
+"why-is-node-running@npm:^2.3.0":
+ version: 2.3.0
+ resolution: "why-is-node-running@npm:2.3.0"
+ dependencies:
+ siginfo: "npm:^2.0.0"
+ stackback: "npm:0.0.2"
+ bin:
+ why-is-node-running: cli.js
+ checksum: 10c0/1cde0b01b827d2cf4cb11db962f3958b9175d5d9e7ac7361d1a7b0e2dc6069a263e69118bd974c4f6d0a890ef4eedfe34cf3d5167ec14203dbc9a18620537054
+ languageName: node
+ linkType: hard
+
+"word-wrap@npm:^1.2.5":
+ version: 1.2.5
+ resolution: "word-wrap@npm:1.2.5"
+ checksum: 10c0/e0e4a1ca27599c92a6ca4c32260e8a92e8a44f4ef6ef93f803f8ed823f486e0889fc0b93be4db59c8d51b3064951d25e43d434e95dc8c960cc3a63d65d00ba20
+ languageName: node
+ linkType: hard
+
+"yallist@npm:^3.0.2":
+ version: 3.1.1
+ resolution: "yallist@npm:3.1.1"
+ checksum: 10c0/c66a5c46bc89af1625476f7f0f2ec3653c1a1791d2f9407cfb4c2ba812a1e1c9941416d71ba9719876530e3340a99925f697142989371b72d93b9ee628afd8c1
+ languageName: node
+ linkType: hard
+
+"yallist@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "yallist@npm:4.0.0"
+ checksum: 10c0/2286b5e8dbfe22204ab66e2ef5cc9bbb1e55dfc873bbe0d568aa943eb255d131890dfd5bf243637273d31119b870f49c18fcde2c6ffbb7a7a092b870dc90625a
+ languageName: node
+ linkType: hard
+
+"yallist@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "yallist@npm:5.0.0"
+ checksum: 10c0/a499c81ce6d4a1d260d4ea0f6d49ab4da09681e32c3f0472dee16667ed69d01dae63a3b81745a24bd78476ec4fcf856114cb4896ace738e01da34b2c42235416
+ languageName: node
+ linkType: hard
+
+"yocto-queue@npm:^0.1.0":
+ version: 0.1.0
+ resolution: "yocto-queue@npm:0.1.0"
+ checksum: 10c0/dceb44c28578b31641e13695d200d34ec4ab3966a5729814d5445b194933c096b7ced71494ce53a0e8820685d1d010df8b2422e5bf2cdea7e469d97ffbea306f
+ languageName: node
+ linkType: hard
+
+"zod@npm:^4.1.12":
+ version: 4.3.6
+ resolution: "zod@npm:4.3.6"
+ checksum: 10c0/860d25a81ab41d33aa25f8d0d07b091a04acb426e605f396227a796e9e800c44723ed96d0f53a512b57be3d1520f45bf69c0cb3b378a232a00787a2609625307
+ languageName: node
+ linkType: hard
+
+"zwitch@npm:^2.0.0":
+ version: 2.0.4
+ resolution: "zwitch@npm:2.0.4"
+ checksum: 10c0/3c7830cdd3378667e058ffdb4cf2bb78ac5711214e2725900873accb23f3dfe5f9e7e5a06dcdc5f29605da976fc45c26d9a13ca334d6eea2245a15e77b8fc06e
+ languageName: node
+ linkType: hard
diff --git a/install.sh b/install.sh
index a75f7d7..aaec10d 100755
--- a/install.sh
+++ b/install.sh
@@ -241,7 +241,8 @@ else
# Try pre-built images from ghcr.io, fall back to local build
PROD_COMPOSE="$SCRIPT_DIR/docker-compose.prod.yml"
if docker pull "$GHCR_PREFIX-mcp-server:latest" >/dev/null 2>&1 && \
- docker pull "$GHCR_PREFIX-ui:latest" >/dev/null 2>&1; then
+ docker pull "$GHCR_PREFIX-api:latest" >/dev/null 2>&1 && \
+ docker pull "$GHCR_PREFIX-frontend:latest" >/dev/null 2>&1; then
ok "Pulled pre-built images from ghcr.io"
COMPOSE_FILE="$PROD_COMPOSE"
info "Starting Docker services (pre-built)..."
@@ -261,7 +262,7 @@ import sys, json
lines = sys.stdin.read().strip().split('\n')
services = [json.loads(l) for l in lines if l.strip()]
healthy = all(s.get('Health','') == 'healthy' or s.get('State','') == 'running' for s in services)
-sys.exit(0 if healthy and len(services) >= 3 else 1)
+sys.exit(0 if healthy and len(services) >= 4 else 1)
" 2>/dev/null; then
break
fi
@@ -321,16 +322,23 @@ else
fi
if curl -sf http://localhost:8088/health -o /dev/null 2>/dev/null; then
- ok "Web UI responding (http://localhost:8088)"
+ ok "Python API responding (http://localhost:8088)"
else
- warn "Web UI not responding yet — may still be starting"
+ warn "Python API not responding yet — may still be starting"
+fi
+
+if curl -sf http://localhost:3000/ -o /dev/null 2>/dev/null; then
+ ok "Frontend responding (http://localhost:3000)"
+else
+ warn "Frontend not responding yet — may still be starting"
fi
# ─── Done ────────────────────────────────────────────────────────────
echo ""
echo -e "${GREEN}PRDforge installed successfully!${NC}"
echo ""
-echo " Web UI: http://localhost:8088"
+echo " Frontend: http://localhost:3000"
+echo " Python API: http://localhost:8088"
echo " MCP Server: http://localhost:8080/mcp/"
echo ""
if [ "$MODE" = "code" ]; then
diff --git a/mcp_server/server.py b/mcp_server/server.py
index 4223213..9bb8ab1 100644
--- a/mcp_server/server.py
+++ b/mcp_server/server.py
@@ -14,7 +14,9 @@
from mcp.server.fastmcp import FastMCP
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
+from shared.constants import VALID_SECTION_TYPES, SECTION_TYPE_ALIASES
from shared.settings import DEFAULT_PROJECT_SETTINGS, SETTINGS_SCHEMA, validate_settings
+from shared.project_factory import create_project_with_template
logger = logging.getLogger("prd_forge_mcp")
logging.basicConfig(
@@ -27,21 +29,7 @@
MAX_SLUG = 100
VALID_STATUSES = {"draft", "in_progress", "review", "approved", "outdated"}
VALID_DEP_TYPES = {"references", "implements", "blocks", "extends"}
-VALID_SECTION_TYPES = {
- "overview", "tech_spec", "data_model", "api_spec", "ui_design",
- "architecture", "deployment", "security", "testing", "timeline", "general",
-}
-SECTION_TYPE_ALIASES = {
- "requirement": "general",
- "requirements": "general",
- "functional_requirements": "tech_spec",
- "non_functional_requirements": "tech_spec",
- "api": "api_spec",
- "data": "data_model",
- "ui": "ui_design",
- "ux": "ui_design",
- "roadmap": "timeline",
-}
+# VALID_SECTION_TYPES and SECTION_TYPE_ALIASES imported from shared.constants
# --- Pool ---
_pool: asyncpg.Pool | None = None
@@ -204,19 +192,22 @@ async def prd_list_projects() -> str:
@mcp.tool(
annotations={"readOnlyHint": False, "destructiveHint": False, "idempotentHint": False, "openWorldHint": False}
)
-async def prd_create_project(name: str, slug: str, description: str = "") -> str:
- """Create a new PRD project. Slug must be unique, lowercase alphanumeric with hyphens."""
- slug_err = validate_slug(slug)
- if slug_err:
- return err(slug_err)
+async def prd_create_project(name: str, slug: str, description: str = "", template: str = "") -> str:
+ """Create a new PRD project. Slug must be unique, lowercase alphanumeric with hyphens.
+ Optional template: 'blank', 'saas-mvp', 'mobile-app', 'api-design'."""
try:
pool = await get_pool()
- row = await pool.fetchrow(
- "INSERT INTO projects (name, slug, description) VALUES ($1, $2, $3) RETURNING *",
- name, slug, description,
+ result = await create_project_with_template(
+ pool, name, slug, description,
+ template_id=template or None,
)
- logger.info("Created project: %s", slug)
- return ok({"created": row_to_dict(row)})
+ logger.info("Created project: %s (template=%s)", slug, template or "none")
+ pid = await resolve_project_id(pool, slug)
+ if pid:
+ await _record_activity(pool, pid, "prd_create_project", {"slug": slug, "template": template or "none"})
+ return ok({"created": result})
+ except ValueError as e:
+ return err(str(e))
except asyncpg.UniqueViolationError:
return err(f"project with slug '{slug}' already exists")
except Exception as e:
@@ -235,6 +226,7 @@ async def prd_delete_project(project: str) -> str:
if not pid:
return err(f"project '{project}' not found")
count = await pool.fetchval("SELECT COUNT(*) FROM sections WHERE project_id = $1", pid)
+ await _record_activity(pool, pid, "prd_delete_project", {"slug": project, "sections": count})
await pool.execute("DELETE FROM projects WHERE id = $1", pid)
logger.info("Deleted project: %s (%d sections)", project, count)
return ok({"deleted": project, "sections_removed": count})
@@ -298,7 +290,7 @@ async def prd_read_section(project: str, section: str) -> str:
)
depends_on = await pool.fetch("""
- SELECT s.slug, s.title, s.summary, s.status, s.tags,
+ SELECT s.id, s.slug, s.title, s.summary, s.status, s.tags,
d.dependency_type AS dep_type, d.description AS dep_reason
FROM section_dependencies d
JOIN sections s ON s.id = d.depends_on_id
@@ -306,7 +298,7 @@ async def prd_read_section(project: str, section: str) -> str:
""", sec_id)
depended_by = await pool.fetch("""
- SELECT s.slug, s.title, s.summary, s.status, s.tags,
+ SELECT s.id, s.slug, s.title, s.summary, s.status, s.tags,
d.dependency_type AS dep_type, d.description AS dep_reason
FROM section_dependencies d
JOIN sections s ON s.id = d.section_id
@@ -339,13 +331,20 @@ async def prd_read_section(project: str, section: str) -> str:
cd["replies"] = replies_by_comment.get(str(c["id"]), [])
comment_dicts.append(cd)
- # Track token savings
+ # Track token savings — granular section-level access
loaded_words = (sec["word_count"] or 0) + sum(
len((d["summary"] or "").split()) for d in depends_on
) + sum(
len((d["summary"] or "").split()) for d in depended_by
)
await _record_token_estimate(pool, pid, "read_section", loaded_words)
+ # New: section-level access log for honest dedup
+ accesses = [(sec_id, "full", sec["word_count"] or 0)]
+ for d in depends_on:
+ accesses.append((d["id"], "summary", len((d["summary"] or "").split())))
+ for d in depended_by:
+ accesses.append((d["id"], "summary", len((d["summary"] or "").split())))
+ await _record_section_access(pool, pid, "read_section", accesses)
return ok({
"section": row_to_dict(sec),
@@ -413,6 +412,7 @@ async def prd_create_section(
"Initial section creation",
)
+ await _record_activity(pool, pid, "prd_create_section", {"slug": slug, "title": title})
created = row_to_dict(row)
created.pop("id", None)
logger.info("Created section: %s/%s", project, slug)
@@ -531,6 +531,7 @@ async def prd_update_section(
""", valid_cids, row["id"])
resolved_ids = [str(r["id"]) for r in resolved_rows]
+ await _record_activity(pool, pid, "prd_update_section", {"slug": section, "fields": list(fields.keys())})
result = {"updated": row_to_dict(updated)}
if revision_created is not None:
result["revision_created"] = revision_created
@@ -566,6 +567,7 @@ async def prd_delete_section(project: str, section: str) -> str:
)
affected = [r["slug"] for r in depended_by]
+ await _record_activity(pool, pid, "prd_delete_section", {"slug": section})
await pool.execute("DELETE FROM sections WHERE id = $1", sec["id"])
result = {"deleted": section}
if affected:
@@ -629,6 +631,7 @@ async def prd_move_section(
f"UPDATE sections SET {', '.join(sets)} WHERE id = ${len(vals)}", *vals
)
+ await _record_activity(pool, pid, "prd_move_section", {"slug": section})
new_order = sort_order if sort_order is not None else sec["sort_order"]
return ok({"moved": {"slug": section, "title": sec["title"], "sort_order": new_order}})
except Exception as e:
@@ -667,6 +670,7 @@ async def prd_duplicate_section(
""", pid, new_slug, title, src["section_type"], src["sort_order"] + 1,
src["status"], src["content"], src["summary"], src["tags"], src["notes"])
+ await _record_activity(pool, pid, "prd_duplicate_section", {"from": section, "to": new_slug})
logger.info("Duplicated section: %s/%s → %s", project, section, new_slug)
return ok({"duplicated": row_to_dict(row), "from": section})
except asyncpg.UniqueViolationError:
@@ -708,6 +712,8 @@ async def prd_add_dependency(
""", section, depends_on, dependency_type, description, project)
if not row:
return err(f"sections '{section}' and/or '{depends_on}' not found in project '{project}'")
+ pid = await resolve_project_id(pool, project)
+ await _record_activity(pool, pid, "prd_add_dependency", {"from": section, "to": depends_on})
logger.info("Added dependency: %s/%s → %s", project, section, depends_on)
return ok({"dependency": {"from": section, "to": depends_on, "type": dependency_type}})
except Exception as e:
@@ -732,6 +738,8 @@ async def prd_remove_dependency(project: str, section: str, depends_on: str) ->
AND depends_on_id = (SELECT id FROM sections WHERE project_id = $1 AND slug = $3)
""", pid, section, depends_on)
removed = result.split()[-1] != "0"
+ if removed:
+ await _record_activity(pool, pid, "prd_remove_dependency", {"from": section, "to": depends_on})
return ok({"removed": removed, "from": section, "to": depends_on})
except Exception as e:
logger.error("prd_remove_dependency: %s", e)
@@ -802,6 +810,7 @@ async def prd_add_comment(
INSERT INTO section_comments (section_id, anchor_text, anchor_prefix, anchor_suffix, body)
VALUES ($1, $2, $3, $4, $5) RETURNING *
""", sec["id"], anchor_text, anchor_prefix, anchor_suffix, body)
+ await _record_activity(pool, pid, "prd_add_comment", {"section": section})
logger.info("Added comment on %s/%s: %.40s", project, section, anchor_text)
return ok({"created": row_to_dict(row)})
except Exception as e:
@@ -843,6 +852,8 @@ async def prd_delete_comment(project: str, section: str, comment_id: str) -> str
if not resolved:
return err(f"comment '{comment_id}' not found in {project}/{section}")
cid, _ = resolved
+ pid = await resolve_project_id(pool, project)
+ await _record_activity(pool, pid, "prd_delete_comment", {"section": section})
await pool.execute("DELETE FROM section_comments WHERE id = $1", cid)
logger.info("Deleted comment %s on %s/%s", comment_id, project, section)
return ok({"deleted": comment_id})
@@ -946,7 +957,7 @@ async def prd_get_overview(project: str) -> str:
return err(f"project '{project}' not found")
sections = await pool.fetch("""
- SELECT slug, title, section_type, status, summary, tags, word_count,
+ SELECT id, slug, title, section_type, status, summary, tags, word_count,
parent_slug, updated_at
FROM section_tree WHERE project_id = $1 ORDER BY sort_order
""", proj["id"])
@@ -967,6 +978,8 @@ async def prd_get_overview(project: str) -> str:
# Track token savings — overview loads summaries only
loaded_words = sum(len((s["summary"] or "").split()) for s in sections)
await _record_token_estimate(pool, proj["id"], "get_overview", loaded_words)
+ accesses = [(s["id"], "summary", len((s["summary"] or "").split())) for s in sections]
+ await _record_section_access(pool, proj["id"], "get_overview", accesses)
return ok({
"project": {
@@ -1004,16 +1017,18 @@ async def prd_search(project: str, query: str) -> str:
if query.startswith("tag:"):
tag = query[4:].strip()
rows = await pool.fetch("""
- SELECT slug, title, status, tags, summary
+ SELECT id, slug, title, status, tags, summary
FROM sections WHERE project_id = $1 AND $2 = ANY(tags)
ORDER BY sort_order
""", pid, tag)
loaded_words = sum(len((r["summary"] or "").split()) for r in rows)
await _record_token_estimate(pool, pid, "search", loaded_words)
+ accesses = [(r["id"], "summary", len((r["summary"] or "").split())) for r in rows]
+ await _record_section_access(pool, pid, "search", accesses)
return ok({"tag": tag, "results": [row_to_dict(r) for r in rows]})
else:
rows = await pool.fetch("""
- SELECT slug, title, section_type, status, tags,
+ SELECT id, slug, title, section_type, status, tags,
ts_rank(to_tsvector('english',
coalesce(title,'') || ' ' || coalesce(content,'') || ' ' || coalesce(notes,'')),
plainto_tsquery('english', $2)) AS rank,
@@ -1027,6 +1042,8 @@ async def prd_search(project: str, query: str) -> str:
""", pid, query)
loaded_words = sum(len((r["snippet"] or "").split()) for r in rows)
await _record_token_estimate(pool, pid, "search", loaded_words)
+ accesses = [(r["id"], "snippet", len((r["snippet"] or r.get("summary") or "").split())) for r in rows]
+ await _record_section_access(pool, pid, "search", accesses)
return ok({"query": query, "results": [row_to_dict(r) for r in rows]})
except Exception as e:
logger.error("prd_search: %s", e)
@@ -1390,6 +1407,8 @@ async def prd_bulk_status(
else:
updated.append(slug)
+ if updated:
+ await _record_activity(pool, pid, "prd_bulk_status", {"status": status, "count": len(updated)})
return ok({"status": status, "updated": updated, "not_found": not_found})
except Exception as e:
logger.error("prd_bulk_status: %s", e)
@@ -1398,8 +1417,19 @@ async def prd_bulk_status(
# --- Group 9: Token Stats ---
+async def _record_activity(pool, pid, tool_name: str, detail: dict | None = None):
+ """Record a write operation in mcp_activity for audit/dashboard."""
+ try:
+ await pool.execute(
+ "INSERT INTO mcp_activity (project_id, tool_name, detail) VALUES ($1, $2, $3::jsonb)",
+ pid, tool_name, json.dumps(detail or {}),
+ )
+ except Exception as e:
+ logger.warning("activity recording failed: %s", e)
+
+
async def _record_token_estimate(pool, pid, operation: str, loaded_words: int):
- """Record a token estimate for tracking context savings."""
+ """Legacy: record a token estimate (kept for backward compat)."""
try:
full_doc_words = await pool.fetchval(
"SELECT COALESCE(SUM(word_count), 0) FROM sections WHERE project_id = $1", pid,
@@ -1415,6 +1445,24 @@ async def _record_token_estimate(pool, pid, operation: str, loaded_words: int):
logger.warning("token estimate recording failed: %s", e)
+async def _record_section_access(
+ pool, pid, operation: str,
+ accesses: list[tuple], # [(section_id, access_level, loaded_words), ...]
+):
+ """Record granular section-level access for honest token savings."""
+ if not accesses:
+ return
+ try:
+ await pool.executemany(
+ "INSERT INTO section_access_log "
+ "(project_id, operation, section_id, access_level, loaded_words) "
+ "VALUES ($1, $2, $3, $4, $5)",
+ [(pid, operation, sid, level, words) for sid, level, words in accesses],
+ )
+ except Exception as e:
+ logger.warning("section access recording failed: %s", e)
+
+
@mcp.tool(
annotations={"readOnlyHint": True, "destructiveHint": False, "idempotentHint": True, "openWorldHint": False}
)
diff --git a/scripts/record_demo.py b/scripts/record_demo.py
index faf1990..9555f24 100644
--- a/scripts/record_demo.py
+++ b/scripts/record_demo.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-"""Record a ~35s demo video of PRDforge Web UI.
+"""Record a ~45s demo video of PRDforge Web UI.
Prerequisites:
docker compose up -d
@@ -9,6 +9,9 @@
Usage:
python scripts/record_demo.py
+ # With custom credentials
+ DEMO_EMAIL=admin@example.com DEMO_PASSWORD=secret python scripts/record_demo.py
+
Output:
demo.webm in the project root.
@@ -18,20 +21,81 @@
demo.gif
"""
+import os
import shutil
+import sys
import tempfile
from pathlib import Path
from playwright.sync_api import sync_playwright
-BASE_URL = "http://localhost:8088"
+BASE_URL = os.environ.get("DEMO_BASE_URL", "http://localhost:3000")
+DEMO_EMAIL = os.environ.get("DEMO_EMAIL", "demo@prdforge.local")
+DEMO_PASSWORD = os.environ.get("DEMO_PASSWORD", "prdforge-demo")
+DEMO_NAME = "Demo User"
+DEMO_PROJECT_SLUG = "prdforge-demo"
+
PROJECT_ROOT = Path(__file__).resolve().parent.parent
OUTPUT = PROJECT_ROOT / "demo.webm"
-WIDTH, HEIGHT = 1280, 720
+WIDTH, HEIGHT = 1440, 900
+
+
+def bootstrap_user(page):
+ """Ensure demo user exists via /api/auth/setup (idempotent)."""
+ result = page.evaluate(f"""
+ fetch('/api/auth/setup', {{
+ method: 'POST',
+ headers: {{'Content-Type': 'application/json'}},
+ body: JSON.stringify({{
+ name: '{DEMO_NAME}',
+ email: '{DEMO_EMAIL}',
+ password: '{DEMO_PASSWORD}'
+ }})
+ }}).then(r => ({{ status: r.status, ok: r.ok }}))
+ """)
+ status = result.get("status", 0)
+ if status not in (200, 409):
+ print(f"ERROR: /api/auth/setup returned {status}. Stack may not be running.")
+ sys.exit(1)
+ print(f"Bootstrap: status={status} ({'created' if status == 200 else 'already exists'})")
+
+
+def sign_in(page):
+ """Sign in via the UI form."""
+ page.goto(f"{BASE_URL}/signin")
+ page.fill("#email", DEMO_EMAIL)
+ page.fill("#password", DEMO_PASSWORD)
+ page.click('button[type="submit"]')
+
+ # Wait for redirect to /projects
+ page.wait_for_url("**/projects", timeout=10_000)
+ print("Signed in successfully")
+
+
+def ensure_demo_project(page):
+ """Create demo project with saas-mvp template (ignore if slug exists)."""
+ result = page.evaluate(f"""
+ fetch('/api/projects', {{
+ method: 'POST',
+ headers: {{'Content-Type': 'application/json'}},
+ body: JSON.stringify({{
+ name: 'PRDforge Demo',
+ slug: '{DEMO_PROJECT_SLUG}',
+ description: 'Demo SaaS MVP project',
+ template_id: 'saas-mvp'
+ }})
+ }}).then(r => ({{ status: r.status, ok: r.ok }}))
+ """)
+ status = result.get("status", 0)
+ if status in (200, 201, 409):
+ print(f"Demo project: status={status}")
+ else:
+ print(f"WARNING: create project returned {status}")
def main():
video_dir = tempfile.mkdtemp(prefix="prdforge-demo-")
+ demo_comment_id = None
with sync_playwright() as p:
browser = p.chromium.launch()
@@ -42,83 +106,113 @@ def main():
)
page = context.new_page()
- # ── Scene 1: Landing (0-5s) ──────────────────────────────
+ # ── Setup ──────────────────────────────────────────────────
page.goto(BASE_URL)
- page.wait_for_selector("#sectionList .section-item", timeout=10_000)
- page.wait_for_timeout(2500)
+ page.wait_for_timeout(1000)
+ bootstrap_user(page)
- # ── Scene 2: Browse sections (5-12s) ─────────────────────
- page.locator(".section-item").filter(has_text="Overview").first.click()
- page.wait_for_selector(".section-title", timeout=5000)
- page.wait_for_timeout(2500)
+ # ── Scene 1: Sign in (0-4s) ───────────────────────────────
+ sign_in(page)
+ page.wait_for_timeout(1500)
- page.locator(".section-item").filter(has_text="Data Model").click()
- page.wait_for_selector(".section-title", timeout=5000)
- page.wait_for_timeout(2500)
+ ensure_demo_project(page)
+ page.wait_for_timeout(500)
- # ── Scene 3: Scroll content (12-16s) ─────────────────────
- page.evaluate(
- 'document.querySelector(".main").scrollBy({top: 400, behavior: "smooth"})'
- )
- page.wait_for_timeout(1500)
- page.evaluate(
- 'document.querySelector(".main").scrollBy({top: 300, behavior: "smooth"})'
- )
+ # ── Scene 2: Projects list → click demo project (4-7s) ───
+ page.reload()
page.wait_for_timeout(1500)
- # ── Scene 4: Dependency graph (16-23s) ───────────────────
- page.locator('.nav-icon[data-tab="deps"]').click()
- page.wait_for_timeout(4000) # let force-directed graph settle
- # hover near center to trigger node highlight
- canvas = page.locator("canvas")
- if canvas.count():
- box = canvas.bounding_box()
- if box:
- page.mouse.move(
- box["x"] + box["width"] * 0.45,
- box["y"] + box["height"] * 0.4,
- )
+ # Click the demo project card
+ card = page.locator("text=PRDforge Demo").first
+ if card.is_visible():
+ card.click()
+ else:
+ page.goto(f"{BASE_URL}/projects/{DEMO_PROJECT_SLUG}")
page.wait_for_timeout(2000)
- # ── Scene 5: Add a comment (23-30s) ──────────────────────
- page.locator('.nav-icon[data-tab="sections"]').click()
- page.wait_for_timeout(500)
- page.locator(".section-item").filter(has_text="API Specification").click()
- page.wait_for_selector(".section-title", timeout=5000)
- page.wait_for_timeout(1500)
+ # ── Scene 3: Browse sections (7-16s) ──────────────────────
+ sidebar_buttons = page.locator("nav button")
+
+ # Click through sidebar sections
+ for section_text in ["Tech Stack", "Data Model", "API Design"]:
+ btn = sidebar_buttons.filter(has_text=section_text).first
+ if btn.is_visible():
+ btn.click()
+ page.wait_for_timeout(2000)
- # Create comment via API (more reliable than simulating text selection)
- comment_resp = page.evaluate("""
- fetch('/api/projects/snaphabit/sections/api-spec/comments', {
+ # ── Scene 4: Select text → comment form (16-22s) ──────────
+ # Create a comment via API for demo purposes
+ demo_comment_id = page.evaluate(f"""
+ fetch('/api/projects/{DEMO_PROJECT_SLUG}/sections/api-design/comments', {{
method: 'POST',
- headers: {'Content-Type': 'application/json'},
- body: JSON.stringify({
- anchor_text: 'Rate limiting',
- anchor_prefix: '**',
- anchor_suffix: ':** 100 req/min',
- body: 'Should we add per-endpoint rate limits?'
- })
- }).then(r => r.json())
+ headers: {{'Content-Type': 'application/json'}},
+ body: JSON.stringify({{
+ anchor_text: 'POST /api/auth/login',
+ anchor_prefix: '### `',
+ anchor_suffix: '`',
+ body: 'Should we add rate limiting to the login endpoint?'
+ }})
+ }}).then(r => r.json()).then(d => d.id || null).catch(() => null)
""")
- page.wait_for_timeout(800)
- # Reload section to show highlight + comment card
- page.evaluate("loadSection('api-spec')")
- page.wait_for_timeout(3000)
+ page.wait_for_timeout(500)
- # ── Scene 6: Theme toggle (30-34s) ───────────────────────
- page.locator("#themeBtn").click()
- page.wait_for_timeout(2000)
- page.locator("#themeBtn").click()
- page.wait_for_timeout(1500)
+ # Reload section to show comment
+ btn = sidebar_buttons.filter(has_text="API Design").first
+ if btn.is_visible():
+ btn.click()
+ page.wait_for_timeout(2500)
- # ── Scene 7: Final hold (34-36s) ─────────────────────────
- page.wait_for_timeout(1500)
+ # ── Scene 5: Dependencies tab (22-28s) ────────────────────
+ deps_tab = page.locator('[value="deps"]').first
+ if deps_tab.is_visible():
+ deps_tab.click()
+ page.wait_for_timeout(4000)
+
+ # ── Scene 6: Stats tab (28-33s) ───────────────────────────
+ stats_tab = page.locator('[value="stats"]').first
+ if stats_tab.is_visible():
+ stats_tab.click()
+ page.wait_for_timeout(3000)
+
+ # Back to sections
+ sections_tab = page.locator('[value="sections"]').first
+ if sections_tab.is_visible():
+ sections_tab.click()
+ page.wait_for_timeout(1000)
+
+ # ── Scene 7: Chat panel (33-39s) ──────────────────────────
+ chat_tab = page.locator('[value="chat"]').first
+ if chat_tab.is_visible():
+ chat_tab.click()
+ page.wait_for_timeout(1500)
+
+ # Type a message (don't send — just show the composer)
+ chat_input = page.locator('textarea[placeholder]').first
+ if chat_input.is_visible():
+ chat_input.fill("What sections need the most attention?")
+ page.wait_for_timeout(2000)
+ chat_input.fill("")
+
+ # Back to sections
+ if sections_tab.is_visible():
+ sections_tab.click()
+ page.wait_for_timeout(1000)
+
+ # ── Scene 8: Theme toggle (39-43s) ────────────────────────
+ theme_btn = page.locator('button[aria-label="Toggle theme"]').first
+ if theme_btn.is_visible():
+ theme_btn.click()
+ page.wait_for_timeout(2000)
+ theme_btn.click()
+ page.wait_for_timeout(1500)
+
+ # ── Scene 9: Final hold (43-46s) ──────────────────────────
+ page.wait_for_timeout(2000)
- # ── Cleanup: delete the demo comment ─────────────────────
- if comment_resp and isinstance(comment_resp, dict) and "id" in comment_resp:
- cid = comment_resp["id"]
+ # ── Cleanup: delete demo comment ───────────────────────────
+ if demo_comment_id:
page.evaluate(f"""
- fetch('/api/projects/snaphabit/sections/api-spec/comments/{cid}', {{
+ fetch('/api/projects/{DEMO_PROJECT_SLUG}/sections/api-design/comments/{demo_comment_id}', {{
method: 'DELETE'
}})
""")
@@ -130,10 +224,9 @@ def main():
# Copy video to project root
shutil.copy2(video_path, OUTPUT)
- # Clean up temp dir
shutil.rmtree(video_dir, ignore_errors=True)
- print(f"Demo video saved to: {OUTPUT}")
+ print(f"\nDemo video saved to: {OUTPUT}")
print()
print("Convert to GIF with:")
print(
diff --git a/shared/constants.py b/shared/constants.py
new file mode 100644
index 0000000..90d429f
--- /dev/null
+++ b/shared/constants.py
@@ -0,0 +1,18 @@
+"""Shared constants used by both API and MCP server."""
+
+VALID_SECTION_TYPES = {
+ "overview", "tech_spec", "data_model", "api_spec", "ui_design",
+ "architecture", "deployment", "security", "testing", "timeline", "general",
+}
+
+SECTION_TYPE_ALIASES = {
+ "requirement": "general",
+ "requirements": "general",
+ "functional_requirements": "tech_spec",
+ "non_functional_requirements": "tech_spec",
+ "api": "api_spec",
+ "data": "data_model",
+ "ui": "ui_design",
+ "ux": "ui_design",
+ "roadmap": "timeline",
+}
diff --git a/shared/project_factory.py b/shared/project_factory.py
new file mode 100644
index 0000000..d6f63db
--- /dev/null
+++ b/shared/project_factory.py
@@ -0,0 +1,135 @@
+"""Shared project creation logic used by both API and MCP server."""
+
+import re
+import logging
+
+import asyncpg
+
+from shared.constants import VALID_SECTION_TYPES
+from shared.templates import get_template
+
+logger = logging.getLogger("prd_forge_factory")
+
+SLUG_RE = re.compile(r"^[a-z0-9]([a-z0-9-]*[a-z0-9])?$")
+MAX_SLUG = 100
+MAX_CONTENT_LEN = 50_000
+
+
+def _validate_slug(slug: str) -> str | None:
+ if not slug or len(slug) > MAX_SLUG or not SLUG_RE.match(slug):
+ return f"invalid slug '{slug}': must be 1-{MAX_SLUG} chars, lowercase alphanumeric with hyphens"
+ return None
+
+
+async def create_project_with_template(
+ pool: asyncpg.Pool,
+ name: str,
+ slug: str,
+ description: str = "",
+ template_id: str | None = None,
+ user_id: str | None = None,
+ organization_id: str | None = None,
+) -> dict:
+ """Create a project with optional template sections in a single transaction.
+
+ Returns the created project dict (with section_count).
+ Raises ValueError for validation errors, asyncpg.UniqueViolationError for slug conflicts.
+ """
+ # Validate slug
+ slug_err = _validate_slug(slug)
+ if slug_err:
+ raise ValueError(slug_err)
+
+ # Resolve template
+ template = None
+ if template_id and template_id != "blank":
+ template = get_template(template_id)
+ if template is None:
+ raise ValueError(f"unknown template '{template_id}'")
+ # Validate template sections
+ seen_slugs: set[str] = set()
+ for sec in template.sections:
+ sec_slug_err = _validate_slug(sec.slug)
+ if sec_slug_err:
+ raise ValueError(f"template section: {sec_slug_err}")
+ if sec.section_type not in VALID_SECTION_TYPES:
+ raise ValueError(f"template section '{sec.slug}': invalid type '{sec.section_type}'")
+ if len(sec.content) > MAX_CONTENT_LEN:
+ raise ValueError(f"template section '{sec.slug}': content exceeds {MAX_CONTENT_LEN} chars")
+ if sec.slug in seen_slugs:
+ raise ValueError(f"template has duplicate section slug '{sec.slug}'")
+ seen_slugs.add(sec.slug)
+
+ async with pool.acquire() as conn:
+ async with conn.transaction():
+ # Insert project
+ row = await conn.fetchrow(
+ """
+ INSERT INTO projects (name, slug, description, created_by, organization_id)
+ VALUES ($1, $2, $3, $4, $5)
+ RETURNING id, slug, name, description, version, created_at, updated_at
+ """,
+ name,
+ slug,
+ description,
+ user_id,
+ organization_id,
+ )
+ project_id = row["id"]
+
+ section_count = 0
+ # Insert template sections
+ if template and template.sections:
+ for sec in template.sections:
+ sec_row = await conn.fetchrow(
+ """
+ INSERT INTO sections (project_id, slug, title, section_type,
+ sort_order, content, summary, tags, notes)
+ VALUES ($1, $2, $3, $4, $5, $6, '', '{}', '')
+ RETURNING id
+ """,
+ project_id,
+ sec.slug,
+ sec.title,
+ sec.section_type,
+ sec.sort_order,
+ sec.content,
+ )
+ await conn.execute(
+ """
+ INSERT INTO section_revisions (section_id, revision_number, content, summary, change_description)
+ VALUES ($1, 1, $2, '', 'Initial section creation')
+ ON CONFLICT (section_id, revision_number) DO NOTHING
+ """,
+ sec_row["id"],
+ sec.content,
+ )
+ section_count += 1
+
+ # Add project_members owner row if user_id provided
+ if user_id:
+ # Check if project_members table exists
+ has_pm = await conn.fetchval("SELECT to_regclass('project_members')")
+ if has_pm:
+ await conn.execute(
+ """
+ INSERT INTO project_members (project_id, user_id, role)
+ VALUES ($1, $2, 'owner')
+ ON CONFLICT (project_id, user_id) DO NOTHING
+ """,
+ project_id,
+ user_id,
+ )
+
+ # Build result
+ result = {}
+ for key in ("id", "slug", "name", "description", "version", "created_at", "updated_at"):
+ val = row[key]
+ if hasattr(val, "isoformat"):
+ val = val.isoformat()
+ elif hasattr(val, "hex"): # UUID
+ val = str(val)
+ result[key] = val
+ result["section_count"] = section_count
+ result["total_words"] = 0
+ return result
diff --git a/shared/templates.py b/shared/templates.py
new file mode 100644
index 0000000..98db4c8
--- /dev/null
+++ b/shared/templates.py
@@ -0,0 +1,513 @@
+"""Project templates with pre-built section structures."""
+
+from dataclasses import dataclass, field
+
+
+@dataclass
+class SectionSpec:
+ slug: str
+ title: str
+ section_type: str
+ content: str
+ sort_order: int = 0
+
+
+@dataclass
+class TemplateSpec:
+ name: str
+ description: str
+ sections: list[SectionSpec] = field(default_factory=list)
+
+ @property
+ def section_count(self) -> int:
+ return len(self.sections)
+
+
+TEMPLATES: dict[str, TemplateSpec] = {
+ "blank": TemplateSpec(
+ name="Blank Project",
+ description="Empty project — add your own sections.",
+ sections=[],
+ ),
+ "saas-mvp": TemplateSpec(
+ name="SaaS MVP",
+ description="Product requirements for a SaaS minimum viable product.",
+ sections=[
+ SectionSpec(
+ slug="overview",
+ title="Product Overview",
+ section_type="overview",
+ sort_order=1,
+ content="""\
+## Vision
+
+Describe the product vision and the problem it solves.
+
+## Target Audience
+
+- Primary persona
+- Secondary persona
+
+## Success Metrics
+
+| Metric | Target | Timeframe |
+|--------|--------|-----------|
+| MAU | | 3 months |
+| Churn | | Monthly |
+""",
+ ),
+ SectionSpec(
+ slug="tech-stack",
+ title="Tech Stack & Architecture",
+ section_type="architecture",
+ sort_order=2,
+ content="""\
+## Architecture Overview
+
+Describe the high-level system architecture.
+
+## Tech Stack
+
+| Layer | Technology | Rationale |
+|-----------|-----------|-----------|
+| Frontend | | |
+| Backend | | |
+| Database | | |
+| Hosting | | |
+
+## Key Decisions
+
+- ADR-001: ...
+""",
+ ),
+ SectionSpec(
+ slug="data-model",
+ title="Data Model",
+ section_type="data_model",
+ sort_order=3,
+ content="""\
+## Core Entities
+
+### Users
+| Field | Type | Constraints |
+|-------|------|-------------|
+| id | UUID | PK |
+| email | text | unique |
+
+### (Add more entities)
+
+## Relationships
+
+- Users → ...
+""",
+ ),
+ SectionSpec(
+ slug="api-design",
+ title="API Design",
+ section_type="api_spec",
+ sort_order=4,
+ content="""\
+## Authentication
+
+Describe the auth mechanism (JWT, session, OAuth).
+
+## Endpoints
+
+### `POST /api/auth/login`
+- **Request:** `{ email, password }`
+- **Response:** `{ token, user }`
+
+### (Add more endpoints)
+
+## Error Handling
+
+Standard error response:
+```json
+{ "error": { "code": "NOT_FOUND", "message": "..." } }
+```
+""",
+ ),
+ SectionSpec(
+ slug="ui-design",
+ title="UI/UX Design",
+ section_type="ui_design",
+ sort_order=5,
+ content="""\
+## Design Principles
+
+1. Simplicity first
+2. Mobile-responsive
+3. Accessible (WCAG 2.1 AA)
+
+## Key Screens
+
+### Dashboard
+- Purpose: ...
+- Key components: ...
+
+### Settings
+- Purpose: ...
+
+## Design System
+
+- Typography: ...
+- Color palette: ...
+""",
+ ),
+ SectionSpec(
+ slug="security",
+ title="Security Requirements",
+ section_type="security",
+ sort_order=6,
+ content="""\
+## Authentication & Authorization
+
+- Auth method: ...
+- Session management: ...
+- Role-based access control: ...
+
+## Data Protection
+
+- Encryption at rest: ...
+- Encryption in transit: TLS 1.2+
+- PII handling: ...
+
+## Compliance
+
+- GDPR considerations: ...
+""",
+ ),
+ SectionSpec(
+ slug="timeline",
+ title="Roadmap & Timeline",
+ section_type="timeline",
+ sort_order=7,
+ content="""\
+## Phase 1: MVP (Weeks 1-4)
+
+- [ ] Core user flows
+- [ ] Authentication
+- [ ] Basic dashboard
+
+## Phase 2: Beta (Weeks 5-8)
+
+- [ ] Feedback integration
+- [ ] Performance optimization
+- [ ] Documentation
+
+## Phase 3: Launch
+
+- [ ] Marketing site
+- [ ] Monitoring & alerting
+- [ ] Support workflows
+""",
+ ),
+ ],
+ ),
+ "mobile-app": TemplateSpec(
+ name="Mobile App",
+ description="Requirements for a cross-platform mobile application.",
+ sections=[
+ SectionSpec(
+ slug="overview",
+ title="App Overview",
+ section_type="overview",
+ sort_order=1,
+ content="""\
+## App Concept
+
+Describe the app concept and core value proposition.
+
+## Platforms
+
+- iOS (minimum version: ...)
+- Android (minimum API level: ...)
+
+## Target Users
+
+- Primary: ...
+- Secondary: ...
+""",
+ ),
+ SectionSpec(
+ slug="features",
+ title="Core Features",
+ section_type="tech_spec",
+ sort_order=2,
+ content="""\
+## Feature List
+
+### P0 — Must Have
+1. User registration & login
+2. ...
+
+### P1 — Should Have
+1. Push notifications
+2. ...
+
+### P2 — Nice to Have
+1. ...
+""",
+ ),
+ SectionSpec(
+ slug="ui-design",
+ title="UI/UX Design",
+ section_type="ui_design",
+ sort_order=3,
+ content="""\
+## Navigation Structure
+
+- Tab bar / drawer navigation
+- Screen flow diagram
+
+## Key Screens
+
+### Onboarding
+- Steps: ...
+
+### Home
+- Layout: ...
+
+### Profile
+- Fields: ...
+
+## Design Guidelines
+
+- Follow platform conventions (Material Design / HIG)
+- Accessibility: minimum tap target 44pt
+""",
+ ),
+ SectionSpec(
+ slug="data-model",
+ title="Data Model & Storage",
+ section_type="data_model",
+ sort_order=4,
+ content="""\
+## Local Storage
+
+- Offline-first strategy: ...
+- Cache invalidation: ...
+
+## Backend API
+
+- Base URL: ...
+- Authentication: Bearer token
+
+## Sync Strategy
+
+- Conflict resolution: last-write-wins / merge
+- Background sync: ...
+""",
+ ),
+ SectionSpec(
+ slug="deployment",
+ title="Build & Deployment",
+ section_type="deployment",
+ sort_order=5,
+ content="""\
+## Build Pipeline
+
+- CI/CD: ...
+- Code signing: ...
+
+## Distribution
+
+- App Store / Google Play
+- TestFlight / Internal testing track
+- OTA updates: ...
+
+## Monitoring
+
+- Crash reporting: ...
+- Analytics: ...
+- Performance monitoring: ...
+""",
+ ),
+ ],
+ ),
+ "api-design": TemplateSpec(
+ name="API Design",
+ description="Backend API specification with data model and deployment.",
+ sections=[
+ SectionSpec(
+ slug="overview",
+ title="API Overview",
+ section_type="overview",
+ sort_order=1,
+ content="""\
+## Purpose
+
+Describe the API's purpose and the systems it serves.
+
+## Consumers
+
+- Frontend web app
+- Mobile apps
+- Third-party integrations
+
+## Conventions
+
+- REST / GraphQL / gRPC
+- Versioning strategy: URL path (`/v1/`) / header
+- Pagination: cursor-based / offset
+""",
+ ),
+ SectionSpec(
+ slug="auth",
+ title="Authentication & Authorization",
+ section_type="security",
+ sort_order=2,
+ content="""\
+## Auth Flow
+
+1. Client sends credentials to `POST /auth/token`
+2. Server returns JWT (access + refresh)
+3. Client includes `Authorization: Bearer ` on requests
+
+## Scopes & Permissions
+
+| Scope | Description |
+|----------|--------------------|
+| read | Read-only access |
+| write | Create/update |
+| admin | Full access |
+
+## Rate Limiting
+
+- Default: 100 req/min per API key
+- Authenticated: 1000 req/min
+""",
+ ),
+ SectionSpec(
+ slug="endpoints",
+ title="Endpoint Reference",
+ section_type="api_spec",
+ sort_order=3,
+ content="""\
+## Resources
+
+### Users (`/api/v1/users`)
+
+| Method | Path | Description | Auth |
+|--------|---------------|------------------|---------|
+| GET | /users | List users | admin |
+| POST | /users | Create user | admin |
+| GET | /users/:id | Get user | read |
+| PATCH | /users/:id | Update user | write |
+
+### (Add more resources)
+
+## Error Responses
+
+```json
+{
+ "error": {
+ "code": "VALIDATION_ERROR",
+ "message": "email is required",
+ "details": { "field": "email" }
+ }
+}
+```
+""",
+ ),
+ SectionSpec(
+ slug="data-model",
+ title="Data Model",
+ section_type="data_model",
+ sort_order=4,
+ content="""\
+## Database
+
+- Engine: PostgreSQL / MySQL / MongoDB
+- Migrations: ...
+
+## Schema
+
+### users
+| Column | Type | Constraints |
+|------------|-------------|-------------------|
+| id | UUID | PK |
+| email | VARCHAR(255) | UNIQUE, NOT NULL |
+| created_at | TIMESTAMPTZ | DEFAULT now() |
+
+### (Add more tables)
+
+## Indexes
+
+- `users(email)` — unique
+""",
+ ),
+ SectionSpec(
+ slug="deployment",
+ title="Deployment & Operations",
+ section_type="deployment",
+ sort_order=5,
+ content="""\
+## Infrastructure
+
+- Runtime: Docker / serverless
+- Hosting: AWS / GCP / Azure
+- Database: managed / self-hosted
+
+## CI/CD
+
+- Pipeline stages: lint → test → build → deploy
+- Environments: dev / staging / production
+
+## Observability
+
+- Logging: structured JSON
+- Metrics: request latency, error rate, throughput
+- Alerting: ...
+
+## Backup & Recovery
+
+- Database backups: daily automated
+- RTO / RPO targets: ...
+""",
+ ),
+ SectionSpec(
+ slug="testing",
+ title="Testing Strategy",
+ section_type="testing",
+ sort_order=6,
+ content="""\
+## Test Pyramid
+
+### Unit Tests
+- Coverage target: 80%
+- Framework: ...
+
+### Integration Tests
+- Database: test containers
+- External services: mocked / sandboxed
+
+### E2E / Contract Tests
+- API contract tests for each consumer
+- Tool: Pact / Dredd / custom
+
+## Load Testing
+
+- Tool: k6 / Locust
+- Targets: p95 < 200ms at 1000 RPS
+""",
+ ),
+ ],
+ ),
+}
+
+
+def get_template(template_id: str) -> TemplateSpec | None:
+ return TEMPLATES.get(template_id)
+
+
+def list_templates() -> list[dict]:
+ return [
+ {
+ "id": tid,
+ "name": t.name,
+ "description": t.description,
+ "section_count": t.section_count,
+ }
+ for tid, t in TEMPLATES.items()
+ ]
diff --git a/tests/conftest.py b/tests/conftest.py
index c622c6d..31d1c11 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -6,7 +6,7 @@
# Add project root + subpackages to path for imports
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "mcp_server"))
-sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "ui"))
+sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "api"))
try:
import asyncpg
@@ -26,6 +26,10 @@ async def db_pool():
async def clean_test_data(db_pool):
"""Clean up test-created data after each test, preserving seed data."""
async def _clean():
+ # FK-safe order. Uses to_regclass() — safe when tables don't exist yet.
+ for t in ['section_access_log', 'password_reset_tokens', 'audit_events', 'prdforge_bootstrap', 'project_members', 'mcp_activity']:
+ if await db_pool.fetchval(f"SELECT to_regclass('{t}')") is not None:
+ await db_pool.execute(f"DELETE FROM {t}")
await db_pool.execute("DELETE FROM chat_messages")
await db_pool.execute("DELETE FROM project_chats")
await db_pool.execute("DELETE FROM comment_replies")
diff --git a/tests/test_auth.py b/tests/test_auth.py
new file mode 100644
index 0000000..1a1371e
--- /dev/null
+++ b/tests/test_auth.py
@@ -0,0 +1,267 @@
+"""Tests for auth middleware and WebSocket tokens."""
+
+import json
+import time
+
+import pytest
+
+pytestmark = pytest.mark.asyncio
+
+
+class TestAuthContract:
+ """Verify auth contract module works."""
+
+ async def test_contract_tables_missing_ok(self, db_pool):
+ """Contract check returns errors when auth tables don't exist."""
+ import sys, os
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "api"))
+ from auth_contract import verify_auth_contract
+ errors = await verify_auth_contract(db_pool)
+ # Tables may or may not exist depending on test env
+ assert isinstance(errors, list)
+
+ async def test_role_hierarchy(self):
+ import sys, os
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "api"))
+ from auth import has_min_role, ROLE_HIERARCHY
+
+ assert has_min_role("owner", "viewer")
+ assert has_min_role("admin", "editor")
+ assert has_min_role("editor", "editor")
+ assert not has_min_role("viewer", "editor")
+ assert not has_min_role("commenter", "admin")
+
+ async def test_role_hierarchy_all_levels(self):
+ from auth import has_min_role
+
+ # owner > admin > editor > commenter > viewer
+ roles = ["owner", "admin", "editor", "commenter", "viewer"]
+ for i, higher in enumerate(roles):
+ for j, lower in enumerate(roles):
+ if i <= j:
+ assert has_min_role(higher, lower), f"{higher} should satisfy {lower}"
+ else:
+ assert not has_min_role(higher, lower), f"{higher} should NOT satisfy {lower}"
+
+
+class TestWSToken:
+ """Verify WS token minting and verification."""
+
+ async def test_mint_and_verify(self):
+ import sys, os
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "api"))
+ from ws import mint_ws_token, verify_ws_token
+
+ token = mint_ws_token("user-123", "my-project")
+ payload = verify_ws_token(token)
+ assert payload is not None
+ assert payload["sub"] == "user-123"
+ assert payload["project"] == "my-project"
+ assert payload["aud"] == "ws"
+
+ async def test_verify_rejects_tampered(self):
+ from ws import mint_ws_token, verify_ws_token
+
+ token = mint_ws_token("user-123", "proj")
+ # Tamper with signature
+ parts = token.rsplit(".", 1)
+ tampered = parts[0] + ".0000000000000000"
+ assert verify_ws_token(tampered) is None
+
+ async def test_verify_rejects_expired(self):
+ from ws import verify_ws_token, WS_TOKEN_SECRET
+ import hashlib, hmac
+
+ payload = json.dumps({
+ "jti": "test-jti",
+ "sub": "user-1",
+ "aud": "ws",
+ "project": "proj",
+ "exp": int(time.time()) - 10, # expired
+ }, separators=(",", ":"), sort_keys=True)
+ sig = hmac.new(WS_TOKEN_SECRET.encode(), payload.encode(), hashlib.sha256).hexdigest()
+ token = f"{payload}.{sig}"
+ assert verify_ws_token(token) is None
+
+ async def test_verify_rejects_wrong_audience(self):
+ from ws import verify_ws_token, WS_TOKEN_SECRET
+ import hashlib, hmac
+
+ payload = json.dumps({
+ "jti": "test-jti",
+ "sub": "user-1",
+ "aud": "http", # wrong
+ "project": "proj",
+ "exp": int(time.time()) + 120,
+ }, separators=(",", ":"), sort_keys=True)
+ sig = hmac.new(WS_TOKEN_SECRET.encode(), payload.encode(), hashlib.sha256).hexdigest()
+ token = f"{payload}.{sig}"
+ assert verify_ws_token(token) is None
+
+ async def test_each_token_has_unique_jti(self):
+ from ws import mint_ws_token, verify_ws_token
+
+ t1 = mint_ws_token("u", "p")
+ t2 = mint_ws_token("u", "p")
+ p1 = verify_ws_token(t1)
+ p2 = verify_ws_token(t2)
+ assert p1["jti"] != p2["jti"]
+
+
+class TestWSTokenEndpoint:
+ """Test the POST /api/ws-token endpoint."""
+
+ async def test_mint_token_success(self, ui_client, mcp_pool):
+ import server
+ await server.prd_create_project(name="WS Test", slug="ws-test")
+
+ resp = await ui_client.post("/api/ws-token", json={
+ "project_slug": "ws-test",
+ })
+ assert resp.status_code == 200
+ data = resp.json()
+ assert "token" in data
+
+ async def test_mint_token_missing_fields(self, ui_client):
+ resp = await ui_client.post("/api/ws-token", json={})
+ assert resp.status_code == 400
+
+ async def test_mint_token_unknown_project(self, ui_client):
+ resp = await ui_client.post("/api/ws-token", json={
+ "project_slug": "nonexistent",
+ })
+ assert resp.status_code == 404
+
+
+class TestMemberEndpoints:
+ """Test project member management endpoints."""
+
+ async def test_list_members_empty(self, ui_client, mcp_pool):
+ import server
+ await server.prd_create_project(name="Mem Test", slug="mem-test")
+ resp = await ui_client.get("/api/projects/mem-test/members")
+ assert resp.status_code == 200
+ assert resp.json() == []
+
+ async def test_add_and_list_member(self, ui_client, mcp_pool):
+ import server
+ await server.prd_create_project(name="Mem Test2", slug="mem-test2")
+
+ import uuid
+ user_id = str(uuid.uuid4())
+ resp = await ui_client.post("/api/projects/mem-test2/members", json={
+ "user_id": user_id, "role": "editor",
+ })
+ assert resp.status_code == 200
+ assert resp.json()["role"] == "editor"
+
+ resp = await ui_client.get("/api/projects/mem-test2/members")
+ assert len(resp.json()) == 1
+
+ async def test_remove_member(self, ui_client, mcp_pool):
+ import server, uuid
+ await server.prd_create_project(name="Mem Test3", slug="mem-test3")
+
+ user_id = str(uuid.uuid4())
+ await ui_client.post("/api/projects/mem-test3/members", json={
+ "user_id": user_id, "role": "viewer",
+ })
+
+ resp = await ui_client.delete(f"/api/projects/mem-test3/members/{user_id}")
+ assert resp.status_code == 200
+ assert resp.json()["removed"] is True
+
+ async def test_add_member_invalid_role(self, ui_client, mcp_pool):
+ import server
+ await server.prd_create_project(name="Mem Test4", slug="mem-test4")
+ resp = await ui_client.post("/api/projects/mem-test4/members", json={
+ "user_id": "xxx", "role": "superadmin",
+ })
+ assert resp.status_code == 400
+
+ async def test_add_member_project_not_found(self, ui_client):
+ resp = await ui_client.post("/api/projects/nonexistent/members", json={
+ "user_id": "xxx", "role": "viewer",
+ })
+ assert resp.status_code == 404
+
+
+class TestAuditEndpoints:
+ async def test_audit_empty(self, ui_client, mcp_pool):
+ import server
+ await server.prd_create_project(name="Aud Test", slug="aud-test")
+ resp = await ui_client.get("/api/projects/aud-test/audit")
+ assert resp.status_code == 200
+ assert resp.json() == []
+
+ async def test_audit_not_found(self, ui_client):
+ resp = await ui_client.get("/api/projects/nonexistent/audit")
+ assert resp.status_code == 404
+
+
+class TestOptimisticLocking:
+ """Test expected_revision conflict detection on section PATCH."""
+
+ async def test_patch_with_correct_revision(self, ui_client, mcp_pool):
+ import server
+ await server.prd_create_project(name="Lock Test", slug="lock-test")
+ await server.prd_create_section(project="lock-test", slug="s1", title="S1", content="v1")
+ # revision 1 was created by prd_create_section
+ resp = await ui_client.patch("/api/projects/lock-test/sections/s1", json={
+ "status": "in_progress",
+ "expected_revision": 1,
+ })
+ assert resp.status_code == 200
+
+ async def test_patch_with_stale_revision_returns_409(self, ui_client, mcp_pool):
+ import server
+ await server.prd_create_project(name="Lock Test2", slug="lock-test2")
+ await server.prd_create_section(project="lock-test2", slug="s1", title="S1", content="v1")
+ # Update content to create revision 2
+ await server.prd_update_section(project="lock-test2", section="s1", content="v2")
+ # Client thinks revision is still 1
+ resp = await ui_client.patch("/api/projects/lock-test2/sections/s1", json={
+ "status": "review",
+ "expected_revision": 1,
+ })
+ assert resp.status_code == 409
+ data = resp.json()
+ assert data["error"]["code"] == "CONFLICT"
+ assert data["error"]["details"]["current_revision"] == 2
+
+ async def test_patch_without_expected_revision_succeeds(self, ui_client, mcp_pool):
+ import server
+ await server.prd_create_project(name="Lock Test3", slug="lock-test3")
+ await server.prd_create_section(project="lock-test3", slug="s1", title="S1")
+ # No expected_revision — no conflict check
+ resp = await ui_client.patch("/api/projects/lock-test3/sections/s1", json={
+ "status": "approved",
+ })
+ assert resp.status_code == 200
+
+
+class TestErrorModule:
+ async def test_error_response_format(self):
+ import sys, os
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "api"))
+ from errors import error_response, NOT_FOUND
+
+ resp = error_response(NOT_FOUND, "project 'x' not found", 404)
+ body = json.loads(resp.body.decode())
+ assert body["error"]["code"] == "NOT_FOUND"
+ assert body["error"]["status"] == 404
+ assert "not found" in body["error"]["message"]
+ assert resp.status_code == 404
+
+ async def test_helper_functions(self):
+ from errors import not_found, validation_error, unauthorized, permission_denied, conflict
+
+ for fn, status in [
+ (lambda: not_found("project", "x"), 404),
+ (lambda: validation_error("bad slug"), 400),
+ (lambda: unauthorized(), 401),
+ (lambda: permission_denied(), 403),
+ (lambda: conflict("version mismatch"), 409),
+ ]:
+ resp = fn()
+ assert resp.status_code == status
diff --git a/tests/test_mcp_tools.py b/tests/test_mcp_tools.py
index e4f4892..9054138 100644
--- a/tests/test_mcp_tools.py
+++ b/tests/test_mcp_tools.py
@@ -696,3 +696,72 @@ async def test_suggest_nonexistent_section(self, mcp_pool):
project="snaphabit", section="nonexistent"
))
assert "error" in result
+
+
+class TestMcpActivity:
+ """Tests for MCP activity tracking on write operations."""
+
+ @staticmethod
+ def _detail(row):
+ """Parse JSONB detail — asyncpg returns JSONB as strings."""
+ d = row["detail"]
+ return json.loads(d) if isinstance(d, str) else d
+
+ async def test_create_project_records_activity(self, mcp_pool):
+ import server
+ await server.prd_create_project(name="Act Test", slug="act-test")
+ rows = await mcp_pool.fetch(
+ "SELECT tool_name, detail FROM mcp_activity WHERE tool_name = 'prd_create_project'"
+ )
+ assert len(rows) >= 1
+ assert self._detail(rows[-1])["slug"] == "act-test"
+
+ async def test_create_section_records_activity(self, mcp_pool):
+ import server
+ await server.prd_create_project(name="Act Sec", slug="act-sec")
+ await server.prd_create_section(project="act-sec", slug="s1", title="S1")
+ rows = await mcp_pool.fetch(
+ "SELECT tool_name, detail FROM mcp_activity WHERE tool_name = 'prd_create_section'"
+ )
+ assert len(rows) >= 1
+ assert self._detail(rows[-1])["slug"] == "s1"
+
+ async def test_update_section_records_activity(self, mcp_pool):
+ import server
+ await server.prd_create_project(name="Act Upd", slug="act-upd")
+ await server.prd_create_section(project="act-upd", slug="s1", title="S1", content="old")
+ await server.prd_update_section(project="act-upd", section="s1", content="new")
+ rows = await mcp_pool.fetch(
+ "SELECT detail FROM mcp_activity WHERE tool_name = 'prd_update_section'"
+ )
+ assert len(rows) >= 1
+ assert "content" in self._detail(rows[-1])["fields"]
+
+ async def test_delete_section_records_activity(self, mcp_pool):
+ import server
+ await server.prd_create_project(name="Act Del", slug="act-del")
+ await server.prd_create_section(project="act-del", slug="ds1", title="DS1")
+ await server.prd_delete_section(project="act-del", section="ds1")
+ rows = await mcp_pool.fetch(
+ "SELECT detail FROM mcp_activity WHERE tool_name = 'prd_delete_section'"
+ )
+ assert len(rows) >= 1
+ assert self._detail(rows[-1])["slug"] == "ds1"
+
+ async def test_activity_in_token_stats(self, mcp_pool):
+ """Token stats endpoint returns activity field."""
+ import server
+ import app as ui_app
+ from httpx import ASGITransport, AsyncClient
+
+ ui_app.pool = mcp_pool
+ transport = ASGITransport(app=ui_app.app)
+ async with AsyncClient(transport=transport, base_url="http://test") as client:
+ await server.prd_create_project(name="Act Stats", slug="act-stats")
+ await server.prd_create_section(project="act-stats", slug="as1", title="AS1")
+ resp = await client.get("/api/projects/act-stats/token-stats")
+ assert resp.status_code == 200
+ data = resp.json()
+ assert "activity" in data
+ assert isinstance(data["activity"], list)
+ assert len(data["activity"]) >= 1
diff --git a/tests/test_smoke.py b/tests/test_smoke.py
index 88ca927..67ccf4b 100644
--- a/tests/test_smoke.py
+++ b/tests/test_smoke.py
@@ -7,7 +7,8 @@
import pytest
MCP_URL = "http://localhost:8080"
-UI_URL = "http://localhost:8088"
+API_URL = "http://localhost:8088"
+FRONTEND_URL = "http://localhost:3000"
@pytest.fixture(scope="session")
@@ -33,54 +34,44 @@ def test_mcp_port_open(self, http_client):
class TestDBReadiness:
- def test_ui_health_endpoint(self, http_client):
- """UI /health endpoint confirms DB connection."""
- resp = http_client.get(f"{UI_URL}/health")
+ def test_api_health_endpoint(self, http_client):
+ """Python API /health endpoint confirms DB connection."""
+ resp = http_client.get(f"{API_URL}/health")
assert resp.status_code == 200
data = resp.json()
assert data["status"] == "ok"
assert data["db"] == "connected"
-class TestUIEndpoints:
- def test_index_returns_html(self, http_client):
- resp = http_client.get(f"{UI_URL}/")
- assert resp.status_code == 200
- assert "text/html" in resp.headers["content-type"]
- assert "PRD Forge" in resp.text
-
+class TestAPIEndpoints:
def test_api_projects(self, http_client):
- resp = http_client.get(f"{UI_URL}/api/projects")
+ resp = http_client.get(f"{API_URL}/api/projects")
assert resp.status_code == 200
data = resp.json()
assert isinstance(data, list)
assert len(data) >= 1
- def test_static_js_served(self, http_client):
- resp = http_client.get(f"{UI_URL}/static/marked.min.js")
- assert resp.status_code == 200
-
class TestSeedData:
def test_snaphabit_project_exists(self, http_client):
- resp = http_client.get(f"{UI_URL}/api/projects/snaphabit")
+ resp = http_client.get(f"{API_URL}/api/projects/snaphabit")
assert resp.status_code == 200
data = resp.json()
assert data["project"]["slug"] == "snaphabit"
assert data["stats"]["sections"] >= 10
def test_seed_sections_have_content(self, http_client):
- resp = http_client.get(f"{UI_URL}/api/projects/snaphabit/sections/data-model")
+ resp = http_client.get(f"{API_URL}/api/projects/snaphabit/sections/data-model")
assert resp.status_code == 200
data = resp.json()
assert len(data["section"]["content"]) > 100
def test_seed_dependencies_exist(self, http_client):
- resp = http_client.get(f"{UI_URL}/api/projects/snaphabit")
+ resp = http_client.get(f"{API_URL}/api/projects/snaphabit")
assert resp.status_code == 200
assert len(resp.json()["dependencies"]) >= 5
def test_export_produces_markdown(self, http_client):
- resp = http_client.get(f"{UI_URL}/api/projects/snaphabit/export")
+ resp = http_client.get(f"{API_URL}/api/projects/snaphabit/export")
assert resp.status_code == 200
assert "# SnapHabit" in resp.text
diff --git a/tests/test_ui_api.py b/tests/test_ui_api.py
index fd3415d..4a097ff 100644
--- a/tests/test_ui_api.py
+++ b/tests/test_ui_api.py
@@ -1,18 +1,13 @@
-"""Tests for FastAPI UI endpoints."""
+"""Tests for Python API endpoints."""
import json
+from unittest.mock import patch
+import pytest
import pytest_asyncio
class TestUIEndpoints:
- async def test_index_html(self, ui_client):
- resp = await ui_client.get("/")
- assert resp.status_code == 200
- assert "text/html" in resp.headers["content-type"]
- assert "PRD Forge" in resp.text
- assert "marked.min.js" in resp.text
-
async def test_list_projects(self, ui_client):
resp = await ui_client.get("/api/projects")
assert resp.status_code == 200
@@ -620,9 +615,9 @@ async def test_chat_approve_continues_blocked_turn(self, ui_client, monkeypatch)
pid = await pool.fetchval("SELECT id FROM projects WHERE slug='snaphabit'")
chat_id = await pool.fetchval(
"""
- INSERT INTO project_chats (project_id)
- VALUES ($1)
- ON CONFLICT (project_id)
+ INSERT INTO project_chats (project_id, chat_type)
+ VALUES ($1, 'main')
+ ON CONFLICT (project_id, chat_type, COALESCE(section_id, '00000000-0000-0000-0000-000000000000'))
DO UPDATE SET updated_at = now()
RETURNING id
""",
@@ -704,9 +699,9 @@ async def test_chat_approve_rejects_message_without_approval(self, ui_client):
pid = await pool.fetchval("SELECT id FROM projects WHERE slug='snaphabit'")
chat_id = await pool.fetchval(
"""
- INSERT INTO project_chats (project_id)
- VALUES ($1)
- ON CONFLICT (project_id)
+ INSERT INTO project_chats (project_id, chat_type)
+ VALUES ($1, 'main')
+ ON CONFLICT (project_id, chat_type, COALESCE(section_id, '00000000-0000-0000-0000-000000000000'))
DO UPDATE SET updated_at = now()
RETURNING id
""",
@@ -742,17 +737,17 @@ async def test_token_stats_success(self, ui_client):
resp = await ui_client.get("/api/projects/snaphabit/token-stats")
assert resp.status_code == 200
d = resp.json()
- assert d["operations"] == 2
- assert d["total_full_doc_tokens"] == 30000
- assert d["total_loaded_tokens"] == 2000
- assert d["total_saved_tokens"] == 28000
- assert d["savings_percent"] == 93.3
+ assert d["operations"] >= 2
+ # total_full_doc_tokens is now live doc size, not sum of per-operation
+ assert d["total_full_doc_tokens"] > 0
+ assert d["savings_percent"] >= 0
+ assert "sessions" in d
+ assert "best_session_savings" in d
+ assert "section_heatmap" in d
assert d["project_stats"]["sections"] >= 12
- assert d["project_stats"]["dependencies"] >= 1
- assert d["project_stats"]["revisions"] >= 0
assert len(d["by_operation"]) >= 1
ops = {o["operation"]: o for o in d["by_operation"]}
- assert ops["read_section"]["count"] == 2
+ assert ops["read_section"]["count"] >= 2
assert len(d["daily_trend"]) == 7
days = [e["day"] for e in d["daily_trend"]]
assert days == sorted(days)
@@ -768,9 +763,7 @@ async def test_token_stats_empty(self, ui_client):
assert resp.status_code == 200
d = resp.json()
assert d["operations"] == 0
- assert d["total_full_doc_tokens"] == 0
- assert d["total_loaded_tokens"] == 0
- assert d["total_saved_tokens"] == 0
+ assert d["total_full_doc_tokens"] > 0 # live doc size, even with no ops
assert d["savings_percent"] == 0
assert d["project_stats"]["sections"] >= 12
assert d["project_stats"]["dependencies"] >= 1
@@ -934,3 +927,177 @@ async def test_cli_login_code_no_pending(self, ui_client):
)
assert resp.status_code == 400
assert "No pending login" in resp.json()["error"]
+
+
+class TestTemplates:
+ """Project creation with templates."""
+
+ async def test_list_templates(self, ui_client):
+ resp = await ui_client.get("/api/templates")
+ assert resp.status_code == 200
+ data = resp.json()
+ assert isinstance(data, list)
+ ids = [t["id"] for t in data]
+ assert "blank" in ids
+ assert "saas-mvp" in ids
+ assert "mobile-app" in ids
+ assert "api-design" in ids
+ for t in data:
+ assert "name" in t
+ assert "description" in t
+ assert "section_count" in t
+
+ async def test_create_project_with_template(self, ui_client):
+ resp = await ui_client.post(
+ "/api/projects",
+ json={
+ "name": "Template Test",
+ "slug": "template-test",
+ "template_id": "saas-mvp",
+ },
+ )
+ assert resp.status_code == 200
+ data = resp.json()
+ assert data["slug"] == "template-test"
+ assert data["section_count"] == 7
+
+ # Verify sections actually exist
+ detail = await ui_client.get("/api/projects/template-test")
+ assert detail.status_code == 200
+ sections = detail.json()["sections"]
+ assert len(sections) == 7
+ slugs = [s["slug"] for s in sections]
+ assert "overview" in slugs
+ assert "tech-stack" in slugs
+ assert "data-model" in slugs
+
+ async def test_create_project_with_blank_template(self, ui_client):
+ resp = await ui_client.post(
+ "/api/projects",
+ json={
+ "name": "Blank Test",
+ "slug": "blank-test",
+ "template_id": "blank",
+ },
+ )
+ assert resp.status_code == 200
+ data = resp.json()
+ assert data["section_count"] == 0
+
+ async def test_create_project_invalid_template(self, ui_client):
+ resp = await ui_client.post(
+ "/api/projects",
+ json={
+ "name": "Bad Template",
+ "slug": "bad-template",
+ "template_id": "nonexistent",
+ },
+ )
+ assert resp.status_code == 400
+ assert "unknown template" in resp.json()["error"]
+
+ async def test_create_project_no_template(self, ui_client):
+ """No template_id = blank project (backwards compatible)."""
+ resp = await ui_client.post(
+ "/api/projects",
+ json={"name": "No Template", "slug": "no-template"},
+ )
+ assert resp.status_code == 200
+ data = resp.json()
+ assert data["section_count"] == 0
+
+ async def test_transaction_rollback_on_section_failure(self, db_pool, ui_client):
+ """If section insert fails mid-transaction, no project should be left behind."""
+ import app as ui_app
+ from shared.project_factory import create_project_with_template
+
+ # Patch to simulate a failure during section insert
+ original = create_project_with_template.__wrapped__ if hasattr(create_project_with_template, '__wrapped__') else None
+
+ async def failing_factory(pool, name, slug, description="", template_id=None, user_id=None, organization_id=None):
+ raise RuntimeError("Simulated section insert failure")
+
+ with patch("app.create_project_with_template", failing_factory):
+ resp = await ui_client.post(
+ "/api/projects",
+ json={
+ "name": "Rollback Test",
+ "slug": "rollback-test",
+ "template_id": "saas-mvp",
+ },
+ )
+ assert resp.status_code == 500
+
+ # Verify no project was left behind
+ check = await ui_client.get("/api/projects/rollback-test")
+ assert check.status_code == 404
+
+
+class TestTemplatesMCP:
+ """MCP prd_create_project with template param."""
+
+ async def test_create_with_template(self, mcp_pool):
+ import server
+ result = json.loads(await server.prd_create_project(
+ name="MCP Template", slug="mcp-tpl", template="saas-mvp"
+ ))
+ assert "created" in result
+ assert result["created"]["slug"] == "mcp-tpl"
+ assert result["created"]["section_count"] == 7
+
+ # Verify sections exist
+ sections = json.loads(await server.prd_list_sections(project="mcp-tpl"))
+ assert len(sections) == 7
+
+ async def test_create_with_invalid_template(self, mcp_pool):
+ import server
+ result = json.loads(await server.prd_create_project(
+ name="Bad MCP Template", slug="bad-mcp-tpl", template="nonexistent"
+ ))
+ assert "error" in result
+ assert "unknown template" in result["error"]
+
+ async def test_create_without_template(self, mcp_pool):
+ import server
+ result = json.loads(await server.prd_create_project(
+ name="No Template MCP", slug="no-tpl-mcp"
+ ))
+ assert "created" in result
+ assert result["created"]["section_count"] == 0
+
+
+class TestNotesRBAC:
+ """Notes endpoint requires editor role minimum."""
+
+ async def test_notes_update_no_auth(self, ui_client):
+ """In single-user mode (no auth tables), notes update should work."""
+ resp = await ui_client.post(
+ "/api/projects/snaphabit/sections/overview/notes",
+ json={"notes": "Test note content"},
+ )
+ assert resp.status_code == 200
+ assert resp.json()["ok"] is True
+ assert resp.json()["notes"] == "Test note content"
+
+ async def test_notes_update_empty(self, ui_client):
+ """Can clear notes by sending empty string."""
+ resp = await ui_client.post(
+ "/api/projects/snaphabit/sections/overview/notes",
+ json={"notes": ""},
+ )
+ assert resp.status_code == 200
+ assert resp.json()["notes"] == ""
+
+ async def test_notes_update_nonexistent_project(self, ui_client):
+ resp = await ui_client.post(
+ "/api/projects/nonexistent/sections/overview/notes",
+ json={"notes": "test"},
+ )
+ assert resp.status_code == 404
+
+ async def test_notes_update_nonexistent_section(self, ui_client):
+ resp = await ui_client.post(
+ "/api/projects/snaphabit/sections/nonexistent/notes",
+ json={"notes": "test"},
+ )
+ assert resp.status_code == 404