diff --git a/.gitignore b/.gitignore index 662b2b02a..f8fd29897 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,10 @@ __pycache__/ *$py.class **/node_modules/ +# Self-hosted server local runtime state +server/history/ +server/.env + # C extensions *.so @@ -15,8 +19,8 @@ dist/ downloads/ eggs/ .eggs/ -lib/ -lib64/ +/lib/ +/lib64/ parts/ sdist/ var/ diff --git a/LLM.md b/LLM.md index 693f69ae2..f0304257f 100644 --- a/LLM.md +++ b/LLM.md @@ -1313,7 +1313,7 @@ async def delete_memory(memory_id: str): - **Documentation**: https://docs.mem0.ai - **GitHub Repository**: https://github.com/mem0ai/mem0 - **Discord Community**: https://mem0.dev/DiG -- **Platform**: https://app.mem0.ai +- **Platform**: https://app.mem0.ai?utm_source=oss&utm_medium=llm - **Research Paper**: https://mem0.ai/research - **Examples**: https://github.com/mem0ai/mem0/tree/main/examples diff --git a/README.md b/README.md index f9ab4cd70..a0eef407e 100644 --- a/README.md +++ b/README.md @@ -85,18 +85,17 @@ See the [migration guide](https://docs.mem0.ai/migration/oss-v2-to-v3) for upgra ## πŸš€ Quickstart Guide -Choose between our hosted platform or self-hosted package: +| | Library | Self-Hosted Server | Cloud Platform | +|---|---------|-------------------|----------------| +| **Best for** | Testing, prototyping | Teams running on their own infrastructure | Zero-ops production use | +| **Setup** | `pip install mem0ai` | `docker compose up` | Sign up at [app.mem0.ai](https://app.mem0.ai?utm_source=oss&utm_medium=readme) | +| **Dashboard** | -- | [Yes](https://docs.mem0.ai/open-source/setup) | Yes | +| **Auth & API Keys** | -- | Yes | Yes | +| **Advanced Features** | -- | Teasers | All included | -### Hosted Platform +Just testing? Use the library. Building for a team? Self-hosted. Want zero ops? Cloud. -Get up and running in minutes with automatic updates, analytics, and enterprise security. - -1. Sign up on [Mem0 Platform](https://app.mem0.ai) -2. Embed the memory layer via SDK or API keys - -### Self-Hosted (Open Source) - -Install the sdk via pip: +### Library (pip / npm) ```bash pip install mem0ai @@ -110,10 +109,30 @@ python -m spacy download en_core_web_sm ``` Install sdk via npm: + ```bash npm install mem0ai ``` +### Self-Hosted Server + +> **Note:** Self-hosted auth is on by default. Upgrading from a pre-auth build? Set `ADMIN_API_KEY`, register an admin through the wizard, or `AUTH_DISABLED=true` for local dev only. See [upgrade notes](https://docs.mem0.ai/open-source/setup#upgrade-notes). + +```bash +# Recommended: one command β€” start the stack, create an admin, issue the first API key. +cd server && make bootstrap + +# Manual: start the stack and finish setup via the browser wizard. +cd server && docker compose up -d # http://localhost:3000 +``` + +See the [self-hosted docs](https://docs.mem0.ai/open-source/overview) for configuration. + +### Cloud Platform + +1. Sign up on [Mem0 Platform](https://app.mem0.ai?utm_source=oss&utm_medium=readme) +2. Embed the memory layer via SDK or API keys + ### CLI Manage memories from your terminal: diff --git a/cli/node/src/branding.ts b/cli/node/src/branding.ts index 10c6aa094..bdceadde1 100644 --- a/cli/node/src/branding.ts +++ b/cli/node/src/branding.ts @@ -96,7 +96,7 @@ export function printError(message: string, hint?: string): void { const resolvedHint = hint ?? (message.includes("Authentication failed") - ? `Run ${brand("mem0 init")} to reconfigure your API key Β· https://app.mem0.ai/dashboard/api-keys` + ? `Run ${brand("mem0 init")} to reconfigure your API key Β· https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=cli-node` : undefined); if (resolvedHint) { console.error(` ${dim(resolvedHint)}`); diff --git a/cli/node/src/commands/init.ts b/cli/node/src/commands/init.ts index 9f65cc564..930b4818f 100644 --- a/cli/node/src/commands/init.ts +++ b/cli/node/src/commands/init.ts @@ -185,7 +185,7 @@ function promptLine(label: string, defaultValue?: string): Promise { async function setupPlatform(config: Mem0Config): Promise { console.log(); console.log( - ` ${dim("Get your API key at https://app.mem0.ai/dashboard/api-keys")}`, + ` ${dim("Get your API key at https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=cli-node")}`, ); console.log(); @@ -234,7 +234,7 @@ async function validatePlatform(config: Mem0Config): Promise { } else { printError( `Could not connect: ${status.error ?? "Unknown error"}`, - "Visit https://app.mem0.ai/dashboard/api-keys to get a new key, or run mem0 init again.", + "Visit https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=cli-node to get a new key, or run mem0 init again.", ); } } catch (e) { diff --git a/cli/node/src/commands/utils.ts b/cli/node/src/commands/utils.ts index ae7b441d4..1e12d231a 100644 --- a/cli/node/src/commands/utils.ts +++ b/cli/node/src/commands/utils.ts @@ -63,7 +63,7 @@ export async function cmdStatus( ` ${dim("Run")} ${brand("mem0 init")} ${dim("to reconfigure your API key")}`, ); lines.push( - ` ${dim("Get a key at")} ${brand("https://app.mem0.ai/dashboard/api-keys")}`, + ` ${dim("Get a key at")} ${brand("https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=cli-node")}`, ); } } diff --git a/cli/python/src/mem0_cli/branding.py b/cli/python/src/mem0_cli/branding.py index b2bdf9cc0..7879ec8bf 100644 --- a/cli/python/src/mem0_cli/branding.py +++ b/cli/python/src/mem0_cli/branding.py @@ -146,7 +146,7 @@ def timed_status(console: Console, message: str): if "Authentication failed" in ctx.error_msg: _err.print( f" [{DIM_COLOR}]Run [bold]mem0 init[/bold] to reconfigure your API key" - f" Β· [bold]https://app.mem0.ai/dashboard/api-keys[/bold][/]" + f" Β· [bold]https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=cli-python[/bold][/]" ) raise else: diff --git a/cli/python/src/mem0_cli/commands/init_cmd.py b/cli/python/src/mem0_cli/commands/init_cmd.py index fadfb406f..22de4d7be 100644 --- a/cli/python/src/mem0_cli/commands/init_cmd.py +++ b/cli/python/src/mem0_cli/commands/init_cmd.py @@ -19,7 +19,13 @@ from mem0_cli.branding import ( print_info, print_success, ) -from mem0_cli.config import CONFIG_FILE, DEFAULT_BASE_URL, Mem0Config, load_config, save_config +from mem0_cli.config import ( + CONFIG_FILE, + DEFAULT_BASE_URL, + Mem0Config, + load_config, + save_config, +) console = Console() err_console = Console(stderr=True) @@ -352,7 +358,9 @@ def run_init( def _setup_platform(config: Mem0Config) -> None: """Platform setup flow.""" console.print() - console.print(f" [{DIM_COLOR}]Get your API key at https://app.mem0.ai/dashboard/api-keys[/]") + console.print( + f" [{DIM_COLOR}]Get your API key at https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=cli-python[/]" + ) console.print() console.print(f" [{BRAND_COLOR}]API Key[/]: ", end="") @@ -404,7 +412,7 @@ def _validate_platform(config: Mem0Config) -> None: print_error( err_console, f"Could not connect: {status.get('error', 'Unknown error')}", - hint="Visit https://app.mem0.ai/dashboard/api-keys to get a new key, then run mem0 init again.", + hint="Visit https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=cli-python to get a new key, then run mem0 init again.", ) except Exception as e: print_error(err_console, f"Connection test failed: {e}") diff --git a/cli/python/src/mem0_cli/commands/utils.py b/cli/python/src/mem0_cli/commands/utils.py index 5016f5f8f..8807030bc 100644 --- a/cli/python/src/mem0_cli/commands/utils.py +++ b/cli/python/src/mem0_cli/commands/utils.py @@ -77,7 +77,7 @@ def cmd_status( f" [{DIM_COLOR}]Run [bold]mem0 init[/bold] to reconfigure your API key[/]" ) lines.append( - f" [{DIM_COLOR}]Get a key at [bold]https://app.mem0.ai/dashboard/api-keys[/bold][/]" + f" [{DIM_COLOR}]Get a key at [bold]https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=cli-python[/bold][/]" ) lines.append(f" [{DIM_COLOR}]Latency:[/] {_elapsed:.2f}s") diff --git a/docs/api-reference.mdx b/docs/api-reference.mdx index 3c3cc073f..f44bbc0b5 100644 --- a/docs/api-reference.mdx +++ b/docs/api-reference.mdx @@ -10,7 +10,7 @@ description: "REST APIs for memory management, search, and entity operations" Mem0 provides a comprehensive REST API for integrating advanced memory capabilities into your applications. Create, search, update, and manage memories across users, agents, and custom entities with simple HTTP requests. -**Quick start:** Get your API key from the Mem0 Dashboard and make your first memory operation in minutes. +**Quick start:** Get your API key from the Mem0 Dashboard and make your first memory operation in minutes. --- @@ -87,7 +87,7 @@ All API requests require authentication using Token-based authentication. Includ Authorization: Token ``` -Get your API key from the Mem0 Dashboard. +Get your API key from the Mem0 Dashboard. **Keep your API key secure.** Never expose it in client-side code or public repositories. Use environment variables and server-side requests only. diff --git a/docs/cookbooks/companions/quickstart-demo.mdx b/docs/cookbooks/companions/quickstart-demo.mdx index 06404bff1..b94b86b9d 100644 --- a/docs/cookbooks/companions/quickstart-demo.mdx +++ b/docs/cookbooks/companions/quickstart-demo.mdx @@ -45,7 +45,7 @@ Before you begin, follow these steps to set up the demo application: OPENAI_API_KEY=your_openai_api_key MEM0_API_KEY=your_mem0_api_key ``` - You can obtain your `MEM0_API_KEY` by signing up at Mem0 API Dashboard. + You can obtain your `MEM0_API_KEY` by signing up at Mem0 API Dashboard. 5. Start the development server: ```bash diff --git a/docs/cookbooks/essentials/controlling-memory-ingestion.mdx b/docs/cookbooks/essentials/controlling-memory-ingestion.mdx index cd0f65c3a..05227bd17 100644 --- a/docs/cookbooks/essentials/controlling-memory-ingestion.mdx +++ b/docs/cookbooks/essentials/controlling-memory-ingestion.mdx @@ -38,7 +38,7 @@ client = MemoryClient(api_key="your-api-key") ``` -Replace `your-api-key` with your actual Mem0 API key from the dashboard. Without proper API authentication, memory operations will fail. +Replace `your-api-key` with your actual Mem0 API key from the dashboard. Without proper API authentication, memory operations will fail. --- diff --git a/docs/cookbooks/essentials/entity-partitioning-playbook.mdx b/docs/cookbooks/essentials/entity-partitioning-playbook.mdx index 1311098f8..6226c9c17 100644 --- a/docs/cookbooks/essentials/entity-partitioning-playbook.mdx +++ b/docs/cookbooks/essentials/entity-partitioning-playbook.mdx @@ -17,7 +17,7 @@ from mem0 import MemoryClient client = MemoryClient(api_key="m0-...") ``` -Grab an API key from the Mem0 dashboard to get started. +Grab an API key from the Mem0 dashboard to get started. ## Store and Retrieve Scoped Memories diff --git a/docs/cookbooks/essentials/exporting-memories.mdx b/docs/cookbooks/essentials/exporting-memories.mdx index 8517932b8..229406655 100644 --- a/docs/cookbooks/essentials/exporting-memories.mdx +++ b/docs/cookbooks/essentials/exporting-memories.mdx @@ -20,7 +20,7 @@ client = MemoryClient(api_key="your-api-key") ``` -Your API key needs export permissions to download memory data. Check your project settings on the dashboard if export operations fail with authentication errors. +Your API key needs export permissions to download memory data. Check your project settings on the dashboard if export operations fail with authentication errors. Let's add some sample memories to work with: diff --git a/docs/cookbooks/frameworks/eliza-os-character.mdx b/docs/cookbooks/frameworks/eliza-os-character.mdx index 8ec6d95cc..af8892660 100644 --- a/docs/cookbooks/frameworks/eliza-os-character.mdx +++ b/docs/cookbooks/frameworks/eliza-os-character.mdx @@ -42,7 +42,7 @@ Create a `.env` file in the root of the project and add the following (you can u ```bash # Mem0 Configuration -MEM0_API_KEY= # Mem0 API Key (get from https://app.mem0.ai/dashboard/api-keys) +MEM0_API_KEY= # Mem0 API Key (get from https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=cookbook-eliza-os) MEM0_USER_ID= # Default: eliza-os-user MEM0_PROVIDER= # Default: openai MEM0_PROVIDER_API_KEY= # API Key for the provider (OpenAI, Anthropic, etc.) diff --git a/docs/cookbooks/frameworks/gemini-3-with-mem0-mcp.mdx b/docs/cookbooks/frameworks/gemini-3-with-mem0-mcp.mdx index 7cb15788e..4ed81087e 100644 --- a/docs/cookbooks/frameworks/gemini-3-with-mem0-mcp.mdx +++ b/docs/cookbooks/frameworks/gemini-3-with-mem0-mcp.mdx @@ -55,7 +55,7 @@ GEMINI_API_KEY=your-gemini-api-key-here ``` -Ensure you have your Mem0 API key from the Mem0 Dashboard and your Gemini API key from the [Google AI Studio](https://ai.studio/app/api-keys). +Ensure you have your Mem0 API key from the Mem0 Dashboard and your Gemini API key from the [Google AI Studio](https://ai.studio/app/api-keys). ## Gemini Memory Agent diff --git a/docs/cookbooks/frameworks/llamaindex-multiagent.mdx b/docs/cookbooks/frameworks/llamaindex-multiagent.mdx index cc6349a2c..92ab6d945 100644 --- a/docs/cookbooks/frameworks/llamaindex-multiagent.mdx +++ b/docs/cookbooks/frameworks/llamaindex-multiagent.mdx @@ -41,7 +41,7 @@ Set up your environment variables: - `MEM0_API_KEY`: Your Mem0 Platform API key - `OPENAI_API_KEY`: Your OpenAI API key -You can obtain your Mem0 Platform API key from the Mem0 Platform. +You can obtain your Mem0 Platform API key from the Mem0 Platform. ## Complete Implementation @@ -357,7 +357,7 @@ Based on our previous session, I remember we covered Vision Language Models and ## Help & Resources - [LlamaIndex Agent Workflows](https://docs.llamaindex.ai/en/stable/use_cases/agents/) -- Mem0 Platform +- Mem0 Platform --- diff --git a/docs/cookbooks/frameworks/llamaindex-react.mdx b/docs/cookbooks/frameworks/llamaindex-react.mdx index 343c074e6..31e5fe565 100644 --- a/docs/cookbooks/frameworks/llamaindex-react.mdx +++ b/docs/cookbooks/frameworks/llamaindex-react.mdx @@ -25,7 +25,7 @@ os.environ["OPENAI_API_KEY"] = "" llm = OpenAI(model="gpt-5-mini") ``` -Initialize the Mem0 client. You can find your API key here. Read about Mem0 [Open Source](https://docs.mem0.ai/open-source/overview). +Initialize the Mem0 client. You can find your API key here. Read about Mem0 [Open Source](https://docs.mem0.ai/open-source/overview). ```python os.environ["MEM0_API_KEY"] = "" diff --git a/docs/cookbooks/integrations/agents-sdk-tool.mdx b/docs/cookbooks/integrations/agents-sdk-tool.mdx index ca1fc215d..53647e734 100644 --- a/docs/cookbooks/integrations/agents-sdk-tool.mdx +++ b/docs/cookbooks/integrations/agents-sdk-tool.mdx @@ -223,7 +223,7 @@ context = Mem0Context(user_id="user123") ## Resources - [Mem0 Documentation](https://docs.mem0.ai/introduction) -- Mem0 Dashboard +- Mem0 Dashboard - [API Reference](https://docs.mem0.ai/api-reference) --- diff --git a/docs/cookbooks/integrations/openai-tool-calls.mdx b/docs/cookbooks/integrations/openai-tool-calls.mdx index 8bc607ac6..4e437cda3 100644 --- a/docs/cookbooks/integrations/openai-tool-calls.mdx +++ b/docs/cookbooks/integrations/openai-tool-calls.mdx @@ -23,7 +23,7 @@ MEM0_API_KEY=your_mem0_api_key OPENAI_API_KEY=your_openai_api_key ``` -Get your Mem0 API key from the Mem0 Dashboard. +Get your Mem0 API key from the Mem0 Dashboard. ### Configuration @@ -303,7 +303,7 @@ run().catch(console.error); ## Resources - [Mem0 Documentation](https://docs.mem0.ai/introduction) -- Mem0 Dashboard +- Mem0 Dashboard - [API Reference](https://docs.mem0.ai/api-reference) - [OpenAI Documentation](https://platform.openai.com/docs) diff --git a/docs/docs.json b/docs/docs.json index aafc9f099..f77d05f26 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -153,6 +153,7 @@ "icon": "rocket", "pages": [ "open-source/overview", + "open-source/setup", "vibecoding", "open-source/python-quickstart", "open-source/node-quickstart" @@ -578,7 +579,7 @@ "primary": { "type": "button", "label": "Your Dashboard", - "href": "https://app.mem0.ai" + "href": "https://app.mem0.ai?utm_source=oss&utm_medium=docs-nav" } }, "footer": { @@ -608,7 +609,7 @@ "title": "Try in Playground", "description": "Open this example in the interactive Mem0 playground", "icon": "play", - "href": "https://app.mem0.ai/playground" + "href": "https://app.mem0.ai/playground?utm_source=oss&utm_medium=docs-nav" } ] }, diff --git a/docs/integrations/agentops.mdx b/docs/integrations/agentops.mdx index b32bf12af..656e312b6 100644 --- a/docs/integrations/agentops.mdx +++ b/docs/integrations/agentops.mdx @@ -24,7 +24,7 @@ pip install mem0ai agentops python-dotenv 2. Valid API keys: - [AgentOps API Key](https://app.agentops.ai/dashboard/api-keys) - OpenAI API Key (for LLM operations) - - Mem0 API Key (optional, for cloud operations) + - Mem0 API Key (optional, for cloud operations) ## Basic Integration Example diff --git a/docs/integrations/agno.mdx b/docs/integrations/agno.mdx index 2dbf967f7..a4a32a791 100644 --- a/docs/integrations/agno.mdx +++ b/docs/integrations/agno.mdx @@ -23,7 +23,7 @@ pip install agno mem0ai python-dotenv ``` 2. Valid API keys: - - Mem0 API Key + - Mem0 API Key - OpenAI API Key (for the agent model) ## Quick Integration (Using `Mem0Tools`) diff --git a/docs/integrations/autogen.mdx b/docs/integrations/autogen.mdx index 18192c11c..a7d12947c 100644 --- a/docs/integrations/autogen.mdx +++ b/docs/integrations/autogen.mdx @@ -19,7 +19,7 @@ pip install autogen mem0ai openai python-dotenv First, we'll import the necessary libraries and set up our configurations. -Remember to get the Mem0 API key from Mem0 Platform. +Remember to get the Mem0 API key from Mem0 Platform. ```python import os @@ -32,7 +32,7 @@ load_dotenv() # Configuration # OPENAI_API_KEY = 'sk-xxx' # Replace with your actual OpenAI API key -# MEM0_API_KEY = 'your-mem0-key' # Replace with your actual Mem0 API key from https://app.mem0.ai +# MEM0_API_KEY = 'your-mem0-key' # Replace with your actual Mem0 API key from https://app.mem0.ai?utm_source=oss&utm_medium=integration-autogen USER_ID = "alice" # Set up OpenAI API key diff --git a/docs/integrations/chatdev.mdx b/docs/integrations/chatdev.mdx index 4e33d1ad5..7a50a64c6 100644 --- a/docs/integrations/chatdev.mdx +++ b/docs/integrations/chatdev.mdx @@ -18,7 +18,7 @@ In this guide, you'll: - **Python 3.12+** - **[uv](https://docs.astral.sh/uv/)** β€” Python package manager - **Node.js 18+** and **npm** β€” only needed if using the web console -- A **Mem0 API key** from app.mem0.ai +- A **Mem0 API key** from app.mem0.ai - An **OpenAI API key** (or another LLM provider supported by ChatDev) ## Setup and Configuration @@ -39,7 +39,7 @@ cd frontend && npm install && cd .. Set up your environment variables in a `.env` file: -Get your Mem0 API key from Mem0 Platform. +Get your Mem0 API key from Mem0 Platform. ```bash MEM0_API_KEY=your-mem0-api-key @@ -194,7 +194,7 @@ This means retrieval returns memories from **both** the user's scope and the age | Field | Required | Description | |-------|----------|-------------| -| `api_key` | Yes | Mem0 API key from app.mem0.ai | +| `api_key` | Yes | Mem0 API key from app.mem0.ai | | `user_id` | No | Scope memories to a specific user | | `agent_id` | No | Scope memories to a specific agent | @@ -216,9 +216,9 @@ This means retrieval returns memories from **both** the user's scope and the age - **No memories returned on first run** β€” This is expected. Memories are stored *after* the agent responds, so the first interaction has no prior context. Memories appear starting from the second interaction onward. - **`mem0ai` not installed** β€” If you see `ImportError: mem0ai is required for Mem0Memory`, run `uv add mem0ai` or `pip install mem0ai` to add the dependency. -- **Invalid API key** β€” A wrong or expired `MEM0_API_KEY` will log errors like `Mem0 search failed` or `Mem0 add failed` but won't crash the agent. Check your key at app.mem0.ai. +- **Invalid API key** β€” A wrong or expired `MEM0_API_KEY` will log errors like `Mem0 search failed` or `Mem0 add failed` but won't crash the agent. Check your key at app.mem0.ai. - **Pipeline headers in memories** β€” ChatDev automatically strips internal pipeline headers (e.g., `=== INPUT FROM TASK (user) ===`) before sending text to Mem0, so your memories stay clean. -- **Clearing test memories** β€” To delete memories created during testing, use the Mem0 dashboard at app.mem0.ai or the Python SDK: `MemoryClient().delete_all(user_id="your-test-user")`. +- **Clearing test memories** β€” To delete memories created during testing, use the Mem0 dashboard at app.mem0.ai or the Python SDK: `MemoryClient().delete_all(user_id="your-test-user")`. ## Key Features diff --git a/docs/integrations/claude-code.mdx b/docs/integrations/claude-code.mdx index e7cc527f9..782e3d05b 100644 --- a/docs/integrations/claude-code.mdx +++ b/docs/integrations/claude-code.mdx @@ -17,8 +17,8 @@ Add persistent memory to [**Claude Code**](https://docs.anthropic.com/en/docs/cl Before setting up Mem0 with Claude Code, ensure you have: 1. A Mem0 Platform account and API key: - - Sign up at app.mem0.ai - - Get your API key (starts with `m0-`) + - Sign up at app.mem0.ai + - Get your API key (starts with `m0-`) 2. Claude Code CLI or Claude Cowork desktop app installed diff --git a/docs/integrations/codex.mdx b/docs/integrations/codex.mdx index 9c161fd99..e0647e1cc 100644 --- a/docs/integrations/codex.mdx +++ b/docs/integrations/codex.mdx @@ -17,8 +17,8 @@ Add persistent memory to [**OpenAI Codex**](https://openai.com/index/codex/) wit Before setting up Mem0 with Codex, ensure you have: 1. A Mem0 Platform account and API key: - - Sign up at app.mem0.ai - - Get your API key (starts with `m0-`) + - Sign up at app.mem0.ai + - Get your API key (starts with `m0-`) 2. OpenAI Codex access diff --git a/docs/integrations/crewai.mdx b/docs/integrations/crewai.mdx index aeef25783..22a085d3f 100644 --- a/docs/integrations/crewai.mdx +++ b/docs/integrations/crewai.mdx @@ -22,7 +22,7 @@ pip install crewai crewai-tools mem0ai Import required modules and set up configurations: -Remember to get your API keys from Mem0 Platform, [OpenAI](https://platform.openai.com) and [Serper Dev](https://serper.dev) for search capabilities. +Remember to get your API keys from Mem0 Platform, [OpenAI](https://platform.openai.com) and [Serper Dev](https://serper.dev) for search capabilities. ```python import os diff --git a/docs/integrations/cursor.mdx b/docs/integrations/cursor.mdx index bae397695..61e7a8dec 100644 --- a/docs/integrations/cursor.mdx +++ b/docs/integrations/cursor.mdx @@ -17,8 +17,8 @@ Add persistent memory to [**Cursor**](https://cursor.com) with the Mem0 plugin. Before setting up Mem0 with Cursor, ensure you have: 1. A Mem0 Platform account and API key: - - Sign up at app.mem0.ai - - Get your API key (starts with `m0-`) + - Sign up at app.mem0.ai + - Get your API key (starts with `m0-`) 2. Cursor installed ([cursor.com](https://cursor.com)) diff --git a/docs/integrations/flowise.mdx b/docs/integrations/flowise.mdx index 6438cb61b..f1c8b72b2 100644 --- a/docs/integrations/flowise.mdx +++ b/docs/integrations/flowise.mdx @@ -38,7 +38,7 @@ npx flowise start ### 2. Obtain Your Mem0 API Key -1. Navigate to the Mem0 API Key dashboard. +1. Navigate to the Mem0 API Key dashboard. 2. Generate or copy your existing Mem0 API Key. ![Mem0 API Key](https://raw.githubusercontent.com/FlowiseAI/FlowiseDocs/main/en/.gitbook/assets/mem0/api-key.png) @@ -70,7 +70,7 @@ Test your memory configuration: 1. Save your Flowise configuration 2. Run a test chat and store some information -3. Verify the stored memories in the Mem0 Dashboard +3. Verify the stored memories in the Mem0 Dashboard ![Flowise Test Chat](https://raw.githubusercontent.com/FlowiseAI/FlowiseDocs/main/en/.gitbook/assets/mem0/flowise-chat-1.png) @@ -103,7 +103,7 @@ Available settings include: ### Platform Configuration -Additional settings available in Mem0 Project Settings: +Additional settings available in Mem0 Project Settings: 1. **Custom Instructions**: Define memory extraction rules 2. **Expiration Date**: Set automatic memory cleanup periods diff --git a/docs/integrations/google-ai-adk.mdx b/docs/integrations/google-ai-adk.mdx index 43f6019a5..d8b5d5e8f 100644 --- a/docs/integrations/google-ai-adk.mdx +++ b/docs/integrations/google-ai-adk.mdx @@ -22,7 +22,7 @@ pip install google-adk mem0ai python-dotenv ``` 2. Valid API keys: - - Mem0 API Key + - Mem0 API Key - Google AI Studio API Key ## Basic Integration Example diff --git a/docs/integrations/hermes.mdx b/docs/integrations/hermes.mdx index 2ba2e8524..51349a477 100644 --- a/docs/integrations/hermes.mdx +++ b/docs/integrations/hermes.mdx @@ -52,7 +52,7 @@ hermes memory setup Select **mem0** as the provider and enter your Mem0 API key when prompted. The wizard writes your config to `~/.hermes/mem0.json`. -Get your API key from app.mem0.ai. +Get your API key from app.mem0.ai. ### Option 2: Manual Configuration diff --git a/docs/integrations/keywords.mdx b/docs/integrations/keywords.mdx index 0b19c825a..919b0c028 100644 --- a/docs/integrations/keywords.mdx +++ b/docs/integrations/keywords.mdx @@ -16,7 +16,7 @@ Combining Mem0 with Keywords AI allows you to: 4. Optimize token usage and reduce costs -You can get your Mem0 API key from the Mem0 dashboard. +You can get your Mem0 API key from the Mem0 dashboard. ## Setup and Configuration diff --git a/docs/integrations/langchain.mdx b/docs/integrations/langchain.mdx index b2dfd3633..6f7a3df5a 100644 --- a/docs/integrations/langchain.mdx +++ b/docs/integrations/langchain.mdx @@ -22,7 +22,7 @@ pip install langchain langchain_openai mem0ai python-dotenv Import required modules and set up configurations: -Remember to get the Mem0 API key from Mem0 Platform. +Remember to get the Mem0 API key from Mem0 Platform. ```python import os diff --git a/docs/integrations/langgraph.mdx b/docs/integrations/langgraph.mdx index 2a5529b1d..4254b225b 100644 --- a/docs/integrations/langgraph.mdx +++ b/docs/integrations/langgraph.mdx @@ -23,7 +23,7 @@ pip install langgraph langchain-openai mem0ai python-dotenv Import required modules and set up configurations: -Remember to get the Mem0 API key from Mem0 Platform. +Remember to get the Mem0 API key from Mem0 Platform. ```python from typing import Annotated, TypedDict, List diff --git a/docs/integrations/llama-index.mdx b/docs/integrations/llama-index.mdx index 8ed19d83d..c6e91388e 100644 --- a/docs/integrations/llama-index.mdx +++ b/docs/integrations/llama-index.mdx @@ -22,7 +22,7 @@ pip install llama-index-core llama-index-memory-mem0 python-dotenv Set your Mem0 Platform API key as an environment variable. You can replace `` with your actual API key: - You can obtain your Mem0 Platform API key from the Mem0 Platform. + You can obtain your Mem0 Platform API key from the Mem0 Platform. ```python diff --git a/docs/integrations/mastra.mdx b/docs/integrations/mastra.mdx index cc7a9ba46..684db1260 100644 --- a/docs/integrations/mastra.mdx +++ b/docs/integrations/mastra.mdx @@ -23,7 +23,7 @@ npm install @mastra/core @mastra/mem0 @ai-sdk/openai zod Set up your environment variables: -Remember to get the Mem0 API key from Mem0 Platform. +Remember to get the Mem0 API key from Mem0 Platform. ```bash MEM0_API_KEY=your-mem0-api-key diff --git a/docs/integrations/openai-agents-sdk.mdx b/docs/integrations/openai-agents-sdk.mdx index eceacd132..348d8e608 100644 --- a/docs/integrations/openai-agents-sdk.mdx +++ b/docs/integrations/openai-agents-sdk.mdx @@ -22,7 +22,7 @@ pip install openai-agents mem0ai ``` 2. Valid API keys: - - Mem0 API Key + - Mem0 API Key - [OpenAI API Key](https://platform.openai.com/api-keys) ## Basic Integration Example diff --git a/docs/integrations/openclaw.mdx b/docs/integrations/openclaw.mdx index 8c2cfc918..06157e253 100644 --- a/docs/integrations/openclaw.mdx +++ b/docs/integrations/openclaw.mdx @@ -114,7 +114,7 @@ That's it. No API key, no config file editing, no environment variables. The plu - Get your API key from app.mem0.ai. + Get your API key from app.mem0.ai. diff --git a/docs/integrations/raycast.mdx b/docs/integrations/raycast.mdx index df1f69865..9b6c3ba28 100644 --- a/docs/integrations/raycast.mdx +++ b/docs/integrations/raycast.mdx @@ -9,7 +9,7 @@ Mem0 is a self-improving memory layer for LLM applications, enabling personalize **Get your API Key**: You'll need a Mem0 API key to use this extension: -a. Sign up at app.mem0.ai +a. Sign up at app.mem0.ai b. Navigate to your API Keys page diff --git a/docs/integrations/vercel-ai-sdk.mdx b/docs/integrations/vercel-ai-sdk.mdx index e0676058e..cb0ae112f 100644 --- a/docs/integrations/vercel-ai-sdk.mdx +++ b/docs/integrations/vercel-ai-sdk.mdx @@ -29,7 +29,7 @@ npm install @mem0/vercel-ai-provider ### Setting Up Mem0 -1. Get your **Mem0 API Key** from the Mem0 Dashboard. +1. Get your **Mem0 API Key** from the Mem0 Dashboard. 2. Initialize the Mem0 Client in your application: diff --git a/docs/llms.txt b/docs/llms.txt index 54ded1e07..1725f45ab 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -161,6 +161,7 @@ If the user is on a pre-current major (Python < 2, TS < 3, or Platform `output_f - [Open Source Configuration](https://docs.mem0.ai/open-source/configuration) [OSS]: Use when configuring `Memory` - LLM, embedder, vector store, graph store. - [Open Source Python Quickstart](https://docs.mem0.ai/open-source/python-quickstart) [OSS]: Use for the first self-hosted Python integration. - [Open Source Node.js Quickstart](https://docs.mem0.ai/open-source/node-quickstart) [OSS]: Use for the first self-hosted Node integration. +- [Self-Hosted Setup](https://docs.mem0.ai/open-source/setup) [OSS]: Use when standing up the bundled REST server and dashboard via Docker Compose, including auth, API keys, and the setup wizard. ## Core Concepts diff --git a/docs/migration/oss-to-platform.mdx b/docs/migration/oss-to-platform.mdx index 24f5c1494..2af242682 100644 --- a/docs/migration/oss-to-platform.mdx +++ b/docs/migration/oss-to-platform.mdx @@ -28,7 +28,7 @@ Move your Mem0 implementation to managed infrastructure with enterprise features ## Plan -1. **Sign up**: Create an account on Mem0 Platform. +1. **Sign up**: Create an account on Mem0 Platform. 2. **Get API Key**: Navigate to **Settings > API Keys** and generate a new key. 3. **Review Usage**: Identify where you instantiate `Memory` and where you call `search` or `get_all`. @@ -372,7 +372,7 @@ If you encounter issues, you can revert immediately by switching your import bac ## Next Steps -- Platform Dashboard - Monitor usage and manage settings. +- Platform Dashboard - Monitor usage and manage settings. - [Webhooks Setup](/platform/features/webhooks) - Configure real-time event notifications. - [Organizations & Projects](/api-reference/organizations-projects) - Set up multi-tenancy for your team. diff --git a/docs/open-source/features/rest-api.mdx b/docs/open-source/features/rest-api.mdx index 576b98c1b..a6ef488c4 100644 --- a/docs/open-source/features/rest-api.mdx +++ b/docs/open-source/features/rest-api.mdx @@ -13,6 +13,10 @@ The Mem0 REST API server exposes every OSS memory operation over HTTP. Run it al - You plan to explore or debug endpoints through the built-in OpenAPI page at `/docs`. + + **First time self-hosting, or upgrading from a pre-1.x build?** Start at [Self-Hosted Setup](/open-source/setup). It walks through the stack, the setup wizard, and the upgrade path for deployments that relied on open endpoints or `ADMIN_API_KEY`. This page covers the API surface and auth modes only. + + **OSS vs Platform API paths:** The self-hosted OSS server does **not** use the `/v1/` prefix. For example, the endpoint is `POST /memories`, not `POST /v1/memories/`. The [API Reference](/api-reference) documents the hosted platform at `api.mem0.ai` which uses `/v1/` paths β€” those do not apply to the OSS server. @@ -26,7 +30,7 @@ The Mem0 REST API server exposes every OSS memory operation over HTTP. Run it al ## Feature - **CRUD endpoints:** Create, retrieve, search, update, delete, and reset memories by `user_id`, `agent_id`, or `run_id`. -- **API key authentication:** Optionally secure all endpoints with a shared API key via the `X-API-Key` header. +- **Authentication:** On by default. Dashboard sessions use JWTs; programmatic clients use per-user `X-API-Key` headers. Legacy `ADMIN_API_KEY` is still supported. - **Status health check:** Access base routes to confirm the server is online. - **OpenAPI explorer:** Visit `/docs` for interactive testing and schema reference. @@ -40,51 +44,75 @@ The Mem0 REST API server exposes every OSS memory operation over HTTP. Run it al 1. Create `server/.env` with your keys: -```bash -OPENAI_API_KEY=your-openai-api-key -``` + ```bash + OPENAI_API_KEY=your-openai-api-key + JWT_SECRET=$(openssl rand -base64 48) + ``` -2. Start the stack: +2. Bootstrap the stack in one command: -```bash -cd server -docker compose up -``` + ```bash + cd server + make bootstrap # starts Compose, creates an admin, issues the first API key + ``` -3. Reach the API at `http://localhost:8888`. Edits to the server or library auto-reload. + Or to start the stack only and finish setup via the browser wizard at http://localhost:3000: + + ```bash + cd server + docker compose up -d + ``` + +3. API is at `http://localhost:8888`. Code edits auto-reload. -### Run with Docker + + + **Run with Docker** - - + + ```bash docker pull mem0/mem0-api-server ``` - - + + ```bash docker build -t mem0-api-server . ``` - - + + -1. Create a `.env` file with `OPENAI_API_KEY`. -2. Run the container: + 1. Create a `.env` file with `OPENAI_API_KEY` and `JWT_SECRET`. + 2. Run the container: -```bash -docker run -p 8000:8000 --env-file .env mem0-api-server -``` + ```bash + docker run -p 8000:8000 --env-file .env mem0-api-server + ``` -3. Visit `http://localhost:8000`. + 3. Visit `http://localhost:8000`. -### Run directly (no Docker) + **Run directly (no Docker)** -```bash -pip install -r requirements.txt -uvicorn main:app --reload -``` + + This path skips Docker and assumes Postgres is already running and reachable at `POSTGRES_HOST:POSTGRES_PORT`. For a single-command local setup with Postgres included, use Docker Compose above. + + + ```bash + pip install -r requirements.txt + uvicorn main:app --reload + ``` + + + + + Compose publishes internal port 8000 as 8888 on the host. Raw Docker and raw uvicorn listen on 8000 unless remapped. + + + + `JWT_SECRET` is required once auth is enabled β€” the server returns `500` on auth endpoints if it's unset. Generate one with `openssl rand -base64 48`. See [Self-Hosted Setup](/open-source/setup#configure-the-environment) for the full env var table. + Use a process manager such as `systemd`, Supervisor, or PM2 when deploying the FastAPI server for production resilience. @@ -98,35 +126,74 @@ uvicorn main:app --reload ## Authentication -The server supports optional API key authentication. When the `ADMIN_API_KEY` environment variable is set, every endpoint requires a valid `X-API-Key` header. The `/` redirect, `/docs`, and `/openapi.json` routes remain open so you can always reach the interactive API explorer. +Auth is on by default. Protected endpoints require either a JWT (from the dashboard login flow) or an `X-API-Key` header. The `/` redirect, `/docs`, and `/openapi.json` routes stay open so you can reach the OpenAPI explorer. -| `ADMIN_API_KEY` value | Behavior | -|---|---| -| Not set / empty | All endpoints are open (no auth) | -| Any non-empty string | Requests must include `X-API-Key: ` | +| Mode | How to send it | When to use it | +|---|---|---| +| Bearer JWT | `Authorization: Bearer ` | Dashboard sessions; tokens come from `POST /auth/login` and refresh via `POST /auth/refresh` | +| Per-user API key | `X-API-Key: m0sk_...` | Programmatic access scoped to a single dashboard user | +| Legacy `ADMIN_API_KEY` | `X-API-Key: ` | Back-compat for deployments that set the `ADMIN_API_KEY` env var | +| `AUTH_DISABLED=true` | β€” | Local development only; bypasses auth entirely | -### Enable authentication +The `/docs` OpenAPI explorer supports both auth modes. Click **Authorize** at the top of the page and paste either `Bearer ` (JWT) or your `X-API-Key` value. Protected endpoints return `401` until you authorize. -Add the key to your `.env` file: +### Log in and use a JWT + +Register the first admin (only works when no user exists yet), then log in: ```bash -ADMIN_API_KEY=your-secret-api-key +# First admin only β€” returns 403 after the first admin is registered +curl -X POST http://localhost:8888/auth/register \ + -H "Content-Type: application/json" \ + -d '{"name": "Admin", "email": "admin@example.com", "password": "strong-password"}' ``` -Then include the header in every request: +```bash +curl -X POST http://localhost:8888/auth/login \ + -H "Content-Type: application/json" \ + -d '{"email": "admin@example.com", "password": "your-password"}' +``` + +Use the returned `access_token` as a bearer token: ```bash -curl -X POST http://localhost:8000/memories \ +curl -X POST http://localhost:8888/memories \ -H "Content-Type: application/json" \ - -H "X-API-Key: your-secret-api-key" \ + -H "Authorization: Bearer " \ -d '{ "messages": [{"role": "user", "content": "I love pizza."}], "user_id": "alice" }' ``` +When the access token expires, exchange the refresh token at `POST /auth/refresh`. + +### Create and use a per-user API key + +Create a key from the dashboard **API Keys** page, or call `POST /api-keys` with a JWT. The full `m0sk_...` value is returned **once** at creation time β€” store it securely. + +```bash +curl -X POST http://localhost:8888/memories \ + -H "Content-Type: application/json" \ + -H "X-API-Key: m0sk_your_key_here" \ + -d '{ + "messages": [{"role": "user", "content": "I love pizza."}], + "user_id": "alice" + }' +``` + +Per-user keys inherit the creating user's scope. List or revoke them via `GET /api-keys` and `DELETE /api-keys/{id}`. + +### Legacy `ADMIN_API_KEY` + +Set the `ADMIN_API_KEY` environment variable and send it as `X-API-Key`. The request is treated as admin-level and is not tied to a dashboard user. This mode is kept for back-compat with older self-hosted deployments β€” prefer JWT or per-user keys for new setups. + +```bash +ADMIN_API_KEY=your-long-admin-key +``` + - The server logs a warning at startup when `ADMIN_API_KEY` is not set. Always set it in production. + Setting `AUTH_DISABLED=true` makes every protected endpoint open β€” the server logs a warning at startup when it's enabled. The server also warns when `ADMIN_API_KEY` is shorter than 16 characters. Never enable `AUTH_DISABLED` in production, and always use a long `ADMIN_API_KEY` if you rely on the legacy fallback. --- @@ -136,7 +203,7 @@ curl -X POST http://localhost:8000/memories \ ### Create and search memories via HTTP ```bash -curl -X POST http://localhost:8000/memories \ +curl -X POST http://localhost:8888/memories \ -H "Content-Type: application/json" \ -d '{ "messages": [ @@ -151,7 +218,7 @@ curl -X POST http://localhost:8000/memories \ ```bash -curl -X POST http://localhost:8000/search \ +curl -X POST http://localhost:8888/search \ -H "Content-Type: application/json" \ -d '{ "query": "vegetable", @@ -161,7 +228,7 @@ curl -X POST http://localhost:8000/search \ ### Explore with OpenAPI docs -1. Navigate to `http://localhost:8000/docs`. +1. Navigate to `http://localhost:8888/docs` (Compose) or `http://localhost:8000/docs` (raw Docker / uvicorn). 2. Pick an endpoint (e.g., `POST /search`). 3. Fill in parameters and click **Execute** to try requests in-browser. @@ -175,9 +242,13 @@ curl -X POST http://localhost:8000/search \ The OSS REST server exposes the following endpoints. None use the `/v1/` prefix. +### Memory operations + | Method | Path | Description | |--------|------|-------------| -| `POST` | `/configure` | Set memory configuration | +| `POST` | `/configure` | Set memory configuration. Rejects unbundled providers with a 400 | +| `GET` | `/configure` | Get the current memory configuration | +| `GET` | `/configure/providers` | List the LLM and embedder providers bundled in the container | | `POST` | `/memories` | Create memories | | `GET` | `/memories` | Get all memories (filter by `user_id`, `agent_id`, or `run_id`) | | `GET` | `/memories/{memory_id}` | Get a specific memory | @@ -188,6 +259,43 @@ The OSS REST server exposes the following endpoints. None use the `/v1/` prefix. | `POST` | `/search` | Search memories | | `POST` | `/reset` | Reset all memories | +### Authentication + +| Method | Path | Description | +|--------|------|-------------| +| `GET` | `/auth/setup-status` | Returns `{needsSetup: bool}`. Open, no auth required | +| `POST` | `/auth/register` | Register the first admin. Registration closes after the first admin is created; additional accounts are provisioned by the existing admin. | +| `POST` | `/auth/login` | Exchange email and password for access and refresh JWTs | +| `POST` | `/auth/refresh` | Exchange a refresh token for a new access token | +| `GET` | `/auth/me` | Get the current authenticated user (JWT required) | +| `PATCH` | `/auth/me` | Update the caller's name or email. 409 if the new email is already in use | +| `POST` | `/auth/change-password` | Change the caller's password. 401 if the current password is wrong; new password must be at least 8 characters | + +### API keys + +All `/api-keys` endpoints require a JWT. + +| Method | Path | Description | +|--------|------|-------------| +| `GET` | `/api-keys` | List the caller's API keys | +| `POST` | `/api-keys` | Create a new key; the full `m0sk_...` value is returned once | +| `DELETE` | `/api-keys/{id}` | Revoke an API key | + +### Request logs + +| Method | Path | Description | +|--------|------|-------------| +| `GET` | `/requests?limit=N` | Recent API call log (JWT or admin key) | + +### Entities + +| Method | Path | Description | +|--------|------|-------------| +| `GET` | `/entities` | Distinct `user_id` / `agent_id` / `run_id` values with memory counts | +| `DELETE` | `/entities/{entity_type}/{entity_id}` | Cascade-delete all memories for an entity; `entity_type` is `user`, `agent`, or `run` | + +The `/auth/*`, `/api-keys`, `/requests`, and `/entities` routes are new to the self-hosted server and primarily back the dashboard, but you can call them directly from your own tooling. + --- ## Verify the feature is working @@ -201,7 +309,7 @@ The OSS REST server exposes the following endpoints. None use the `/v1/` prefix. ## Best practices -1. **Enable authentication:** Set `ADMIN_API_KEY` to secure all endpoints, or use an API gateway for more advanced schemes. +1. **Keep auth on:** Auth is enabled by default. Never set `AUTH_DISABLED=true` in production. If you rely on `ADMIN_API_KEY`, use a long value (16+ chars) or prefer per-user API keys. 2. **Use HTTPS:** Terminate TLS at your load balancer or reverse proxy. 3. **Monitor uptime:** Track request rates, latency, and error codes per endpoint. 4. **Version configs:** Keep environment files and Docker Compose definitions in source control. diff --git a/docs/open-source/overview.mdx b/docs/open-source/overview.mdx index 7b2edb6e5..450e8e900 100644 --- a/docs/open-source/overview.mdx +++ b/docs/open-source/overview.mdx @@ -15,12 +15,15 @@ Mem0 Open Source delivers the same adaptive memory engine as the platform, but p - **Extendable codebase**: Fork the repo, add providers, and ship custom automations. - Begin with the Python quickstart (or the Node.js variant) to clone the repo, configure dependencies, and validate memory reads/writes locally. + Two ways to run Mem0 OSS: as a **library** inside your app (Python or Node), or as a **self-hosted server** with a dashboard, per-user API keys, and a request audit log. ## Choose your path - + + + Run `make bootstrap` to launch the server + dashboard, create an admin, and issue your first API key. + Bootstrap CLI and verify add/search loop. @@ -41,15 +44,6 @@ Mem0 Open Source delivers the same adaptive memory engine as the platform, but p - - - Reference deployment with REST endpoints. - - - Async add/search flows and automation. - - - Need a managed alternative? Compare hosting models in the Platform vs OSS guide or switch tabs to the Platform documentation. @@ -70,19 +64,27 @@ Mem0 Open Source delivers the same adaptive memory engine as the platform, but p ## Default components - Mem0 OSS works out of the box with sensible defaults: + **Library defaults** (when you `import` Mem0 and call `Memory()` directly): - LLM: OpenAI `gpt-5-mini` (via `OPENAI_API_KEY`) - Embeddings: OpenAI `text-embedding-3-small` - - Vector store: Local Qdrant instance storing data at `/tmp/qdrant` - - History store: SQLite database at `~/.mem0/history.db` - - Reranker: Disabled until you configure a provider + - Vector store: Local Qdrant at `/tmp/qdrant` + - History store: SQLite at `~/.mem0/history.db` + - Reranker: Disabled until configured Override any component with `Memory.from_config`. -## Keep going + + **Self-hosted server defaults** (the `server/` Docker Compose stack): + - LLM: OpenAI `gpt-4.1-nano-2025-04-14` (override with `MEM0_DEFAULT_LLM_MODEL`) + - Embeddings: OpenAI `text-embedding-3-small` (override with `MEM0_DEFAULT_EMBEDDER_MODEL`) + - Vector store: Postgres + pgvector + - Bundled providers: `openai`, `anthropic`, `gemini` β€” switch from the Configuration page -{/* DEBUG: verify CTA targets */} + See Self-Hosted Setup for the full provider list and how to extend it. + + +## Keep going - - - Need a managed alternative? Compare hosting models in the Platform vs OSS guide or switch tabs to the Platform documentation. - diff --git a/docs/open-source/setup.mdx b/docs/open-source/setup.mdx new file mode 100644 index 000000000..b6f630126 --- /dev/null +++ b/docs/open-source/setup.mdx @@ -0,0 +1,218 @@ +--- +title: "Self-Hosted Setup" +description: "Stand up the Mem0 REST server and dashboard in a few minutes β€” admin account, API keys, and a live audit log included." +icon: "rocket-launch" +--- + +The self-hosted bundle ships the REST API and a web dashboard together. Configure your LLM provider and secrets in a `.env` file, start the containers, then choose how to create your admin account: through the browser-based setup wizard, or from the command line. + + + **Use this page when…** + - You want a self-hosted Mem0 with a dashboard, not just the Python or Node library. + - You need per-user API keys and a request audit log for your team. + - You're upgrading from a pre-1.x server that relied on `ADMIN_API_KEY` or open endpoints. + + + + **Upgrading from 1.x?** Auth is now on by default. Deployments that ran with an empty `ADMIN_API_KEY` will return `401` on every protected endpoint until you either set `ADMIN_API_KEY`, register an admin through the wizard, or set `AUTH_DISABLED=true` for local development. See [Upgrade notes](#upgrade-notes) below. + + +--- + +## Prerequisites + +- Docker and Docker Compose (the reference path). +- An `OPENAI_API_KEY` (or equivalent β€” the server reads the same component config as the library). +- A free port `8888` for the API and `3000` for the dashboard. + +--- + +## Configure the environment + +Copy `server/.env.example` to `server/.env` and fill in the required values. The server refuses to start if `JWT_SECRET` is unset once auth is enabled. + +| Variable | Required | Purpose | +|---|---|---| +| `OPENAI_API_KEY` | Yes | Default LLM and embedder provider. | +| `JWT_SECRET` | Yes | Signs access and refresh tokens. Use a long random value. A missing secret causes auth endpoints to return `500`. | +| `ADMIN_API_KEY` | Optional | Legacy shared admin key. Kept for back-compat; prefer per-user keys for new setups. | +| `AUTH_DISABLED` | Optional | `true` turns off auth for local development only. Never enable in production. | +| `DASHBOARD_URL` | Optional | Origin the API accepts for CORS. Defaults to `http://localhost:3000`. Set this when you front the dashboard on a custom domain. | +| `POSTGRES_*` | Optional | Override the bundled Postgres / pgvector connection. | + + + Generate a `JWT_SECRET` with `openssl rand -base64 48` or `python -c "import secrets; print(secrets.token_urlsafe(48))"`. + + +--- + +## Start the stack + +Pick the path that fits your workflow. + +### Browser-first (setup wizard) + +```bash +cd server +make up +``` + +This starts the containers and runs database migrations. The REST API listens on `http://localhost:8888` and the dashboard on `http://localhost:3000`. + +Open `http://localhost:3000` β€” since no admin account exists yet, the dashboard redirects to the one-time setup wizard at `/setup`. See [Run the setup wizard](#run-the-setup-wizard) below. + +### Agent-first (command line) + +First, set `OPENAI_API_KEY` (or `ANTHROPIC_API_KEY` / `GOOGLE_API_KEY`) in `server/.env`. `make bootstrap` does not prompt for it, and the runtime test will fail without a valid provider key. + +```bash +cd server +make bootstrap +``` + +`make bootstrap` starts the same containers, then automatically creates the admin account and generates the first API key via the CLI. The admin credentials and API key are printed to your terminal β€” no browser required. + +You can override the generated credentials: + +```bash +make bootstrap EMAIL=admin@company.com PASSWORD='strong-password' NAME='Admin' +``` + +Because `make bootstrap` already creates the admin, the setup wizard is skipped. Opening `http://localhost:3000` takes you straight to the login page. + + + For machine-readable output (useful in CI), run `OUTPUT=json make seed` after `make up`. + + +--- + +## Run the setup wizard + + + This section applies to the **browser-first** path (`make up`). If you used `make bootstrap`, the admin and API key were already created β€” skip ahead to [What the dashboard gives you](#what-the-dashboard-gives-you). + + +On a fresh install the dashboard redirects to `/setup`. Each step submits on Enter. + +**1. Create the admin account.** Name, email, password. This account becomes the first admin. Registration closes after the first admin is created; additional accounts are provisioned by the existing admin. + +**2. Review the effective config.** Read-only display of the LLM and embedder the server is running with, sourced from your environment. If anything is wrong here, stop the stack, fix the `.env`, and restart β€” the dashboard intentionally does not let you change provider secrets at runtime. + +**3. Generate your first API key.** The full `m0sk_...` value is shown **once**. Copy it immediately β€” the server only stores the prefix and a bcrypt hash. + +**4. Tell us your use case.** Pick a preset or describe your use case in a few words. Mem0 generates custom instructions that tell the memory system what to prioritize. You can edit the instructions before saving, or skip this step entirely. + +**5. Test the key.** A ready-to-paste `curl` exercises `POST /memories` against your new key. Click "Run Test" to fire it from the browser. Success lands you in the dashboard at `/dashboard/requests`, where you'll see the test call in the live audit log. + +--- + +## What the dashboard gives you + +| Page | What it does | +|---|---| +| **Requests** | Default landing page. Live audit log of every API call, with status, latency, and auth mode. | +| **Memories** | Browse and search the memories your server has stored. | +| **Entities** | Distinct `user_id` / `agent_id` / `run_id` values with memory counts and cascade-delete. | +| **API Keys** | Issue per-user keys, label them, and revoke. | +| **Configuration** | Runtime override for LLM and embedder. Changes persist to the app database and reapply on restart, layered over the values from your `.env`. | +| **Settings** | Account and session controls. | + +For the underlying endpoints (including `/auth/*`, `/api-keys`, `/requests`, `/entities`), see the [REST API reference](/open-source/features/rest-api). + +--- + +## Supported providers + +The shipped container bundles the Python packages for: + +- **LLMs** β€” `openai`, `anthropic`, `gemini` +- **Embedders** β€” `openai`, `gemini` + +The Configuration page and `POST /configure` only accept providers from these lists. Anything else returns a 400 up front instead of failing at the first memory write. + +**To add another provider**, for example to run embeddings locally with `sentence-transformers`: + +1. Add the package to `server/requirements.txt` (e.g. `sentence-transformers>=2.0`). +2. Extend `BUNDLED_LLM_PROVIDERS` or `BUNDLED_EMBEDDER_PROVIDERS` in `server/main.py`. +3. Rebuild the image (`make up` or `docker compose build`). + +Heavy providers (`sentence-transformers` pulls in PyTorch, ~2 GB) are intentionally kept out of the default image. + +--- + +## Upgrade notes + +### Upgrading from a pre-auth build + +Previous self-hosted builds allowed open access when `ADMIN_API_KEY` was unset. This build enables auth by default. After pulling the new image, pick **one**: + +1. **Fastest, zero client changes** β€” set `ADMIN_API_KEY` to a long random value (16+ characters). Existing clients that send `X-API-Key: ` keep working unchanged. +2. **Recommended for teams** β€” visit `http://:3000`, run the setup wizard, and switch clients to per-user API keys. You get the audit log and revocation for free. +3. **Local development only** β€” set `AUTH_DISABLED=true`. The server logs a warning on every boot. Never use this in production. + +The server prints an unmissable startup banner when it detects the "upgraded but not configured" state so you know exactly which option to pick. + +### Other changes in this release + +- Dashboard ships as a second container in the reference Compose stack, wired to the API over the internal Docker network. +- New tables: `users`, `api_keys`, `request_logs`. Alembic handles the migration automatically on first boot. + +If `alembic upgrade head` fails on first boot, see the [Troubleshooting](#troubleshooting) section below. + +--- + +## Troubleshooting + + + + Find the owning process on either port: + ```bash + lsof -iTCP:3000 -sTCP:LISTEN + lsof -iTCP:8888 -sTCP:LISTEN + ``` + Kill it (`kill `) or change the host port in `server/docker-compose.yaml`. + + + + The server refuses to start without one. Generate a secret and add it to `server/.env`: + ```bash + echo "JWT_SECRET=$(openssl rand -base64 48)" >> server/.env + ``` + `AUTH_DISABLED=true` is valid for local dev only, never production. + + + + `docker compose restart` does not re-read `env_file`. To pick up changes: + ```bash + cd server && docker compose up -d --force-recreate mem0 + # or + cd server && make up + ``` + + + + Provider credential errors surface as `502 Upstream provider error.`. Check `docker compose logs mem0` for the full trace, then fix the key on the Configuration page and hit **Save**. + + + + Inspect the logs: + ```bash + docker compose logs mem0 | grep -i alembic + ``` + If the database is unrecoverable, reset the volume (**this destroys all memories and users**): + ```bash + docker compose down -v + ``` + + + +--- + + + + Endpoint tables, auth modes, and example requests. + + + Swap LLMs, embedders, vector stores, and rerankers. + + diff --git a/docs/platform/mem0-mcp.mdx b/docs/platform/mem0-mcp.mdx index f62401f9e..7c9bbd7e0 100644 --- a/docs/platform/mem0-mcp.mdx +++ b/docs/platform/mem0-mcp.mdx @@ -7,8 +7,8 @@ estimatedTime: "~2 minutes" **Prerequisites** - - Mem0 Platform account (Sign up here) - - API key (Get one from dashboard) + - Mem0 Platform account (Sign up here) + - API key (Get one from dashboard) - Node.js 14+ (for npx) - An MCP-compatible client (Claude, Claude Code, Cursor, Windsurf, VS Code, OpenCode) @@ -163,7 +163,7 @@ Agent: Updated your project status successfully. ``` - If you get "Connection failed", ensure you have a valid API key from Mem0 Dashboard. + If you get "Connection failed", ensure you have a valid API key from Mem0 Dashboard. --- @@ -171,7 +171,7 @@ Agent: Updated your project status successfully. ## Quick Recovery - **"Connection refused"** β†’ Check your internet connection and ensure the MCP client is correctly configured -- **"Invalid API key"** β†’ Get a new key from Mem0 Dashboard +- **"Invalid API key"** β†’ Get a new key from Mem0 Dashboard - **"npx command not found"** β†’ Install Node.js from [nodejs.org](https://nodejs.org) --- diff --git a/docs/platform/overview.mdx b/docs/platform/overview.mdx index dfd4d25c0..ee4226417 100644 --- a/docs/platform/overview.mdx +++ b/docs/platform/overview.mdx @@ -60,7 +60,7 @@ Mem0 is the memory engine that keeps conversations contextual so users never rep LangChain, CrewAI, Vercel AI SDK. - + Track activity and manage workspaces. diff --git a/docs/platform/platform-vs-oss.mdx b/docs/platform/platform-vs-oss.mdx index b58649d80..0dc73a53c 100644 --- a/docs/platform/platform-vs-oss.mdx +++ b/docs/platform/platform-vs-oss.mdx @@ -150,7 +150,7 @@ Mem0 offers two powerful ways to add memory to your AI applications. Choose base Sign up and test the Platform with our free tier. No credit card required. diff --git a/docs/platform/quickstart.mdx b/docs/platform/quickstart.mdx index 647b0a3e7..1c53ad7e6 100644 --- a/docs/platform/quickstart.mdx +++ b/docs/platform/quickstart.mdx @@ -9,7 +9,7 @@ Get started with Mem0 Platform's hosted API in under 5 minutes. This guide shows ## Prerequisites -- Mem0 Platform account (Sign up here) +- Mem0 Platform account (Sign up here) - API key (Get one from dashboard) - Python 3.10+, Node.js 14+, or cURL diff --git a/docs/vibecoding.mdx b/docs/vibecoding.mdx index 5b7f7c8b1..07949f437 100644 --- a/docs/vibecoding.mdx +++ b/docs/vibecoding.mdx @@ -12,7 +12,7 @@ We follow the llms.txt standard: - [llms.txt](https://docs.mem0.ai/llms.txt) - + Sign up for Mem0 Platform and start building @@ -34,7 +34,7 @@ Works with Claude Code, Cursor, Windsurf, and any assistant that supports skills Connect Claude, Claude Code, Cursor, Windsurf, VS Code, OpenCode, or any MCP-compatible client to Mem0. -Get your API key from app.mem0.ai, then add Mem0 MCP with a single command: +Get your API key from app.mem0.ai, then add Mem0 MCP with a single command: ```bash npx mcp-add \ diff --git a/examples/mem0-demo/app/assistant.tsx b/examples/mem0-demo/app/assistant.tsx index 99fd4718e..6c5215956 100644 --- a/examples/mem0-demo/app/assistant.tsx +++ b/examples/mem0-demo/app/assistant.tsx @@ -91,7 +91,7 @@ export const Assistant = () => { - + Playground diff --git a/examples/mem0-demo/components/assistant-ui/thread.tsx b/examples/mem0-demo/components/assistant-ui/thread.tsx index 240bfc46c..a9c8b7c49 100644 --- a/examples/mem0-demo/components/assistant-ui/thread.tsx +++ b/examples/mem0-demo/components/assistant-ui/thread.tsx @@ -174,7 +174,7 @@ export const Thread: FC = ({ diff --git a/examples/nemoclaw/quickstart.md b/examples/nemoclaw/quickstart.md index ff3a99b92..49fae53d5 100644 --- a/examples/nemoclaw/quickstart.md +++ b/examples/nemoclaw/quickstart.md @@ -2,7 +2,7 @@ Add persistent long-term memory to your [NemoClaw](https://docs.nvidia.com/nemoclaw/latest/get-started/quickstart.html) OpenClaw agent using the `@mem0/openclaw-mem0` plugin. -> **Note:** This plugin requires **Mem0 Platform mode** (i.e., a Mem0 API key from [app.mem0.ai](https://app.mem0.ai)). Open-source mode is not supported in NemoClaw sandboxes because the sandbox proxy blocks `/v1/embeddings` requests required by the open-source backend. See [Known Limitations](#known-limitations) for details. +> **Note:** This plugin requires **Mem0 Platform mode** (i.e., a Mem0 API key from [app.mem0.ai](https://app.mem0.ai?utm_source=oss&utm_medium=example-nemoclaw)). Open-source mode is not supported in NemoClaw sandboxes because the sandbox proxy blocks `/v1/embeddings` requests required by the open-source backend. See [Known Limitations](#known-limitations) for details. ## Prerequisites @@ -15,7 +15,7 @@ Add persistent long-term memory to your [NemoClaw](https://docs.nvidia.com/nemoc **Accounts required:** - **NVIDIA** β€” sign up at [build.nvidia.com](https://build.nvidia.com), generate an API key at [build.nvidia.com/settings/api-keys](https://build.nvidia.com/settings/api-keys) (starts with `nvapi-`) -- **Mem0** β€” sign up at [app.mem0.ai](https://app.mem0.ai), generate an API key from the dashboard (starts with `m0-`) +- **Mem0** β€” sign up at [app.mem0.ai](https://app.mem0.ai?utm_source=oss&utm_medium=example-nemoclaw), generate an API key from the dashboard (starts with `m0-`) **Supported platforms:** Ubuntu 22.04+, macOS (via Docker), Windows (WSL 2 + Docker) @@ -269,4 +269,4 @@ Then re-run `nemoclaw onboard`. - [Mem0 Documentation](https://docs.mem0.ai) - [NemoClaw Documentation](https://docs.nvidia.com/nemoclaw/latest/get-started/quickstart.html) - [`@mem0/openclaw-mem0` on npm](https://www.npmjs.com/package/@mem0/openclaw-mem0) -- [Mem0 Dashboard](https://app.mem0.ai) +- [Mem0 Dashboard](https://app.mem0.ai?utm_source=oss&utm_medium=example-nemoclaw) diff --git a/examples/openai-inbuilt-tools/index.js b/examples/openai-inbuilt-tools/index.js index 2e26cf97c..fa1da9af3 100644 --- a/examples/openai-inbuilt-tools/index.js +++ b/examples/openai-inbuilt-tools/index.js @@ -4,7 +4,7 @@ import { zodResponsesFunction } from "openai/helpers/zod"; import { z } from "zod"; const mem0Config = { - apiKey: process.env.MEM0_API_KEY, // GET THIS API KEY FROM MEM0 (https://app.mem0.ai/dashboard/api-keys) + apiKey: process.env.MEM0_API_KEY, // GET THIS API KEY FROM MEM0 (https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=example-openai-inbuilt-tools) user_id: "sample-user", }; diff --git a/mem0-plugin/README.md b/mem0-plugin/README.md index ac43feb74..b2a41d347 100644 --- a/mem0-plugin/README.md +++ b/mem0-plugin/README.md @@ -6,8 +6,8 @@ Add persistent memory to your AI workflows. Store, retrieve, and manage memories > **You must complete this step before installing the plugin.** -1. Sign up at [app.mem0.ai](https://app.mem0.ai) if you haven't already -2. Go to [app.mem0.ai/dashboard/api-keys](https://app.mem0.ai/dashboard/api-keys) +1. Sign up at [app.mem0.ai](https://app.mem0.ai?utm_source=oss&utm_medium=mem0-plugin-readme) if you haven't already +2. Go to [app.mem0.ai/dashboard/api-keys](https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=mem0-plugin-readme) 3. Click **Create API Key** and copy the key (starts with `m0-`) 4. Add it to your shell profile: diff --git a/mem0-plugin/skills/mem0/README.md b/mem0-plugin/skills/mem0/README.md index f1cb13806..4ed29d162 100644 --- a/mem0-plugin/skills/mem0/README.md +++ b/mem0-plugin/skills/mem0/README.md @@ -1,6 +1,6 @@ # Mem0 Skill for Claude -Add persistent memory to any AI application in minutes using [Mem0 Platform](https://app.mem0.ai). +Add persistent memory to any AI application in minutes using [Mem0 Platform](https://app.mem0.ai?utm_source=oss&utm_medium=mem0-plugin-skill-readme). ## What This Skill Does @@ -24,7 +24,7 @@ See the [plugin README](../../README.md) for full setup instructions. ### Prerequisites -- A Mem0 Platform API key ([Get one here](https://app.mem0.ai/dashboard/api-keys)) +- A Mem0 Platform API key ([Get one here](https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=mem0-plugin-skill-readme)) - Python 3.10+ or Node.js 18+ - Set the environment variable: @@ -63,7 +63,7 @@ skills/mem0/ ## Links -- [Mem0 Platform Dashboard](https://app.mem0.ai) +- [Mem0 Platform Dashboard](https://app.mem0.ai?utm_source=oss&utm_medium=mem0-plugin-skill-readme) - [Mem0 Documentation](https://docs.mem0.ai) - [Mem0 GitHub](https://github.com/mem0ai/mem0) - [API Reference](https://docs.mem0.ai/api-reference) diff --git a/mem0-plugin/skills/mem0/SKILL.md b/mem0-plugin/skills/mem0/SKILL.md index cec1311ce..c700e80a1 100644 --- a/mem0-plugin/skills/mem0/SKILL.md +++ b/mem0-plugin/skills/mem0/SKILL.md @@ -35,7 +35,7 @@ npm install mem0ai export MEM0_API_KEY="m0-your-api-key" ``` -Get an API key at: https://app.mem0.ai/dashboard/api-keys +Get an API key at: https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=mem0-plugin-skill ## Step 2: Initialize the client diff --git a/mem0-plugin/skills/mem0/references/quickstart.md b/mem0-plugin/skills/mem0/references/quickstart.md index 0954f0c88..cfd34b86e 100644 --- a/mem0-plugin/skills/mem0/references/quickstart.md +++ b/mem0-plugin/skills/mem0/references/quickstart.md @@ -5,7 +5,7 @@ Get running with Mem0 in 2 minutes. No infrastructure to deploy -- just an API k ## Prerequisites - Python 3.10+ or Node.js 18+ -- A Mem0 Platform API key ([Get one here](https://app.mem0.ai/dashboard/api-keys)) +- A Mem0 Platform API key ([Get one here](https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=mem0-plugin-skill-quickstart)) ## Python Setup diff --git a/mem0-ts/README.md b/mem0-ts/README.md index 8abb07a93..7baae2f96 100644 --- a/mem0-ts/README.md +++ b/mem0-ts/README.md @@ -15,7 +15,7 @@ npm i mem0ai ## 2. API Key Setup -For the cloud offering, sign in to [Mem0 Platform](https://app.mem0.ai/dashboard/api-keys) to obtain your API Key. +For the cloud offering, sign in to [Mem0 Platform](https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=mem0-ts-readme) to obtain your API Key. ## 3. Client Features diff --git a/openclaw/README.md b/openclaw/README.md index 9ab55501c..7e63b318a 100644 --- a/openclaw/README.md +++ b/openclaw/README.md @@ -29,7 +29,7 @@ openclaw --version openclaw plugins install @mem0/openclaw-mem0 ``` -2. **Get your API key** from [app.mem0.ai](https://app.mem0.ai/dashboard/api-keys). +2. **Get your API key** from [app.mem0.ai](https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=openclaw-readme). 3. **Select the plugin as your memory backend in `openclaw.json`.** Either initialize via the CLI: diff --git a/openclaw/index.ts b/openclaw/index.ts index 1dd99021b..50e506c26 100644 --- a/openclaw/index.ts +++ b/openclaw/index.ts @@ -128,7 +128,7 @@ const memoryPlugin = definePluginEntry({ "openclaw-mem0: API key not configured. Memory features are disabled.\n" + " To set up, run:\n" + " openclaw mem0 init\n" + - " Get your key at: https://app.mem0.ai/dashboard/api-keys", + " Get your key at: https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=openclaw-src", ); // Register CLI even without API key β€” init command must be available diff --git a/openclaw/openclaw.plugin.json b/openclaw/openclaw.plugin.json index 138902265..e30e0e3ec 100644 --- a/openclaw/openclaw.plugin.json +++ b/openclaw/openclaw.plugin.json @@ -27,7 +27,7 @@ "method": "api-key", "choiceId": "mem0-api-key", "choiceLabel": "Mem0 API key", - "choiceHint": "Required for platform mode. Get your key at https://app.mem0.ai/dashboard/api-keys", + "choiceHint": "Required for platform mode. Get your key at https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=openclaw-plugin", "groupId": "mem0", "groupLabel": "Mem0", "optionKey": "apiKey", diff --git a/server/.env.example b/server/.env.example index 820221622..114db1239 100644 --- a/server/.env.example +++ b/server/.env.example @@ -1,8 +1,8 @@ OPENAI_API_KEY= -NEO4J_URI= -NEO4J_USERNAME= -NEO4J_PASSWORD= +# Optional: other bundled LLM/embedder providers (set the key for the one you want to use) +# ANTHROPIC_API_KEY= +# GOOGLE_API_KEY= POSTGRES_HOST= POSTGRES_PORT= @@ -11,5 +11,23 @@ POSTGRES_USER= POSTGRES_PASSWORD= POSTGRES_COLLECTION_NAME= -# Optional: set to enable API key authentication on all endpoints ADMIN_API_KEY= +JWT_SECRET= +# Local development only. Leave false in production. +AUTH_DISABLED=false +DASHBOARD_URL=http://localhost:3000 +APP_DB_NAME=mem0_app + +# Default LLM and embedder models. Provider must be in BUNDLED_*_PROVIDERS +# (see server/main.py). Override to pin a specific model without editing code. +MEM0_DEFAULT_LLM_MODEL=gpt-4.1-nano-2025-04-14 +MEM0_DEFAULT_EMBEDDER_MODEL=text-embedding-3-small + +# Anonymous telemetry. Sends a single onboarding event per install +# (install UUID, email domain, server version, source). No PII. +# Set to false to opt out. +MEM0_TELEMETRY=true + +# Days of request_logs history to keep when `make prune-logs` runs. +# Wire the prune command into cron/systemd in production. +REQUEST_LOG_RETENTION_DAYS=30 diff --git a/server/Makefile b/server/Makefile index 9b1b388ff..8e9e382f1 100644 --- a/server/Makefile +++ b/server/Makefile @@ -1,7 +1,62 @@ +.PHONY: up down clean logs seed wait-api wait-dashboard bootstrap health build run_local reset-admin-password prune-logs + +OUTPUT ?= text +API_URL ?= http://localhost:8888 +DASHBOARD_URL ?= http://localhost:3000 + +up: + @for port in 3000 8888; do \ + if lsof -iTCP:$$port -sTCP:LISTEN >/dev/null 2>&1; then \ + echo "error: port $$port is already in use."; \ + echo "find the owning process with: lsof -iTCP:$$port -sTCP:LISTEN"; \ + exit 1; \ + fi; \ + done + docker compose up -d --build + @$(MAKE) --no-print-directory wait-api + @$(MAKE) --no-print-directory wait-dashboard + @echo "" + @echo "Stack is ready." + @echo " Dashboard: $(DASHBOARD_URL) <- open this to run the setup wizard" + @echo " API: $(API_URL)" + +down: + docker compose down + +clean: + docker compose down -v + +logs: + docker compose logs -f + +seed: + @API_URL="$(API_URL)" DASHBOARD_URL="$(DASHBOARD_URL)" EMAIL="$(EMAIL)" PASSWORD="$(PASSWORD)" NAME="$(NAME)" OUTPUT="$(OUTPUT)" ./scripts/seed.sh + +wait-api: + @echo "Waiting for API..." + @until curl -fsS "$(API_URL)/auth/setup-status" >/dev/null 2>&1; do sleep 2; done + +wait-dashboard: + @echo "Waiting for dashboard..." + @until curl -fsS "$(DASHBOARD_URL)/api/health" >/dev/null 2>&1; do sleep 2; done + +bootstrap: up wait-api wait-dashboard seed + +health: + @echo "API: $$(curl -s -o /dev/null -w '%{http_code}' "$(API_URL)/docs")" + @echo "Dashboard: $$(curl -s -o /dev/null -w '%{http_code}' "$(DASHBOARD_URL)/api/health")" + @echo "Postgres: $$(docker compose exec -T postgres pg_isready -q && echo 'ok' || echo 'down')" + +reset-admin-password: + @test -n "$(EMAIL)" || (echo "usage: make reset-admin-password EMAIL= PASSWORD=" && exit 2) + @test -n "$(PASSWORD)" || (echo "usage: make reset-admin-password EMAIL= PASSWORD=" && exit 2) + @docker compose exec -T -e EMAIL="$(EMAIL)" -e PASSWORD="$(PASSWORD)" -e PYTHONPATH=/app mem0 python scripts/reset_admin_password.py + +prune-logs: + @docker compose exec -T -e REQUEST_LOG_RETENTION_DAYS="$(REQUEST_LOG_RETENTION_DAYS)" -e PYTHONPATH=/app mem0 python scripts/prune_request_logs.py + build: docker build -t mem0-api-server . run_local: docker run -p 8000:8000 -v $(shell pwd):/app mem0-api-server --env-file .env - -.PHONY: build run_local diff --git a/server/README.md b/server/README.md index ef08247b1..37d153556 100644 --- a/server/README.md +++ b/server/README.md @@ -1,17 +1,126 @@ -# Mem0 REST API Server +# Mem0 Self-Hosted Server -Mem0 provides a REST API server (written using FastAPI). Users can perform all operations through REST endpoints. The API also includes OpenAPI documentation, accessible at `/docs` when the server is running. +Mem0 ships a self-hosted FastAPI server plus a local dashboard. It is secure by default, supports dashboard login and API keys, and exposes OpenAPI docs at `/docs`. -## Features +## Quick Start -- **Create memories:** Create memories based on messages for a user, agent, or run. -- **Retrieve memories:** Get all memories for a given user, agent, or run. -- **Search memories:** Search stored memories based on a query. -- **Update memories:** Update an existing memory. -- **Delete memories:** Delete a specific memory or all memories for a user, agent, or run. -- **Reset memories:** Reset all memories for a user, agent, or run. -- **OpenAPI Documentation:** Accessible via `/docs` endpoint. +### Agent-first -## Running the server +Run one command; the terminal prints the admin email, password, and first API key. -Follow the instructions in the [docs](https://docs.mem0.ai/open-source/features/rest-api) to run the server. +```bash +cd server +make bootstrap +``` + +This starts the stack, waits for the API and dashboard to be ready, creates the first admin, and generates the first API key. + +> The generated credentials print once in the `=== Ready ===` block. Save the password and API key before closing the terminal β€” the API key cannot be recovered afterwards. + +> `make bootstrap` skips the setup wizard, so the use-case β†’ custom-instructions step doesn't run. To add custom instructions afterwards, `POST /configure` with `{"custom_instructions": "..."}`, or run the Browser-first flow on a fresh install. + +You can override the generated credentials: + +```bash +cd server +make bootstrap EMAIL=admin@company.com PASSWORD='strong-password' NAME='Admin' +``` + +For machine-readable output: + +```bash +cd server +OUTPUT=json make seed +``` + +Teardown: + +```bash +# Stop the stack +cd server && make down + +# Wipe all data (including the Postgres volume) +cd server && make clean +``` + +### Browser-first + +Start the stack and finish setup by walking through the wizard in your browser. + +```bash +cd server +make up +``` + +Then open `http://localhost:3000` and complete the setup wizard. + +## Security Defaults + +- Dashboard login uses JWTs. +- Programmatic access uses `X-API-Key`. +- Auth is enabled by default. +- `AUTH_DISABLED=true` exists for local development only and should not be used in production. + +## Forgotten password + +Reset an admin password from the host while the stack is running: + +```bash +cd server +make reset-admin-password EMAIL=admin@example.com PASSWORD='new-strong-password' +``` + +This is the supported recovery path. Anyone with shell access to the host already has full access to the database and secrets, so this command does not expand the attack surface. + +## Request log retention + +The `request_logs` table is append-only and grows with traffic (~864k rows/day at 10 req/s). Prune it periodically: + +```bash +cd server +make prune-logs # defaults to 30 days +make prune-logs REQUEST_LOG_RETENTION_DAYS=7 # shorter window +``` + +Wire the command into cron or a systemd timer in production. The `created_at` column uses a BRIN index, so range deletes stay cheap even on large tables. + +## Local URLs + +- Dashboard: `http://localhost:3000` +- API: `http://localhost:8888` +- OpenAPI docs: `http://localhost:8888/docs` + +## Dashboard + +Once logged in, the dashboard exposes: + +- **Requests** β€” live audit log of API calls (method, path, status, latency). +- **Memories** β€” browse memories, filter by user ID. +- **Entities** β€” list every `user_id`, `agent_id`, and `run_id` that owns memories, with counts. Delete an entity to cascade-delete its memories. +- **API Keys** β€” create, label, and revoke per-user keys. +- **Configuration** β€” runtime LLM and embedder override. Changes persist to the app database and reapply on restart, layered over the values from your `.env`. +- **Settings** β€” account profile and password. + +## Telemetry + +Enabled by default, matching the Mem0 OSS library. Sends at most two events per install to the same anonymous PostHog project the library uses: + +- `admin_registered` β€” fired when the first admin is created (wizard or direct API call). Properties: email domain, server version, install UUID. +- `onboarding_completed` β€” fired when the setup wizard reaches its final success state. Carries the same properties plus the freeform `use_case` the operator entered. API-only bootstraps never emit this event. + +Set `MEM0_TELEMETRY=false` to opt out. + +## Security headers + +The dashboard sets the following response headers on every path (see `server/dashboard/next.config.mjs`): + +- `X-Frame-Options: DENY` +- `Content-Security-Policy: frame-ancestors 'none'` +- `X-Content-Type-Options: nosniff` +- `Referrer-Policy: strict-origin-when-cross-origin` + +Together these prevent iframe embedding, sniffing of mislabelled MIME types, and cross-origin referrer leaks. Harden further behind your own reverse proxy if needed. + +## Reference + +Additional product and API documentation lives at [docs.mem0.ai](https://docs.mem0.ai/open-source/overview). diff --git a/server/alembic.ini b/server/alembic.ini new file mode 100644 index 000000000..2ad8035b4 --- /dev/null +++ b/server/alembic.ini @@ -0,0 +1,37 @@ +[alembic] +script_location = alembic +prepend_sys_path = . +sqlalchemy.url = postgresql+psycopg://postgres:postgres@postgres:5432/mem0_app + +[loggers] +keys = root,sqlalchemy,alembic + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine + +[logger_alembic] +level = INFO +handlers = +qualname = alembic + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S diff --git a/server/alembic/env.py b/server/alembic/env.py new file mode 100644 index 000000000..bddd65821 --- /dev/null +++ b/server/alembic/env.py @@ -0,0 +1,44 @@ +from logging.config import fileConfig + +from alembic import context +from sqlalchemy import engine_from_config, pool + +from db import Base, _build_database_url + +# Import models so Base.metadata picks up all tables +import models # noqa: F401 + +config = context.config + +if config.config_file_name is not None: + fileConfig(config.config_file_name) + +target_metadata = Base.metadata + +# Override sqlalchemy.url from alembic.ini with the runtime database URL +config.set_main_option("sqlalchemy.url", _build_database_url()) + + +def run_migrations_offline() -> None: + url = config.get_main_option("sqlalchemy.url") + context.configure(url=url, target_metadata=target_metadata, literal_binds=True) + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online() -> None: + connectable = engine_from_config( + config.get_section(config.config_ini_section, {}), + prefix="sqlalchemy.", + poolclass=pool.NullPool, + ) + with connectable.connect() as connection: + context.configure(connection=connection, target_metadata=target_metadata) + with context.begin_transaction(): + context.run_migrations() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/server/alembic/script.py.mako b/server/alembic/script.py.mako new file mode 100644 index 000000000..fbc4b07dc --- /dev/null +++ b/server/alembic/script.py.mako @@ -0,0 +1,26 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision | comma,n} +Create Date: ${create_date} + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +# revision identifiers, used by Alembic. +revision: str = ${repr(up_revision)} +down_revision: Union[str, None] = ${repr(down_revision)} +branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)} +depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)} + + +def upgrade() -> None: + ${upgrades if upgrades else "pass"} + + +def downgrade() -> None: + ${downgrades if downgrades else "pass"} diff --git a/server/alembic/versions/001_create_users_and_api_keys.py b/server/alembic/versions/001_create_users_and_api_keys.py new file mode 100644 index 000000000..b36988620 --- /dev/null +++ b/server/alembic/versions/001_create_users_and_api_keys.py @@ -0,0 +1,49 @@ +"""Create users and api_keys tables + +Revision ID: 001 +Revises: None +Create Date: 2026-04-10 + +""" + +from typing import Sequence, Union + +import sqlalchemy as sa +from alembic import op + +revision: str = "001" +down_revision: Union[str, None] = None +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + op.create_table( + "users", + sa.Column("id", sa.Uuid(), primary_key=True), + sa.Column("name", sa.String(255), nullable=False), + sa.Column("email", sa.String(255), nullable=False), + sa.Column("password_hash", sa.Text(), nullable=False), + sa.Column("role", sa.String(20), nullable=False, server_default="admin"), + sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()), + sa.Column("last_login_at", sa.DateTime(timezone=True), nullable=True), + sa.UniqueConstraint("email"), + ) + op.create_index("ix_users_email", "users", ["email"]) + + op.create_table( + "api_keys", + sa.Column("id", sa.Uuid(), primary_key=True), + sa.Column("key_prefix", sa.String(12), nullable=False), + sa.Column("key_hash", sa.Text(), nullable=False), + sa.Column("label", sa.String(255), nullable=False), + sa.Column("created_by", sa.Uuid(), sa.ForeignKey("users.id", ondelete="CASCADE"), nullable=False), + sa.Column("last_used_at", sa.DateTime(timezone=True), nullable=True), + sa.Column("revoked_at", sa.DateTime(timezone=True), nullable=True), + sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()), + ) + + +def downgrade() -> None: + op.drop_table("api_keys") + op.drop_table("users") diff --git a/server/alembic/versions/002_create_request_logs.py b/server/alembic/versions/002_create_request_logs.py new file mode 100644 index 000000000..1aae65483 --- /dev/null +++ b/server/alembic/versions/002_create_request_logs.py @@ -0,0 +1,36 @@ +"""Create request_logs table + +Revision ID: 002 +Revises: 001 +Create Date: 2026-04-13 + +""" + +from typing import Sequence, Union + +import sqlalchemy as sa +from alembic import op + +revision: str = "002" +down_revision: Union[str, None] = "001" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + op.create_table( + "request_logs", + sa.Column("id", sa.Uuid(), primary_key=True), + sa.Column("method", sa.String(16), nullable=False), + sa.Column("path", sa.String(512), nullable=False), + sa.Column("status_code", sa.Integer(), nullable=False), + sa.Column("latency_ms", sa.Float(), nullable=False), + sa.Column("auth_type", sa.String(32), nullable=False, server_default="none"), + sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()), + ) + op.create_index("ix_request_logs_created_at", "request_logs", ["created_at"]) + + +def downgrade() -> None: + op.drop_index("ix_request_logs_created_at", table_name="request_logs") + op.drop_table("request_logs") diff --git a/server/alembic/versions/003_create_settings.py b/server/alembic/versions/003_create_settings.py new file mode 100644 index 000000000..0ac01de2b --- /dev/null +++ b/server/alembic/versions/003_create_settings.py @@ -0,0 +1,30 @@ +"""Create settings table + +Revision ID: 003 +Revises: 002 +Create Date: 2026-04-15 + +""" + +from typing import Sequence, Union + +import sqlalchemy as sa +from alembic import op + +revision: str = "003" +down_revision: Union[str, None] = "002" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + op.create_table( + "settings", + sa.Column("key", sa.String(255), primary_key=True), + sa.Column("value", sa.Text(), nullable=False), + sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()), + ) + + +def downgrade() -> None: + op.drop_table("settings") diff --git a/server/alembic/versions/004_unique_admin_role.py b/server/alembic/versions/004_unique_admin_role.py new file mode 100644 index 000000000..f13fe0bcf --- /dev/null +++ b/server/alembic/versions/004_unique_admin_role.py @@ -0,0 +1,31 @@ +"""Enforce at-most-one admin via partial unique index + +Revision ID: 004 +Revises: 003 +Create Date: 2026-04-21 + +""" + +from typing import Sequence, Union + +import sqlalchemy as sa +from alembic import op + +revision: str = "004" +down_revision: Union[str, None] = "003" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + op.create_index( + "ix_users_only_one_admin", + "users", + ["role"], + unique=True, + postgresql_where=sa.text("role = 'admin'"), + ) + + +def downgrade() -> None: + op.drop_index("ix_users_only_one_admin", table_name="users") diff --git a/server/alembic/versions/005_refresh_token_jtis.py b/server/alembic/versions/005_refresh_token_jtis.py new file mode 100644 index 000000000..93ba453b3 --- /dev/null +++ b/server/alembic/versions/005_refresh_token_jtis.py @@ -0,0 +1,39 @@ +"""Create refresh_token_jtis table for single-use refresh tokens + +Revision ID: 005 +Revises: 004 +Create Date: 2026-04-21 + +""" + +from typing import Sequence, Union + +import sqlalchemy as sa +from alembic import op + +revision: str = "005" +down_revision: Union[str, None] = "004" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + op.create_table( + "refresh_token_jtis", + sa.Column("jti", sa.Uuid(), primary_key=True), + sa.Column( + "user_id", + sa.Uuid(), + sa.ForeignKey("users.id", ondelete="CASCADE"), + nullable=False, + ), + sa.Column("expires_at", sa.DateTime(timezone=True), nullable=False), + sa.Column("used_at", sa.DateTime(timezone=True), nullable=True), + sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()), + ) + op.create_index("ix_refresh_token_jtis_expires_at", "refresh_token_jtis", ["expires_at"]) + + +def downgrade() -> None: + op.drop_index("ix_refresh_token_jtis_expires_at", table_name="refresh_token_jtis") + op.drop_table("refresh_token_jtis") diff --git a/server/alembic/versions/006_request_logs_brin.py b/server/alembic/versions/006_request_logs_brin.py new file mode 100644 index 000000000..41e9c9dea --- /dev/null +++ b/server/alembic/versions/006_request_logs_brin.py @@ -0,0 +1,26 @@ +"""Swap request_logs.created_at btree index for a BRIN index + +Revision ID: 006 +Revises: 005 +Create Date: 2026-04-21 + +""" + +from typing import Sequence, Union + +from alembic import op + +revision: str = "006" +down_revision: Union[str, None] = "005" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + op.drop_index("ix_request_logs_created_at", table_name="request_logs") + op.execute("CREATE INDEX ix_request_logs_created_at ON request_logs USING BRIN (created_at)") + + +def downgrade() -> None: + op.drop_index("ix_request_logs_created_at", table_name="request_logs") + op.create_index("ix_request_logs_created_at", "request_logs", ["created_at"]) diff --git a/server/auth.py b/server/auth.py new file mode 100644 index 000000000..47a5cfb34 --- /dev/null +++ b/server/auth.py @@ -0,0 +1,186 @@ +import os +import secrets +import uuid +from datetime import datetime, timedelta, timezone + +from fastapi import Depends, HTTPException, Request +from fastapi.security import APIKeyHeader, HTTPAuthorizationCredentials, HTTPBearer +from jose import JWTError, jwt +from passlib.context import CryptContext +from sqlalchemy import select, update +from sqlalchemy.orm import Session + +from db import get_db +from models import APIKey, RefreshTokenJti, User + +JWT_SECRET = os.environ.get("JWT_SECRET", "") +JWT_ALGORITHM = "HS256" +ACCESS_TOKEN_EXPIRE_MINUTES = 30 +REFRESH_TOKEN_EXPIRE_DAYS = 30 +ADMIN_API_KEY = os.environ.get("ADMIN_API_KEY", "") +AUTH_DISABLED = os.environ.get("AUTH_DISABLED", "").lower() in {"1", "true", "yes", "on"} + +pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") + + +def hash_password(password: str) -> str: + return pwd_context.hash(password) + + +def verify_password(plain: str, hashed: str) -> bool: + return pwd_context.verify(plain, hashed) + + +def dummy_verify_password() -> None: + """Burn the same bcrypt cycles as a real verify so login timing doesn't leak whether an email exists.""" + pwd_context.dummy_verify() + + +def generate_api_key() -> tuple[str, str, str]: + """Returns (full_key, prefix, hash).""" + raw = secrets.token_urlsafe(32) + full_key = f"m0sk_{raw}" + prefix = full_key[:12] + key_hash = pwd_context.hash(full_key) + return full_key, prefix, key_hash + + +def verify_api_key_hash(plain_key: str, hashed: str) -> bool: + return pwd_context.verify(plain_key, hashed) + + +def _get_secret() -> str: + if not JWT_SECRET: + raise HTTPException(status_code=500, detail="JWT_SECRET is not configured.") + return JWT_SECRET + + +def create_access_token(user_id: str, role: str) -> str: + expire = datetime.now(timezone.utc) + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) + payload = {"sub": user_id, "role": role, "exp": expire, "type": "access"} + return jwt.encode(payload, _get_secret(), algorithm=JWT_ALGORITHM) + + +def create_refresh_token(user_id: str, db: Session) -> str: + expire = datetime.now(timezone.utc) + timedelta(days=REFRESH_TOKEN_EXPIRE_DAYS) + jti = uuid.uuid4() + db.add(RefreshTokenJti(jti=jti, user_id=uuid.UUID(user_id), expires_at=expire)) + db.commit() + payload = {"sub": user_id, "exp": expire, "jti": str(jti), "type": "refresh"} + return jwt.encode(payload, _get_secret(), algorithm=JWT_ALGORITHM) + + +def consume_refresh_jti(jti: str, db: Session) -> None: + """Atomically mark a refresh token's jti as used. Raises 401 if missing, already used, or expired. + + The conditional UPDATE closes the read-check-write race: concurrent replays of the same + token race on a single row, so at most one update affects a row and the rest see rowcount 0. + """ + try: + jti_uuid = uuid.UUID(jti) + except (TypeError, ValueError): + raise HTTPException(status_code=401, detail="Refresh token is no longer valid.") + now = datetime.now(timezone.utc) + result = db.execute( + update(RefreshTokenJti) + .where( + RefreshTokenJti.jti == jti_uuid, + RefreshTokenJti.used_at.is_(None), + RefreshTokenJti.expires_at > now, + ) + .values(used_at=now) + ) + if result.rowcount == 0: + raise HTTPException(status_code=401, detail="Refresh token is no longer valid.") + db.commit() + + +def decode_token(token: str) -> dict: + try: + return jwt.decode(token, _get_secret(), algorithms=[JWT_ALGORITHM]) + except JWTError: + raise HTTPException(status_code=401, detail="Invalid or expired token.") + + +bearer_scheme = HTTPBearer(auto_error=False) +api_key_header = APIKeyHeader(name="X-API-Key", auto_error=False) + + +def _mark_auth_type(request: Request, auth_type: str) -> None: + request.state.auth_type = auth_type + + +def _get_default_user(db: Session) -> User | None: + return db.scalar(select(User).order_by(User.created_at.asc())) + + +def _resolve_user_from_jwt(token: str, db: Session) -> User: + payload = decode_token(token) + if payload.get("type") != "access": + raise HTTPException(status_code=401, detail="Invalid token type.") + user = db.get(User, payload.get("sub")) + if user is None: + raise HTTPException(status_code=401, detail="User not found.") + return user + + +def _resolve_user_from_api_key(key: str, db: Session) -> User: + prefix = key[:12] if len(key) >= 12 else key + candidates = ( + db.execute(select(APIKey).where(APIKey.key_prefix == prefix, APIKey.revoked_at.is_(None))).scalars().all() + ) + + for candidate in candidates: + if verify_api_key_hash(key, candidate.key_hash): + candidate.last_used_at = datetime.now(timezone.utc) + db.commit() + user = db.get(User, candidate.created_by) + if user is None: + raise HTTPException(status_code=401, detail="API key owner not found.") + return user + + raise HTTPException(status_code=401, detail="Invalid API key.") + + +async def verify_auth( + request: Request, + credentials: HTTPAuthorizationCredentials | None = Depends(bearer_scheme), + x_api_key: str | None = Depends(api_key_header), + db: Session = Depends(get_db), +) -> User | None: + """Authenticate via JWT, X-API-Key, or legacy ADMIN_API_KEY. Returns User or None.""" + if credentials is not None: + _mark_auth_type(request, "bearer") + return _resolve_user_from_jwt(credentials.credentials, db) + + if x_api_key is not None: + if ADMIN_API_KEY and secrets.compare_digest(x_api_key, ADMIN_API_KEY): + _mark_auth_type(request, "admin_api_key") + return None + _mark_auth_type(request, "api_key") + return _resolve_user_from_api_key(x_api_key, db) + + if AUTH_DISABLED: + _mark_auth_type(request, "disabled") + return None + + raise HTTPException( + status_code=401, + detail="Authentication required. Provide a Bearer token or X-API-Key header.", + headers={"WWW-Authenticate": "Bearer"}, + ) + + +async def require_auth( + request: Request, + user: User | None = Depends(verify_auth), + db: Session = Depends(get_db), +) -> User: + """Like verify_auth but guarantees a non-None User. Use for endpoints that require auth.""" + if user is None: + if getattr(request.state, "auth_type", "none") in {"admin_api_key", "disabled"}: + default_user = _get_default_user(db) + if default_user is not None: + return default_user + raise HTTPException(status_code=401, detail="Authentication required.") + return user diff --git a/server/dashboard/.dockerignore b/server/dashboard/.dockerignore new file mode 100644 index 000000000..2587cca73 --- /dev/null +++ b/server/dashboard/.dockerignore @@ -0,0 +1,6 @@ +node_modules +.next +.env.local +.env.example +.env +.storybook \ No newline at end of file diff --git a/server/dashboard/.env.example b/server/dashboard/.env.example new file mode 100644 index 000000000..bcfbcf893 --- /dev/null +++ b/server/dashboard/.env.example @@ -0,0 +1,3 @@ +NEXT_PUBLIC_API_URL=http://localhost:8888 +API_INTERNAL_URL=http://localhost:8888 +NEXT_PUBLIC_INSTANCE_NAME=Mem0 diff --git a/server/dashboard/.eslintrc.json b/server/dashboard/.eslintrc.json new file mode 100644 index 000000000..957cd1545 --- /dev/null +++ b/server/dashboard/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": ["next/core-web-vitals"] +} diff --git a/server/dashboard/.gitignore b/server/dashboard/.gitignore new file mode 100644 index 000000000..1f9148c7b --- /dev/null +++ b/server/dashboard/.gitignore @@ -0,0 +1,39 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +*storybook.log +storybook-static diff --git a/server/dashboard/Dockerfile b/server/dashboard/Dockerfile new file mode 100644 index 000000000..0f271e1ee --- /dev/null +++ b/server/dashboard/Dockerfile @@ -0,0 +1,51 @@ +FROM node:20-alpine AS base +RUN apk add --no-cache libc6-compat +WORKDIR /app + +# Dependencies +FROM base AS deps +COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./ +RUN \ + if [ -f yarn.lock ]; then yarn --frozen-lockfile --network-timeout 600000; \ + elif [ -f package-lock.json ]; then npm ci; \ + elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i; \ + else npm install; \ + fi + +# Build +FROM base AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +ENV NEXT_TELEMETRY_DISABLED=1 +# Placeholder values replaced at runtime by entrypoint.sh +ENV NEXT_PUBLIC_API_URL=NEXT_PUBLIC_API_URL +ENV NEXT_PUBLIC_INSTANCE_NAME=NEXT_PUBLIC_INSTANCE_NAME + +RUN npm run build + +# Production +FROM base AS runner +WORKDIR /app + +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 + +RUN addgroup --system --gid 1001 nodejs && \ + adduser --system --uid 1001 nextjs + +COPY --from=builder /app/public ./public +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static +COPY --chown=nextjs:nodejs entrypoint.sh /home/nextjs/entrypoint.sh +RUN chmod +x /home/nextjs/entrypoint.sh + +USER nextjs + +EXPOSE 3000 +ENV PORT=3000 +ENV HOSTNAME="0.0.0.0" + +ENTRYPOINT ["/home/nextjs/entrypoint.sh"] +CMD ["node", "server.js"] diff --git a/server/dashboard/components.json b/server/dashboard/components.json new file mode 100644 index 000000000..4a9e7e203 --- /dev/null +++ b/server/dashboard/components.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "tailwind.config.ts", + "css": "src/styles/globals.css", + "baseColor": "zinc", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils" + } +} diff --git a/server/dashboard/entrypoint.sh b/server/dashboard/entrypoint.sh new file mode 100644 index 000000000..d8a727a41 --- /dev/null +++ b/server/dashboard/entrypoint.sh @@ -0,0 +1,17 @@ +#!/bin/sh +set -e + +cd /app + +# Swap NEXT_PUBLIC_* placeholders baked into .next/ at build time with the +# container's real env values. Each placeholder must be declared in the +# Dockerfile as `ENV NAME=NAME` so Next.js inlines the literal name. Currently: +# NEXT_PUBLIC_API_URL, NEXT_PUBLIC_INSTANCE_NAME +# New NEXT_PUBLIC_* vars must be added to the Dockerfile or this loop won't substitute them. +printenv | grep '^NEXT_PUBLIC_' | while IFS='=' read -r key value; do + escaped=$(printf '%s' "$value" | sed -e 's/[\\&|]/\\&/g') + find .next/ -type f -exec sed -i "s|$key|$escaped|g" {} \; +done +echo "Done replacing env variables NEXT_PUBLIC_ with real values" + +exec "$@" diff --git a/server/dashboard/next.config.mjs b/server/dashboard/next.config.mjs new file mode 100644 index 000000000..9b0877178 --- /dev/null +++ b/server/dashboard/next.config.mjs @@ -0,0 +1,41 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + output: "standalone", + eslint: { + ignoreDuringBuilds: false, + }, + typescript: { + ignoreBuildErrors: false, + }, + experimental: { + optimizePackageImports: ["@/components", "@/lib", "@/utils"], + }, + compress: true, + images: { + formats: ["image/webp", "image/avif"], + }, + async headers() { + return [ + { + source: "/(.*)", + headers: [ + { key: "X-Frame-Options", value: "DENY" }, + { key: "Content-Security-Policy", value: "frame-ancestors 'none'" }, + { key: "X-Content-Type-Options", value: "nosniff" }, + { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" }, + ], + }, + ]; + }, + redirects: async () => { + return [ + { + source: "/settings", + destination: "/dashboard/settings", + permanent: false, + }, + ]; + }, +}; + +export default nextConfig; diff --git a/server/dashboard/package.json b/server/dashboard/package.json new file mode 100644 index 000000000..b326bfb37 --- /dev/null +++ b/server/dashboard/package.json @@ -0,0 +1,83 @@ +{ + "name": "mem0-dashboard", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "prettier --check .", + "format": "prettier --write .", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@hookform/resolvers": "^3.6.0", + "@radix-ui/react-accordion": "^1.2.0", + "@radix-ui/react-alert-dialog": "^1.1.4", + "@radix-ui/react-avatar": "^1.0.4", + "@radix-ui/react-checkbox": "^1.0.4", + "@radix-ui/react-collapsible": "^1.1.3", + "@radix-ui/react-dialog": "^1.1.1", + "@radix-ui/react-dropdown-menu": "^2.0.6", + "@radix-ui/react-hover-card": "^1.1.1", + "@radix-ui/react-icons": "^1.3.0", + "@radix-ui/react-label": "^2.1.0", + "@radix-ui/react-popover": "^1.0.7", + "@radix-ui/react-progress": "^1.1.0", + "@radix-ui/react-radio-group": "^1.2.0", + "@radix-ui/react-scroll-area": "^1.0.5", + "@radix-ui/react-select": "^2.1.1", + "@radix-ui/react-separator": "^1.1.0", + "@radix-ui/react-slider": "^1.2.2", + "@radix-ui/react-slot": "^1.2.3", + "@radix-ui/react-switch": "^1.1.2", + "@radix-ui/react-tabs": "^1.1.0", + "@radix-ui/react-toast": "^1.2.1", + "@radix-ui/react-tooltip": "^1.0.7", + "@reduxjs/toolkit": "^2.3.0", + "@tanstack/react-table": "^8.17.3", + "axios": "^1.6.8", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.0", + "cmdk": "^1.0.0", + "date-fns": "^4.1.0", + "framer-motion": "^12.23.12", + "lodash": "^4.17.21", + "lucide-react": "^0.542.0", + "next": "15.2.6", + "next-themes": "^0.4.4", + "react": "^19.0.0", + "react-copy-to-clipboard": "^5.1.0", + "react-day-picker": "8.10.1", + "react-dom": "^19.0.0", + "react-hook-form": "^7.52.0", + "react-redux": "^9.1.2", + "react-syntax-highlighter": "^15.5.0", + "recharts": "^2.15.0", + "redux": "^5.0.1", + "sonner": "^1.4.41", + "tailwind-merge": "^2.2.0", + "tailwindcss-animate": "^1.0.7", + "use-debounce": "^10.0.4", + "uuid": "^9.0.1", + "vaul": "^0.9.1", + "zod": "^3.23.8" + }, + "devDependencies": { + "@tailwindcss/typography": "^0.5.13", + "@types/lodash": "^4.17.7", + "@types/node": "22.5.4", + "@types/react": "^19.0.0", + "@types/react-copy-to-clipboard": "^5.0.7", + "@types/react-dom": "^19.0.0", + "@types/react-syntax-highlighter": "^15.5.13", + "@types/uuid": "^9.0.8", + "autoprefixer": "^10.0.1", + "eslint": "^8", + "eslint-config-next": "15.2.6", + "postcss": "^8", + "prettier": "^3.5.2", + "tailwindcss": "^3.3.0", + "typescript": "^5.6.3" + } +} diff --git a/server/dashboard/pnpm-lock.yaml b/server/dashboard/pnpm-lock.yaml new file mode 100644 index 000000000..9658ab445 --- /dev/null +++ b/server/dashboard/pnpm-lock.yaml @@ -0,0 +1,7967 @@ +lockfileVersion: "9.0" + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + .: + dependencies: + "@hookform/resolvers": + specifier: ^3.6.0 + version: 3.10.0(react-hook-form@7.72.1(react@19.2.5)) + "@radix-ui/react-accordion": + specifier: ^1.2.0 + version: 1.2.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-alert-dialog": + specifier: ^1.1.4 + version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-avatar": + specifier: ^1.0.4 + version: 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-checkbox": + specifier: ^1.0.4 + version: 1.3.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-collapsible": + specifier: ^1.1.3 + version: 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-dialog": + specifier: ^1.1.1 + version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-dropdown-menu": + specifier: ^2.0.6 + version: 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-hover-card": + specifier: ^1.1.1 + version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-icons": + specifier: ^1.3.0 + version: 1.3.2(react@19.2.5) + "@radix-ui/react-label": + specifier: ^2.1.0 + version: 2.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-popover": + specifier: ^1.0.7 + version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-progress": + specifier: ^1.1.0 + version: 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-radio-group": + specifier: ^1.2.0 + version: 1.3.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-scroll-area": + specifier: ^1.0.5 + version: 1.2.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-select": + specifier: ^2.1.1 + version: 2.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-separator": + specifier: ^1.1.0 + version: 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-slider": + specifier: ^1.2.2 + version: 1.3.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-slot": + specifier: ^1.2.3 + version: 1.2.4(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-switch": + specifier: ^1.1.2 + version: 1.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-tabs": + specifier: ^1.1.0 + version: 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-toast": + specifier: ^1.2.1 + version: 1.2.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-tooltip": + specifier: ^1.0.7 + version: 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@reduxjs/toolkit": + specifier: ^2.3.0 + version: 2.11.2(react-redux@9.2.0(@types/react@19.2.14)(react@19.2.5)(redux@5.0.1))(react@19.2.5) + "@tanstack/react-table": + specifier: ^8.17.3 + version: 8.21.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + axios: + specifier: ^1.6.8 + version: 1.15.0 + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + clsx: + specifier: ^2.1.0 + version: 2.1.1 + cmdk: + specifier: ^1.0.0 + version: 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + date-fns: + specifier: ^4.1.0 + version: 4.1.0 + framer-motion: + specifier: ^12.23.12 + version: 12.38.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + lodash: + specifier: ^4.17.21 + version: 4.18.1 + lucide-react: + specifier: ^0.542.0 + version: 0.542.0(react@19.2.5) + next: + specifier: 15.2.6 + version: 15.2.6(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + next-themes: + specifier: ^0.4.4 + version: 0.4.6(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: + specifier: ^19.0.0 + version: 19.2.5 + react-copy-to-clipboard: + specifier: ^5.1.0 + version: 5.1.1(react@19.2.5) + react-day-picker: + specifier: 8.10.1 + version: 8.10.1(date-fns@4.1.0)(react@19.2.5) + react-dom: + specifier: ^19.0.0 + version: 19.2.5(react@19.2.5) + react-hook-form: + specifier: ^7.52.0 + version: 7.72.1(react@19.2.5) + react-redux: + specifier: ^9.1.2 + version: 9.2.0(@types/react@19.2.14)(react@19.2.5)(redux@5.0.1) + react-syntax-highlighter: + specifier: ^15.5.0 + version: 15.6.6(react@19.2.5) + recharts: + specifier: ^2.15.0 + version: 2.15.4(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + redux: + specifier: ^5.0.1 + version: 5.0.1 + sonner: + specifier: ^1.4.41 + version: 1.7.4(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + tailwind-merge: + specifier: ^2.2.0 + version: 2.6.1 + tailwindcss-animate: + specifier: ^1.0.7 + version: 1.0.7(tailwindcss@3.4.19) + use-debounce: + specifier: ^10.0.4 + version: 10.1.1(react@19.2.5) + uuid: + specifier: ^9.0.1 + version: 9.0.1 + vaul: + specifier: ^0.9.1 + version: 0.9.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + zod: + specifier: ^3.23.8 + version: 3.25.76 + devDependencies: + "@tailwindcss/typography": + specifier: ^0.5.13 + version: 0.5.19(tailwindcss@3.4.19) + "@types/lodash": + specifier: ^4.17.7 + version: 4.17.24 + "@types/node": + specifier: 22.5.4 + version: 22.5.4 + "@types/react": + specifier: ^19.0.0 + version: 19.2.14 + "@types/react-copy-to-clipboard": + specifier: ^5.0.7 + version: 5.0.7 + "@types/react-dom": + specifier: ^19.0.0 + version: 19.2.3(@types/react@19.2.14) + "@types/react-syntax-highlighter": + specifier: ^15.5.13 + version: 15.5.13 + "@types/uuid": + specifier: ^9.0.8 + version: 9.0.8 + autoprefixer: + specifier: ^10.0.1 + version: 10.5.0(postcss@8.5.10) + eslint: + specifier: ^8 + version: 8.57.1 + eslint-config-next: + specifier: 15.2.6 + version: 15.2.6(eslint@8.57.1)(typescript@5.9.3) + postcss: + specifier: ^8 + version: 8.5.10 + prettier: + specifier: ^3.5.2 + version: 3.8.3 + tailwindcss: + specifier: ^3.3.0 + version: 3.4.19 + typescript: + specifier: ^5.6.3 + version: 5.9.3 + +packages: + "@alloc/quick-lru@5.2.0": + resolution: + { + integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==, + } + engines: { node: ">=10" } + + "@babel/runtime@7.29.2": + resolution: + { + integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==, + } + engines: { node: ">=6.9.0" } + + "@emnapi/core@1.9.2": + resolution: + { + integrity: sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==, + } + + "@emnapi/runtime@1.9.2": + resolution: + { + integrity: sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==, + } + + "@emnapi/wasi-threads@1.2.1": + resolution: + { + integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==, + } + + "@eslint-community/eslint-utils@4.9.1": + resolution: + { + integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + "@eslint-community/regexpp@4.12.2": + resolution: + { + integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==, + } + engines: { node: ^12.0.0 || ^14.0.0 || >=16.0.0 } + + "@eslint/eslintrc@2.1.4": + resolution: + { + integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + + "@eslint/js@8.57.1": + resolution: + { + integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + + "@floating-ui/core@1.7.5": + resolution: + { + integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==, + } + + "@floating-ui/dom@1.7.6": + resolution: + { + integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==, + } + + "@floating-ui/react-dom@2.1.8": + resolution: + { + integrity: sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==, + } + peerDependencies: + react: ">=16.8.0" + react-dom: ">=16.8.0" + + "@floating-ui/utils@0.2.11": + resolution: + { + integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==, + } + + "@hookform/resolvers@3.10.0": + resolution: + { + integrity: sha512-79Dv+3mDF7i+2ajj7SkypSKHhl1cbln1OGavqrsF7p6mbUv11xpqpacPsGDCTRvCSjEEIez2ef1NveSVL3b0Ag==, + } + peerDependencies: + react-hook-form: ^7.0.0 + + "@humanwhocodes/config-array@0.13.0": + resolution: + { + integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==, + } + engines: { node: ">=10.10.0" } + deprecated: Use @eslint/config-array instead + + "@humanwhocodes/module-importer@1.0.1": + resolution: + { + integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==, + } + engines: { node: ">=12.22" } + + "@humanwhocodes/object-schema@2.0.3": + resolution: + { + integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==, + } + deprecated: Use @eslint/object-schema instead + + "@img/sharp-darwin-arm64@0.33.5": + resolution: + { + integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [arm64] + os: [darwin] + + "@img/sharp-darwin-x64@0.33.5": + resolution: + { + integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [x64] + os: [darwin] + + "@img/sharp-libvips-darwin-arm64@1.0.4": + resolution: + { + integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==, + } + cpu: [arm64] + os: [darwin] + + "@img/sharp-libvips-darwin-x64@1.0.4": + resolution: + { + integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==, + } + cpu: [x64] + os: [darwin] + + "@img/sharp-libvips-linux-arm64@1.0.4": + resolution: + { + integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==, + } + cpu: [arm64] + os: [linux] + libc: [glibc] + + "@img/sharp-libvips-linux-arm@1.0.5": + resolution: + { + integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==, + } + cpu: [arm] + os: [linux] + libc: [glibc] + + "@img/sharp-libvips-linux-s390x@1.0.4": + resolution: + { + integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==, + } + cpu: [s390x] + os: [linux] + libc: [glibc] + + "@img/sharp-libvips-linux-x64@1.0.4": + resolution: + { + integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==, + } + cpu: [x64] + os: [linux] + libc: [glibc] + + "@img/sharp-libvips-linuxmusl-arm64@1.0.4": + resolution: + { + integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==, + } + cpu: [arm64] + os: [linux] + libc: [musl] + + "@img/sharp-libvips-linuxmusl-x64@1.0.4": + resolution: + { + integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==, + } + cpu: [x64] + os: [linux] + libc: [musl] + + "@img/sharp-linux-arm64@0.33.5": + resolution: + { + integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [arm64] + os: [linux] + libc: [glibc] + + "@img/sharp-linux-arm@0.33.5": + resolution: + { + integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [arm] + os: [linux] + libc: [glibc] + + "@img/sharp-linux-s390x@0.33.5": + resolution: + { + integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [s390x] + os: [linux] + libc: [glibc] + + "@img/sharp-linux-x64@0.33.5": + resolution: + { + integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [x64] + os: [linux] + libc: [glibc] + + "@img/sharp-linuxmusl-arm64@0.33.5": + resolution: + { + integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [arm64] + os: [linux] + libc: [musl] + + "@img/sharp-linuxmusl-x64@0.33.5": + resolution: + { + integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [x64] + os: [linux] + libc: [musl] + + "@img/sharp-wasm32@0.33.5": + resolution: + { + integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [wasm32] + + "@img/sharp-win32-ia32@0.33.5": + resolution: + { + integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [ia32] + os: [win32] + + "@img/sharp-win32-x64@0.33.5": + resolution: + { + integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [x64] + os: [win32] + + "@jridgewell/gen-mapping@0.3.13": + resolution: + { + integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==, + } + + "@jridgewell/resolve-uri@3.1.2": + resolution: + { + integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==, + } + engines: { node: ">=6.0.0" } + + "@jridgewell/sourcemap-codec@1.5.5": + resolution: + { + integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==, + } + + "@jridgewell/trace-mapping@0.3.31": + resolution: + { + integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==, + } + + "@napi-rs/wasm-runtime@0.2.12": + resolution: + { + integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==, + } + + "@next/env@15.2.6": + resolution: + { + integrity: sha512-kp1Mpm4K1IzSSJ5ZALfek0JBD2jBw9VGMXR/aT7ykcA2q/ieDARyBzg+e8J1TkeIb5AFj/YjtZdoajdy5uNy6w==, + } + + "@next/eslint-plugin-next@15.2.6": + resolution: + { + integrity: sha512-DkQt+OUzNEABMQvupD+w4FsqkDAmA/otgtwhpExzbYZ4bHnUAHwhDD3PUV0maI1qyiGcoOJGG3qZ0IJyK6w+1A==, + } + + "@next/swc-darwin-arm64@15.2.5": + resolution: + { + integrity: sha512-4OimvVlFTbgzPdA0kh8A1ih6FN9pQkL4nPXGqemEYgk+e7eQhsst/p35siNNqA49eQA6bvKZ1ASsDtu9gtXuog==, + } + engines: { node: ">= 10" } + cpu: [arm64] + os: [darwin] + + "@next/swc-darwin-x64@15.2.5": + resolution: + { + integrity: sha512-ohzRaE9YbGt1ctE0um+UGYIDkkOxHV44kEcHzLqQigoRLaiMtZzGrA11AJh2Lu0lv51XeiY1ZkUvkThjkVNBMA==, + } + engines: { node: ">= 10" } + cpu: [x64] + os: [darwin] + + "@next/swc-linux-arm64-gnu@15.2.5": + resolution: + { + integrity: sha512-FMSdxSUt5bVXqqOoZCc/Seg4LQep9w/fXTazr/EkpXW2Eu4IFI9FD7zBDlID8TJIybmvKk7mhd9s+2XWxz4flA==, + } + engines: { node: ">= 10" } + cpu: [arm64] + os: [linux] + libc: [glibc] + + "@next/swc-linux-arm64-musl@15.2.5": + resolution: + { + integrity: sha512-4ZNKmuEiW5hRKkGp2HWwZ+JrvK4DQLgf8YDaqtZyn7NYdl0cHfatvlnLFSWUayx9yFAUagIgRGRk8pFxS8Qniw==, + } + engines: { node: ">= 10" } + cpu: [arm64] + os: [linux] + libc: [musl] + + "@next/swc-linux-x64-gnu@15.2.5": + resolution: + { + integrity: sha512-bE6lHQ9GXIf3gCDE53u2pTl99RPZW5V1GLHSRMJ5l/oB/MT+cohu9uwnCK7QUph2xIOu2a6+27kL0REa/kqwZw==, + } + engines: { node: ">= 10" } + cpu: [x64] + os: [linux] + libc: [glibc] + + "@next/swc-linux-x64-musl@15.2.5": + resolution: + { + integrity: sha512-y7EeQuSkQbTAkCEQnJXm1asRUuGSWAchGJ3c+Qtxh8LVjXleZast8Mn/rL7tZOm7o35QeIpIcid6ufG7EVTTcA==, + } + engines: { node: ">= 10" } + cpu: [x64] + os: [linux] + libc: [musl] + + "@next/swc-win32-arm64-msvc@15.2.5": + resolution: + { + integrity: sha512-gQMz0yA8/dskZM2Xyiq2FRShxSrsJNha40Ob/M2n2+JGRrZ0JwTVjLdvtN6vCxuq4ByhOd4a9qEf60hApNR2gQ==, + } + engines: { node: ">= 10" } + cpu: [arm64] + os: [win32] + + "@next/swc-win32-x64-msvc@15.2.5": + resolution: + { + integrity: sha512-tBDNVUcI7U03+3oMvJ11zrtVin5p0NctiuKmTGyaTIEAVj9Q77xukLXGXRnWxKRIIdFG4OTA2rUVGZDYOwgmAA==, + } + engines: { node: ">= 10" } + cpu: [x64] + os: [win32] + + "@nodelib/fs.scandir@2.1.5": + resolution: + { + integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==, + } + engines: { node: ">= 8" } + + "@nodelib/fs.stat@2.0.5": + resolution: + { + integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==, + } + engines: { node: ">= 8" } + + "@nodelib/fs.walk@1.2.8": + resolution: + { + integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==, + } + engines: { node: ">= 8" } + + "@nolyfill/is-core-module@1.0.39": + resolution: + { + integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==, + } + engines: { node: ">=12.4.0" } + + "@radix-ui/number@1.1.1": + resolution: + { + integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==, + } + + "@radix-ui/primitive@1.1.3": + resolution: + { + integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==, + } + + "@radix-ui/react-accordion@1.2.12": + resolution: + { + integrity: sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-alert-dialog@1.1.15": + resolution: + { + integrity: sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-arrow@1.1.7": + resolution: + { + integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-avatar@1.1.11": + resolution: + { + integrity: sha512-0Qk603AHGV28BOBO34p7IgD5m+V5Sg/YovfayABkoDDBM5d3NCx0Mp4gGrjzLGes1jV5eNOE1r3itqOR33VC6Q==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-checkbox@1.3.3": + resolution: + { + integrity: sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-collapsible@1.1.12": + resolution: + { + integrity: sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-collection@1.1.7": + resolution: + { + integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-compose-refs@1.1.2": + resolution: + { + integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==, + } + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + + "@radix-ui/react-context@1.1.2": + resolution: + { + integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==, + } + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + + "@radix-ui/react-context@1.1.3": + resolution: + { + integrity: sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==, + } + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + + "@radix-ui/react-dialog@1.1.15": + resolution: + { + integrity: sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-direction@1.1.1": + resolution: + { + integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==, + } + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + + "@radix-ui/react-dismissable-layer@1.1.11": + resolution: + { + integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-dropdown-menu@2.1.16": + resolution: + { + integrity: sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-focus-guards@1.1.3": + resolution: + { + integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==, + } + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + + "@radix-ui/react-focus-scope@1.1.7": + resolution: + { + integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-hover-card@1.1.15": + resolution: + { + integrity: sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-icons@1.3.2": + resolution: + { + integrity: sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g==, + } + peerDependencies: + react: ^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc + + "@radix-ui/react-id@1.1.1": + resolution: + { + integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==, + } + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + + "@radix-ui/react-label@2.1.8": + resolution: + { + integrity: sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-menu@2.1.16": + resolution: + { + integrity: sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-popover@1.1.15": + resolution: + { + integrity: sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-popper@1.2.8": + resolution: + { + integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-portal@1.1.9": + resolution: + { + integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-presence@1.1.5": + resolution: + { + integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-primitive@2.1.3": + resolution: + { + integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-primitive@2.1.4": + resolution: + { + integrity: sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-progress@1.1.8": + resolution: + { + integrity: sha512-+gISHcSPUJ7ktBy9RnTqbdKW78bcGke3t6taawyZ71pio1JewwGSJizycs7rLhGTvMJYCQB1DBK4KQsxs7U8dA==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-radio-group@1.3.8": + resolution: + { + integrity: sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-roving-focus@1.1.11": + resolution: + { + integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-scroll-area@1.2.10": + resolution: + { + integrity: sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-select@2.2.6": + resolution: + { + integrity: sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-separator@1.1.8": + resolution: + { + integrity: sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-slider@1.3.6": + resolution: + { + integrity: sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-slot@1.2.3": + resolution: + { + integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==, + } + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + + "@radix-ui/react-slot@1.2.4": + resolution: + { + integrity: sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==, + } + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + + "@radix-ui/react-switch@1.2.6": + resolution: + { + integrity: sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-tabs@1.1.13": + resolution: + { + integrity: sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-toast@1.2.15": + resolution: + { + integrity: sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-tooltip@1.2.8": + resolution: + { + integrity: sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/react-use-callback-ref@1.1.1": + resolution: + { + integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==, + } + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + + "@radix-ui/react-use-controllable-state@1.2.2": + resolution: + { + integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==, + } + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + + "@radix-ui/react-use-effect-event@0.0.2": + resolution: + { + integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==, + } + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + + "@radix-ui/react-use-escape-keydown@1.1.1": + resolution: + { + integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==, + } + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + + "@radix-ui/react-use-is-hydrated@0.1.0": + resolution: + { + integrity: sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==, + } + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + + "@radix-ui/react-use-layout-effect@1.1.1": + resolution: + { + integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==, + } + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + + "@radix-ui/react-use-previous@1.1.1": + resolution: + { + integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==, + } + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + + "@radix-ui/react-use-rect@1.1.1": + resolution: + { + integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==, + } + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + + "@radix-ui/react-use-size@1.1.1": + resolution: + { + integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==, + } + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + + "@radix-ui/react-visually-hidden@1.2.3": + resolution: + { + integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + + "@radix-ui/rect@1.1.1": + resolution: + { + integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==, + } + + "@reduxjs/toolkit@2.11.2": + resolution: + { + integrity: sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==, + } + 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 + + "@rtsao/scc@1.1.0": + resolution: + { + integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==, + } + + "@rushstack/eslint-patch@1.16.1": + resolution: + { + integrity: sha512-TvZbIpeKqGQQ7X0zSCvPH9riMSFQFSggnfBjFZ1mEoILW+UuXCKwOoPcgjMwiUtRqFZ8jWhPJc4um14vC6I4ag==, + } + + "@standard-schema/spec@1.1.0": + resolution: + { + integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==, + } + + "@standard-schema/utils@0.3.0": + resolution: + { + integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==, + } + + "@swc/counter@0.1.3": + resolution: + { + integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==, + } + + "@swc/helpers@0.5.15": + resolution: + { + integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==, + } + + "@tailwindcss/typography@0.5.19": + resolution: + { + integrity: sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==, + } + peerDependencies: + tailwindcss: ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" + + "@tanstack/react-table@8.21.3": + resolution: + { + integrity: sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==, + } + engines: { node: ">=12" } + peerDependencies: + react: ">=16.8" + react-dom: ">=16.8" + + "@tanstack/table-core@8.21.3": + resolution: + { + integrity: sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==, + } + engines: { node: ">=12" } + + "@tybys/wasm-util@0.10.1": + resolution: + { + integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==, + } + + "@types/d3-array@3.2.2": + resolution: + { + integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==, + } + + "@types/d3-color@3.1.3": + resolution: + { + integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==, + } + + "@types/d3-ease@3.0.2": + resolution: + { + integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==, + } + + "@types/d3-interpolate@3.0.4": + resolution: + { + integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==, + } + + "@types/d3-path@3.1.1": + resolution: + { + integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==, + } + + "@types/d3-scale@4.0.9": + resolution: + { + integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==, + } + + "@types/d3-shape@3.1.8": + resolution: + { + integrity: sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==, + } + + "@types/d3-time@3.0.4": + resolution: + { + integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==, + } + + "@types/d3-timer@3.0.2": + resolution: + { + integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==, + } + + "@types/hast@2.3.10": + resolution: + { + integrity: sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==, + } + + "@types/json5@0.0.29": + resolution: + { + integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==, + } + + "@types/lodash@4.17.24": + resolution: + { + integrity: sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==, + } + + "@types/node@22.5.4": + resolution: + { + integrity: sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==, + } + + "@types/react-copy-to-clipboard@5.0.7": + resolution: + { + integrity: sha512-Gft19D+as4M+9Whq1oglhmK49vqPhcLzk8WfvfLvaYMIPYanyfLy0+CwFucMJfdKoSFyySPmkkWn8/E6voQXjQ==, + } + + "@types/react-dom@19.2.3": + resolution: + { + integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==, + } + peerDependencies: + "@types/react": ^19.2.0 + + "@types/react-syntax-highlighter@15.5.13": + resolution: + { + integrity: sha512-uLGJ87j6Sz8UaBAooU0T6lWJ0dBmjZgN1PZTrj05TNql2/XpC6+4HhMT5syIdFUUt+FASfCeLLv4kBygNU+8qA==, + } + + "@types/react@19.2.14": + resolution: + { + integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==, + } + + "@types/unist@2.0.11": + resolution: + { + integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==, + } + + "@types/use-sync-external-store@0.0.6": + resolution: + { + integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==, + } + + "@types/uuid@9.0.8": + resolution: + { + integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==, + } + + "@typescript-eslint/eslint-plugin@8.58.2": + resolution: + { + integrity: sha512-aC2qc5thQahutKjP+cl8cgN9DWe3ZUqVko30CMSZHnFEHyhOYoZSzkGtAI2mcwZ38xeImDucI4dnqsHiOYuuCw==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + "@typescript-eslint/parser": ^8.58.2 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + + "@typescript-eslint/parser@8.58.2": + resolution: + { + integrity: sha512-/Zb/xaIDfxeJnvishjGdcR4jmr7S+bda8PKNhRGdljDM+elXhlvN0FyPSsMnLmJUrVG9aPO6dof80wjMawsASg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + + "@typescript-eslint/project-service@8.58.2": + resolution: + { + integrity: sha512-Cq6UfpZZk15+r87BkIh5rDpi38W4b+Sjnb8wQCPPDDweS/LRCFjCyViEbzHk5Ck3f2QDfgmlxqSa7S7clDtlfg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + typescript: ">=4.8.4 <6.1.0" + + "@typescript-eslint/scope-manager@8.58.2": + resolution: + { + integrity: sha512-SgmyvDPexWETQek+qzZnrG6844IaO02UVyOLhI4wpo82dpZJY9+6YZCKAMFzXb7qhx37mFK1QcPQ18tud+vo6Q==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + "@typescript-eslint/tsconfig-utils@8.58.2": + resolution: + { + integrity: sha512-3SR+RukipDvkkKp/d0jP0dyzuls3DbGmwDpVEc5wqk5f38KFThakqAAO0XMirWAE+kT00oTauTbzMFGPoAzB0A==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + typescript: ">=4.8.4 <6.1.0" + + "@typescript-eslint/type-utils@8.58.2": + resolution: + { + integrity: sha512-Z7EloNR/B389FvabdGeTo2XMs4W9TjtPiO9DAsmT0yom0bwlPyRjkJ1uCdW1DvrrrYP50AJZ9Xc3sByZA9+dcg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + + "@typescript-eslint/types@8.58.2": + resolution: + { + integrity: sha512-9TukXyATBQf/Jq9AMQXfvurk+G5R2MwfqQGDR2GzGz28HvY/lXNKGhkY+6IOubwcquikWk5cjlgPvD2uAA7htQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + "@typescript-eslint/typescript-estree@8.58.2": + resolution: + { + integrity: sha512-ELGuoofuhhoCvNbQjFFiobFcGgcDCEm0ThWdmO4Z0UzLqPXS3KFvnEZ+SHewwOYHjM09tkzOWXNTv9u6Gqtyuw==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + typescript: ">=4.8.4 <6.1.0" + + "@typescript-eslint/utils@8.58.2": + resolution: + { + integrity: sha512-QZfjHNEzPY8+l0+fIXMvuQ2sJlplB4zgDZvA+NmvZsZv3EQwOcc1DuIU1VJUTWZ/RKouBMhDyNaBMx4sWvrzRA==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + + "@typescript-eslint/visitor-keys@8.58.2": + resolution: + { + integrity: sha512-f1WO2Lx8a9t8DARmcWAUPJbu0G20bJlj8L4z72K00TMeJAoyLr/tHhI/pzYBLrR4dXWkcxO1cWYZEOX8DKHTqA==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + "@ungap/structured-clone@1.3.0": + resolution: + { + integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==, + } + + "@unrs/resolver-binding-android-arm-eabi@1.11.1": + resolution: + { + integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==, + } + cpu: [arm] + os: [android] + + "@unrs/resolver-binding-android-arm64@1.11.1": + resolution: + { + integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==, + } + cpu: [arm64] + os: [android] + + "@unrs/resolver-binding-darwin-arm64@1.11.1": + resolution: + { + integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==, + } + cpu: [arm64] + os: [darwin] + + "@unrs/resolver-binding-darwin-x64@1.11.1": + resolution: + { + integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==, + } + cpu: [x64] + os: [darwin] + + "@unrs/resolver-binding-freebsd-x64@1.11.1": + resolution: + { + integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==, + } + cpu: [x64] + os: [freebsd] + + "@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1": + resolution: + { + integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==, + } + cpu: [arm] + os: [linux] + + "@unrs/resolver-binding-linux-arm-musleabihf@1.11.1": + resolution: + { + integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==, + } + cpu: [arm] + os: [linux] + + "@unrs/resolver-binding-linux-arm64-gnu@1.11.1": + resolution: + { + integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==, + } + cpu: [arm64] + os: [linux] + libc: [glibc] + + "@unrs/resolver-binding-linux-arm64-musl@1.11.1": + resolution: + { + integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==, + } + cpu: [arm64] + os: [linux] + libc: [musl] + + "@unrs/resolver-binding-linux-ppc64-gnu@1.11.1": + resolution: + { + integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==, + } + cpu: [ppc64] + os: [linux] + libc: [glibc] + + "@unrs/resolver-binding-linux-riscv64-gnu@1.11.1": + resolution: + { + integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==, + } + cpu: [riscv64] + os: [linux] + libc: [glibc] + + "@unrs/resolver-binding-linux-riscv64-musl@1.11.1": + resolution: + { + integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==, + } + cpu: [riscv64] + os: [linux] + libc: [musl] + + "@unrs/resolver-binding-linux-s390x-gnu@1.11.1": + resolution: + { + integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==, + } + cpu: [s390x] + os: [linux] + libc: [glibc] + + "@unrs/resolver-binding-linux-x64-gnu@1.11.1": + resolution: + { + integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==, + } + cpu: [x64] + os: [linux] + libc: [glibc] + + "@unrs/resolver-binding-linux-x64-musl@1.11.1": + resolution: + { + integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==, + } + cpu: [x64] + os: [linux] + libc: [musl] + + "@unrs/resolver-binding-wasm32-wasi@1.11.1": + resolution: + { + integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==, + } + engines: { node: ">=14.0.0" } + cpu: [wasm32] + + "@unrs/resolver-binding-win32-arm64-msvc@1.11.1": + resolution: + { + integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==, + } + cpu: [arm64] + os: [win32] + + "@unrs/resolver-binding-win32-ia32-msvc@1.11.1": + resolution: + { + integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==, + } + cpu: [ia32] + os: [win32] + + "@unrs/resolver-binding-win32-x64-msvc@1.11.1": + resolution: + { + integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==, + } + cpu: [x64] + os: [win32] + + acorn-jsx@5.3.2: + resolution: + { + integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==, + } + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.16.0: + resolution: + { + integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==, + } + engines: { node: ">=0.4.0" } + hasBin: true + + ajv@6.14.0: + resolution: + { + integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==, + } + + ansi-regex@5.0.1: + resolution: + { + integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==, + } + engines: { node: ">=8" } + + ansi-styles@4.3.0: + resolution: + { + integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==, + } + engines: { node: ">=8" } + + any-promise@1.3.0: + resolution: + { + integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==, + } + + anymatch@3.1.3: + resolution: + { + integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==, + } + engines: { node: ">= 8" } + + arg@5.0.2: + resolution: + { + integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==, + } + + argparse@2.0.1: + resolution: + { + integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==, + } + + aria-hidden@1.2.6: + resolution: + { + integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==, + } + engines: { node: ">=10" } + + aria-query@5.3.2: + resolution: + { + integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==, + } + engines: { node: ">= 0.4" } + + array-buffer-byte-length@1.0.2: + resolution: + { + integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==, + } + engines: { node: ">= 0.4" } + + array-includes@3.1.9: + resolution: + { + integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==, + } + engines: { node: ">= 0.4" } + + array.prototype.findlast@1.2.5: + resolution: + { + integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==, + } + engines: { node: ">= 0.4" } + + array.prototype.findlastindex@1.2.6: + resolution: + { + integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==, + } + engines: { node: ">= 0.4" } + + array.prototype.flat@1.3.3: + resolution: + { + integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==, + } + engines: { node: ">= 0.4" } + + array.prototype.flatmap@1.3.3: + resolution: + { + integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==, + } + engines: { node: ">= 0.4" } + + array.prototype.tosorted@1.1.4: + resolution: + { + integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==, + } + engines: { node: ">= 0.4" } + + arraybuffer.prototype.slice@1.0.4: + resolution: + { + integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==, + } + engines: { node: ">= 0.4" } + + ast-types-flow@0.0.8: + resolution: + { + integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==, + } + + async-function@1.0.0: + resolution: + { + integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==, + } + engines: { node: ">= 0.4" } + + asynckit@0.4.0: + resolution: + { + integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==, + } + + autoprefixer@10.5.0: + resolution: + { + integrity: sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==, + } + engines: { node: ^10 || ^12 || >=14 } + hasBin: true + peerDependencies: + postcss: ^8.1.0 + + available-typed-arrays@1.0.7: + resolution: + { + integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==, + } + engines: { node: ">= 0.4" } + + axe-core@4.11.3: + resolution: + { + integrity: sha512-zBQouZixDTbo3jMGqHKyePxYxr1e5W8UdTmBQ7sNtaA9M2bE32daxxPLS/jojhKOHxQ7LWwPjfiwf/fhaJWzlg==, + } + engines: { node: ">=4" } + + axios@1.15.0: + resolution: + { + integrity: sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==, + } + + axobject-query@4.1.0: + resolution: + { + integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==, + } + engines: { node: ">= 0.4" } + + balanced-match@1.0.2: + resolution: + { + integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==, + } + + balanced-match@4.0.4: + resolution: + { + integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==, + } + engines: { node: 18 || 20 || >=22 } + + baseline-browser-mapping@2.10.19: + resolution: + { + integrity: sha512-qCkNLi2sfBOn8XhZQ0FXsT1Ki/Yo5P90hrkRamVFRS7/KV9hpfA4HkoWNU152+8w0zPjnxo5psx5NL3PSGgv5g==, + } + engines: { node: ">=6.0.0" } + hasBin: true + + binary-extensions@2.3.0: + resolution: + { + integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==, + } + engines: { node: ">=8" } + + brace-expansion@1.1.14: + resolution: + { + integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==, + } + + brace-expansion@5.0.5: + resolution: + { + integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==, + } + engines: { node: 18 || 20 || >=22 } + + braces@3.0.3: + resolution: + { + integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==, + } + engines: { node: ">=8" } + + browserslist@4.28.2: + resolution: + { + integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==, + } + engines: { node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7 } + hasBin: true + + busboy@1.6.0: + resolution: + { + integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==, + } + engines: { node: ">=10.16.0" } + + call-bind-apply-helpers@1.0.2: + resolution: + { + integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==, + } + engines: { node: ">= 0.4" } + + call-bind@1.0.9: + resolution: + { + integrity: sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==, + } + engines: { node: ">= 0.4" } + + call-bound@1.0.4: + resolution: + { + integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==, + } + engines: { node: ">= 0.4" } + + callsites@3.1.0: + resolution: + { + integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==, + } + engines: { node: ">=6" } + + camelcase-css@2.0.1: + resolution: + { + integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==, + } + engines: { node: ">= 6" } + + caniuse-lite@1.0.30001788: + resolution: + { + integrity: sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==, + } + + chalk@4.1.2: + resolution: + { + integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==, + } + engines: { node: ">=10" } + + character-entities-legacy@1.1.4: + resolution: + { + integrity: sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==, + } + + character-entities@1.2.4: + resolution: + { + integrity: sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==, + } + + character-reference-invalid@1.1.4: + resolution: + { + integrity: sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==, + } + + chokidar@3.6.0: + resolution: + { + integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==, + } + engines: { node: ">= 8.10.0" } + + class-variance-authority@0.7.1: + resolution: + { + integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==, + } + + client-only@0.0.1: + resolution: + { + integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==, + } + + clsx@2.1.1: + resolution: + { + integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==, + } + engines: { node: ">=6" } + + cmdk@1.1.1: + resolution: + { + integrity: sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg==, + } + peerDependencies: + react: ^18 || ^19 || ^19.0.0-rc + react-dom: ^18 || ^19 || ^19.0.0-rc + + color-convert@2.0.1: + resolution: + { + integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==, + } + engines: { node: ">=7.0.0" } + + color-name@1.1.4: + resolution: + { + integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, + } + + color-string@1.9.1: + resolution: + { + integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==, + } + + color@4.2.3: + resolution: + { + integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==, + } + engines: { node: ">=12.5.0" } + + combined-stream@1.0.8: + resolution: + { + integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==, + } + engines: { node: ">= 0.8" } + + comma-separated-tokens@1.0.8: + resolution: + { + integrity: sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==, + } + + commander@4.1.1: + resolution: + { + integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==, + } + engines: { node: ">= 6" } + + concat-map@0.0.1: + resolution: + { + integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==, + } + + copy-to-clipboard@3.3.3: + resolution: + { + integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==, + } + + cross-spawn@7.0.6: + resolution: + { + integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==, + } + engines: { node: ">= 8" } + + cssesc@3.0.0: + resolution: + { + integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==, + } + engines: { node: ">=4" } + hasBin: true + + csstype@3.2.3: + resolution: + { + integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==, + } + + d3-array@3.2.4: + resolution: + { + integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==, + } + engines: { node: ">=12" } + + d3-color@3.1.0: + resolution: + { + integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==, + } + engines: { node: ">=12" } + + d3-ease@3.0.1: + resolution: + { + integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==, + } + engines: { node: ">=12" } + + d3-format@3.1.2: + resolution: + { + integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==, + } + engines: { node: ">=12" } + + d3-interpolate@3.0.1: + resolution: + { + integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==, + } + engines: { node: ">=12" } + + d3-path@3.1.0: + resolution: + { + integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==, + } + engines: { node: ">=12" } + + d3-scale@4.0.2: + resolution: + { + integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==, + } + engines: { node: ">=12" } + + d3-shape@3.2.0: + resolution: + { + integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==, + } + engines: { node: ">=12" } + + d3-time-format@4.1.0: + resolution: + { + integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==, + } + engines: { node: ">=12" } + + d3-time@3.1.0: + resolution: + { + integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==, + } + engines: { node: ">=12" } + + d3-timer@3.0.1: + resolution: + { + integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==, + } + engines: { node: ">=12" } + + damerau-levenshtein@1.0.8: + resolution: + { + integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==, + } + + data-view-buffer@1.0.2: + resolution: + { + integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==, + } + engines: { node: ">= 0.4" } + + data-view-byte-length@1.0.2: + resolution: + { + integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==, + } + engines: { node: ">= 0.4" } + + data-view-byte-offset@1.0.1: + resolution: + { + integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==, + } + engines: { node: ">= 0.4" } + + date-fns@4.1.0: + resolution: + { + integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==, + } + + debug@3.2.7: + resolution: + { + integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==, + } + peerDependencies: + supports-color: "*" + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.3: + resolution: + { + integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==, + } + engines: { node: ">=6.0" } + peerDependencies: + supports-color: "*" + peerDependenciesMeta: + supports-color: + optional: true + + decimal.js-light@2.5.1: + resolution: + { + integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==, + } + + deep-is@0.1.4: + resolution: + { + integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==, + } + + define-data-property@1.1.4: + resolution: + { + integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==, + } + engines: { node: ">= 0.4" } + + define-properties@1.2.1: + resolution: + { + integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==, + } + engines: { node: ">= 0.4" } + + delayed-stream@1.0.0: + resolution: + { + integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==, + } + engines: { node: ">=0.4.0" } + + detect-libc@2.1.2: + resolution: + { + integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==, + } + engines: { node: ">=8" } + + detect-node-es@1.1.0: + resolution: + { + integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==, + } + + didyoumean@1.2.2: + resolution: + { + integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==, + } + + dlv@1.1.3: + resolution: + { + integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==, + } + + doctrine@2.1.0: + resolution: + { + integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==, + } + engines: { node: ">=0.10.0" } + + doctrine@3.0.0: + resolution: + { + integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==, + } + engines: { node: ">=6.0.0" } + + dom-helpers@5.2.1: + resolution: + { + integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==, + } + + dunder-proto@1.0.1: + resolution: + { + integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==, + } + engines: { node: ">= 0.4" } + + electron-to-chromium@1.5.337: + resolution: + { + integrity: sha512-15gKW9mRUNP9RdzhedJNypFUxtYWSXohFz2nTLzM272xbRXHws68kNDzyATG3qej+vUj/7Sn9hf5XTDh0XK6/w==, + } + + emoji-regex@9.2.2: + resolution: + { + integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==, + } + + es-abstract@1.24.2: + resolution: + { + integrity: sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==, + } + engines: { node: ">= 0.4" } + + es-define-property@1.0.1: + resolution: + { + integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==, + } + engines: { node: ">= 0.4" } + + es-errors@1.3.0: + resolution: + { + integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==, + } + engines: { node: ">= 0.4" } + + es-iterator-helpers@1.3.2: + resolution: + { + integrity: sha512-HVLACW1TppGYjJ8H6/jqH/pqOtKRw6wMlrB23xfExmFWxFquAIWCmwoLsOyN96K4a5KbmOf5At9ZUO3GZbetAw==, + } + engines: { node: ">= 0.4" } + + es-object-atoms@1.1.1: + resolution: + { + integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==, + } + engines: { node: ">= 0.4" } + + es-set-tostringtag@2.1.0: + resolution: + { + integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==, + } + engines: { node: ">= 0.4" } + + es-shim-unscopables@1.1.0: + resolution: + { + integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==, + } + engines: { node: ">= 0.4" } + + es-to-primitive@1.3.0: + resolution: + { + integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==, + } + engines: { node: ">= 0.4" } + + escalade@3.2.0: + resolution: + { + integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==, + } + engines: { node: ">=6" } + + escape-string-regexp@4.0.0: + resolution: + { + integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==, + } + engines: { node: ">=10" } + + eslint-config-next@15.2.6: + resolution: + { + integrity: sha512-NZHjg3/y3xIBHMaWu6ayuy0MPg4Udt6A/Y3kXr6E0kTc61MxT4A6jTbkOVNRAfVx5SgZTDu6COVqFpiBLBcRaw==, + } + peerDependencies: + eslint: ^7.23.0 || ^8.0.0 || ^9.0.0 + typescript: ">=3.3.1" + peerDependenciesMeta: + typescript: + optional: true + + eslint-import-resolver-node@0.3.10: + resolution: + { + integrity: sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==, + } + + eslint-import-resolver-typescript@3.10.1: + resolution: + { + integrity: sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==, + } + engines: { node: ^14.18.0 || >=16.0.0 } + peerDependencies: + eslint: "*" + eslint-plugin-import: "*" + eslint-plugin-import-x: "*" + peerDependenciesMeta: + eslint-plugin-import: + optional: true + eslint-plugin-import-x: + optional: true + + eslint-module-utils@2.12.1: + resolution: + { + integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==, + } + engines: { node: ">=4" } + peerDependencies: + "@typescript-eslint/parser": "*" + eslint: "*" + eslint-import-resolver-node: "*" + eslint-import-resolver-typescript: "*" + eslint-import-resolver-webpack: "*" + peerDependenciesMeta: + "@typescript-eslint/parser": + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-import@2.32.0: + resolution: + { + integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==, + } + engines: { node: ">=4" } + peerDependencies: + "@typescript-eslint/parser": "*" + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + peerDependenciesMeta: + "@typescript-eslint/parser": + optional: true + + eslint-plugin-jsx-a11y@6.10.2: + resolution: + { + integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==, + } + engines: { node: ">=4.0" } + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 + + eslint-plugin-react-hooks@5.2.0: + resolution: + { + integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==, + } + engines: { node: ">=10" } + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + + eslint-plugin-react@7.37.5: + resolution: + { + integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==, + } + engines: { node: ">=4" } + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + + eslint-scope@7.2.2: + resolution: + { + integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + + eslint-visitor-keys@3.4.3: + resolution: + { + integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + + eslint-visitor-keys@5.0.1: + resolution: + { + integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==, + } + engines: { node: ^20.19.0 || ^22.13.0 || >=24 } + + eslint@8.57.1: + resolution: + { + integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + hasBin: true + + espree@9.6.1: + resolution: + { + integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + + esquery@1.7.0: + resolution: + { + integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==, + } + engines: { node: ">=0.10" } + + esrecurse@4.3.0: + resolution: + { + integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==, + } + engines: { node: ">=4.0" } + + estraverse@5.3.0: + resolution: + { + integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==, + } + engines: { node: ">=4.0" } + + esutils@2.0.3: + resolution: + { + integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==, + } + engines: { node: ">=0.10.0" } + + eventemitter3@4.0.7: + resolution: + { + integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==, + } + + fast-deep-equal@3.1.3: + resolution: + { + integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==, + } + + fast-equals@5.4.0: + resolution: + { + integrity: sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==, + } + engines: { node: ">=6.0.0" } + + fast-glob@3.3.1: + resolution: + { + integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==, + } + engines: { node: ">=8.6.0" } + + fast-glob@3.3.3: + resolution: + { + integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==, + } + engines: { node: ">=8.6.0" } + + fast-json-stable-stringify@2.1.0: + resolution: + { + integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==, + } + + fast-levenshtein@2.0.6: + resolution: + { + integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==, + } + + fastq@1.20.1: + resolution: + { + integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==, + } + + fault@1.0.4: + resolution: + { + integrity: sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==, + } + + fdir@6.5.0: + resolution: + { + integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==, + } + engines: { node: ">=12.0.0" } + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@6.0.1: + resolution: + { + integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==, + } + engines: { node: ^10.12.0 || >=12.0.0 } + + fill-range@7.1.1: + resolution: + { + integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==, + } + engines: { node: ">=8" } + + find-up@5.0.0: + resolution: + { + integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==, + } + engines: { node: ">=10" } + + flat-cache@3.2.0: + resolution: + { + integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==, + } + engines: { node: ^10.12.0 || >=12.0.0 } + + flatted@3.4.2: + resolution: + { + integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==, + } + + follow-redirects@1.16.0: + resolution: + { + integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==, + } + engines: { node: ">=4.0" } + peerDependencies: + debug: "*" + peerDependenciesMeta: + debug: + optional: true + + for-each@0.3.5: + resolution: + { + integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==, + } + engines: { node: ">= 0.4" } + + form-data@4.0.5: + resolution: + { + integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==, + } + engines: { node: ">= 6" } + + format@0.2.2: + resolution: + { + integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==, + } + engines: { node: ">=0.4.x" } + + fraction.js@5.3.4: + resolution: + { + integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==, + } + + framer-motion@12.38.0: + resolution: + { + integrity: sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g==, + } + peerDependencies: + "@emotion/is-prop-valid": "*" + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@emotion/is-prop-valid": + optional: true + react: + optional: true + react-dom: + optional: true + + fs.realpath@1.0.0: + resolution: + { + integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==, + } + + fsevents@2.3.3: + resolution: + { + integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==, + } + engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 } + os: [darwin] + + function-bind@1.1.2: + resolution: + { + integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==, + } + + function.prototype.name@1.1.8: + resolution: + { + integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==, + } + engines: { node: ">= 0.4" } + + functions-have-names@1.2.3: + resolution: + { + integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==, + } + + generator-function@2.0.1: + resolution: + { + integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==, + } + engines: { node: ">= 0.4" } + + get-intrinsic@1.3.0: + resolution: + { + integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==, + } + engines: { node: ">= 0.4" } + + get-nonce@1.0.1: + resolution: + { + integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==, + } + engines: { node: ">=6" } + + get-proto@1.0.1: + resolution: + { + integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==, + } + engines: { node: ">= 0.4" } + + get-symbol-description@1.1.0: + resolution: + { + integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==, + } + engines: { node: ">= 0.4" } + + get-tsconfig@4.14.0: + resolution: + { + integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==, + } + + glob-parent@5.1.2: + resolution: + { + integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==, + } + engines: { node: ">= 6" } + + glob-parent@6.0.2: + resolution: + { + integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==, + } + engines: { node: ">=10.13.0" } + + glob@7.2.3: + resolution: + { + integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==, + } + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + + globals@13.24.0: + resolution: + { + integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==, + } + engines: { node: ">=8" } + + globalthis@1.0.4: + resolution: + { + integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==, + } + engines: { node: ">= 0.4" } + + gopd@1.2.0: + resolution: + { + integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==, + } + engines: { node: ">= 0.4" } + + graphemer@1.4.0: + resolution: + { + integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==, + } + + has-bigints@1.1.0: + resolution: + { + integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==, + } + engines: { node: ">= 0.4" } + + has-flag@4.0.0: + resolution: + { + integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==, + } + engines: { node: ">=8" } + + has-property-descriptors@1.0.2: + resolution: + { + integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==, + } + + has-proto@1.2.0: + resolution: + { + integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==, + } + engines: { node: ">= 0.4" } + + has-symbols@1.1.0: + resolution: + { + integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==, + } + engines: { node: ">= 0.4" } + + has-tostringtag@1.0.2: + resolution: + { + integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==, + } + engines: { node: ">= 0.4" } + + hasown@2.0.2: + resolution: + { + integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==, + } + engines: { node: ">= 0.4" } + + hast-util-parse-selector@2.2.5: + resolution: + { + integrity: sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==, + } + + hastscript@6.0.0: + resolution: + { + integrity: sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==, + } + + highlight.js@10.7.3: + resolution: + { + integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==, + } + + highlightjs-vue@1.0.0: + resolution: + { + integrity: sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==, + } + + ignore@5.3.2: + resolution: + { + integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==, + } + engines: { node: ">= 4" } + + ignore@7.0.5: + resolution: + { + integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==, + } + engines: { node: ">= 4" } + + immer@11.1.4: + resolution: + { + integrity: sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw==, + } + + import-fresh@3.3.1: + resolution: + { + integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==, + } + engines: { node: ">=6" } + + imurmurhash@0.1.4: + resolution: + { + integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==, + } + engines: { node: ">=0.8.19" } + + inflight@1.0.6: + resolution: + { + integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==, + } + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: + { + integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==, + } + + internal-slot@1.1.0: + resolution: + { + integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==, + } + engines: { node: ">= 0.4" } + + internmap@2.0.3: + resolution: + { + integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==, + } + engines: { node: ">=12" } + + is-alphabetical@1.0.4: + resolution: + { + integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==, + } + + is-alphanumerical@1.0.4: + resolution: + { + integrity: sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==, + } + + is-array-buffer@3.0.5: + resolution: + { + integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==, + } + engines: { node: ">= 0.4" } + + is-arrayish@0.3.4: + resolution: + { + integrity: sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==, + } + + is-async-function@2.1.1: + resolution: + { + integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==, + } + engines: { node: ">= 0.4" } + + is-bigint@1.1.0: + resolution: + { + integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==, + } + engines: { node: ">= 0.4" } + + is-binary-path@2.1.0: + resolution: + { + integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==, + } + engines: { node: ">=8" } + + is-boolean-object@1.2.2: + resolution: + { + integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==, + } + engines: { node: ">= 0.4" } + + is-bun-module@2.0.0: + resolution: + { + integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==, + } + + is-callable@1.2.7: + resolution: + { + integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==, + } + engines: { node: ">= 0.4" } + + is-core-module@2.16.1: + resolution: + { + integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==, + } + engines: { node: ">= 0.4" } + + is-data-view@1.0.2: + resolution: + { + integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==, + } + engines: { node: ">= 0.4" } + + is-date-object@1.1.0: + resolution: + { + integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==, + } + engines: { node: ">= 0.4" } + + is-decimal@1.0.4: + resolution: + { + integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==, + } + + is-extglob@2.1.1: + resolution: + { + integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==, + } + engines: { node: ">=0.10.0" } + + is-finalizationregistry@1.1.1: + resolution: + { + integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==, + } + engines: { node: ">= 0.4" } + + is-generator-function@1.1.2: + resolution: + { + integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==, + } + engines: { node: ">= 0.4" } + + is-glob@4.0.3: + resolution: + { + integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==, + } + engines: { node: ">=0.10.0" } + + is-hexadecimal@1.0.4: + resolution: + { + integrity: sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==, + } + + is-map@2.0.3: + resolution: + { + integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==, + } + engines: { node: ">= 0.4" } + + is-negative-zero@2.0.3: + resolution: + { + integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==, + } + engines: { node: ">= 0.4" } + + is-number-object@1.1.1: + resolution: + { + integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==, + } + engines: { node: ">= 0.4" } + + is-number@7.0.0: + resolution: + { + integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==, + } + engines: { node: ">=0.12.0" } + + is-path-inside@3.0.3: + resolution: + { + integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==, + } + engines: { node: ">=8" } + + is-regex@1.2.1: + resolution: + { + integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==, + } + engines: { node: ">= 0.4" } + + is-set@2.0.3: + resolution: + { + integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==, + } + engines: { node: ">= 0.4" } + + is-shared-array-buffer@1.0.4: + resolution: + { + integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==, + } + engines: { node: ">= 0.4" } + + is-string@1.1.1: + resolution: + { + integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==, + } + engines: { node: ">= 0.4" } + + is-symbol@1.1.1: + resolution: + { + integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==, + } + engines: { node: ">= 0.4" } + + is-typed-array@1.1.15: + resolution: + { + integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==, + } + engines: { node: ">= 0.4" } + + is-weakmap@2.0.2: + resolution: + { + integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==, + } + engines: { node: ">= 0.4" } + + is-weakref@1.1.1: + resolution: + { + integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==, + } + engines: { node: ">= 0.4" } + + is-weakset@2.0.4: + resolution: + { + integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==, + } + engines: { node: ">= 0.4" } + + isarray@2.0.5: + resolution: + { + integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==, + } + + isexe@2.0.0: + resolution: + { + integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==, + } + + iterator.prototype@1.1.5: + resolution: + { + integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==, + } + engines: { node: ">= 0.4" } + + jiti@1.21.7: + resolution: + { + integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==, + } + hasBin: true + + js-tokens@4.0.0: + resolution: + { + integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==, + } + + js-yaml@4.1.1: + resolution: + { + integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==, + } + hasBin: true + + json-buffer@3.0.1: + resolution: + { + integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==, + } + + json-schema-traverse@0.4.1: + resolution: + { + integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==, + } + + json-stable-stringify-without-jsonify@1.0.1: + resolution: + { + integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==, + } + + json5@1.0.2: + resolution: + { + integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==, + } + hasBin: true + + jsx-ast-utils@3.3.5: + resolution: + { + integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==, + } + engines: { node: ">=4.0" } + + keyv@4.5.4: + resolution: + { + integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==, + } + + language-subtag-registry@0.3.23: + resolution: + { + integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==, + } + + language-tags@1.0.9: + resolution: + { + integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==, + } + engines: { node: ">=0.10" } + + levn@0.4.1: + resolution: + { + integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==, + } + engines: { node: ">= 0.8.0" } + + lilconfig@3.1.3: + resolution: + { + integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==, + } + engines: { node: ">=14" } + + lines-and-columns@1.2.4: + resolution: + { + integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==, + } + + locate-path@6.0.0: + resolution: + { + integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==, + } + engines: { node: ">=10" } + + lodash.merge@4.6.2: + resolution: + { + integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==, + } + + lodash@4.18.1: + resolution: + { + integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==, + } + + loose-envify@1.4.0: + resolution: + { + integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==, + } + hasBin: true + + lowlight@1.20.0: + resolution: + { + integrity: sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==, + } + + lucide-react@0.542.0: + resolution: + { + integrity: sha512-w3hD8/SQB7+lzU2r4VdFyzzOzKnUjTZIF/MQJGSSvni7Llewni4vuViRppfRAa2guOsY5k4jZyxw/i9DQHv+dw==, + } + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + math-intrinsics@1.1.0: + resolution: + { + integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==, + } + engines: { node: ">= 0.4" } + + merge2@1.4.1: + resolution: + { + integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==, + } + engines: { node: ">= 8" } + + micromatch@4.0.8: + resolution: + { + integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==, + } + engines: { node: ">=8.6" } + + mime-db@1.52.0: + resolution: + { + integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==, + } + engines: { node: ">= 0.6" } + + mime-types@2.1.35: + resolution: + { + integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==, + } + engines: { node: ">= 0.6" } + + minimatch@10.2.5: + resolution: + { + integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==, + } + engines: { node: 18 || 20 || >=22 } + + minimatch@3.1.5: + resolution: + { + integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==, + } + + minimist@1.2.8: + resolution: + { + integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==, + } + + motion-dom@12.38.0: + resolution: + { + integrity: sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA==, + } + + motion-utils@12.36.0: + resolution: + { + integrity: sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg==, + } + + ms@2.1.3: + resolution: + { + integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, + } + + mz@2.7.0: + resolution: + { + integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==, + } + + nanoid@3.3.11: + resolution: + { + integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==, + } + engines: { node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1 } + hasBin: true + + napi-postinstall@0.3.4: + resolution: + { + integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==, + } + engines: { node: ^12.20.0 || ^14.18.0 || >=16.0.0 } + hasBin: true + + natural-compare@1.4.0: + resolution: + { + integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==, + } + + next-themes@0.4.6: + resolution: + { + integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==, + } + peerDependencies: + react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + + next@15.2.6: + resolution: + { + integrity: sha512-DIKFctUpZoCq5ok2ztVU+PqhWsbiqM9xNP7rHL2cAp29NQcmDp7Y6JnBBhHRbFt4bCsCZigj6uh+/Gwh2158Wg==, + } + engines: { node: ^18.18.0 || ^19.8.0 || >= 20.0.0 } + deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/security-update-2025-12-11 for more details. + hasBin: true + peerDependencies: + "@opentelemetry/api": ^1.1.0 + "@playwright/test": ^1.41.2 + 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 + peerDependenciesMeta: + "@opentelemetry/api": + optional: true + "@playwright/test": + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + + node-exports-info@1.6.0: + resolution: + { + integrity: sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==, + } + engines: { node: ">= 0.4" } + + node-releases@2.0.37: + resolution: + { + integrity: sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==, + } + + normalize-path@3.0.0: + resolution: + { + integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==, + } + engines: { node: ">=0.10.0" } + + object-assign@4.1.1: + resolution: + { + integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==, + } + engines: { node: ">=0.10.0" } + + object-hash@3.0.0: + resolution: + { + integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==, + } + engines: { node: ">= 6" } + + object-inspect@1.13.4: + resolution: + { + integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==, + } + engines: { node: ">= 0.4" } + + object-keys@1.1.1: + resolution: + { + integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==, + } + engines: { node: ">= 0.4" } + + object.assign@4.1.7: + resolution: + { + integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==, + } + engines: { node: ">= 0.4" } + + object.entries@1.1.9: + resolution: + { + integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==, + } + engines: { node: ">= 0.4" } + + object.fromentries@2.0.8: + resolution: + { + integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==, + } + engines: { node: ">= 0.4" } + + object.groupby@1.0.3: + resolution: + { + integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==, + } + engines: { node: ">= 0.4" } + + object.values@1.2.1: + resolution: + { + integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==, + } + engines: { node: ">= 0.4" } + + once@1.4.0: + resolution: + { + integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==, + } + + optionator@0.9.4: + resolution: + { + integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==, + } + engines: { node: ">= 0.8.0" } + + own-keys@1.0.1: + resolution: + { + integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==, + } + engines: { node: ">= 0.4" } + + p-limit@3.1.0: + resolution: + { + integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==, + } + engines: { node: ">=10" } + + p-locate@5.0.0: + resolution: + { + integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==, + } + engines: { node: ">=10" } + + parent-module@1.0.1: + resolution: + { + integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==, + } + engines: { node: ">=6" } + + parse-entities@2.0.0: + resolution: + { + integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==, + } + + path-exists@4.0.0: + resolution: + { + integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==, + } + engines: { node: ">=8" } + + path-is-absolute@1.0.1: + resolution: + { + integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==, + } + engines: { node: ">=0.10.0" } + + path-key@3.1.1: + resolution: + { + integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==, + } + engines: { node: ">=8" } + + path-parse@1.0.7: + resolution: + { + integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==, + } + + picocolors@1.1.1: + resolution: + { + integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==, + } + + picomatch@2.3.2: + resolution: + { + integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==, + } + engines: { node: ">=8.6" } + + picomatch@4.0.4: + resolution: + { + integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==, + } + engines: { node: ">=12" } + + pify@2.3.0: + resolution: + { + integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==, + } + engines: { node: ">=0.10.0" } + + pirates@4.0.7: + resolution: + { + integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==, + } + engines: { node: ">= 6" } + + possible-typed-array-names@1.1.0: + resolution: + { + integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==, + } + engines: { node: ">= 0.4" } + + postcss-import@15.1.0: + resolution: + { + integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==, + } + engines: { node: ">=14.0.0" } + peerDependencies: + postcss: ^8.0.0 + + postcss-js@4.1.0: + resolution: + { + integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==, + } + engines: { node: ^12 || ^14 || >= 16 } + peerDependencies: + postcss: ^8.4.21 + + postcss-load-config@6.0.1: + resolution: + { + integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==, + } + engines: { node: ">= 18" } + peerDependencies: + jiti: ">=1.21.0" + postcss: ">=8.0.9" + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + + postcss-nested@6.2.0: + resolution: + { + integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==, + } + engines: { node: ">=12.0" } + peerDependencies: + postcss: ^8.2.14 + + postcss-selector-parser@6.0.10: + resolution: + { + integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==, + } + engines: { node: ">=4" } + + postcss-selector-parser@6.1.2: + resolution: + { + integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==, + } + engines: { node: ">=4" } + + postcss-value-parser@4.2.0: + resolution: + { + integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==, + } + + postcss@8.4.31: + resolution: + { + integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==, + } + engines: { node: ^10 || ^12 || >=14 } + + postcss@8.5.10: + resolution: + { + integrity: sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==, + } + engines: { node: ^10 || ^12 || >=14 } + + prelude-ls@1.2.1: + resolution: + { + integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==, + } + engines: { node: ">= 0.8.0" } + + prettier@3.8.3: + resolution: + { + integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==, + } + engines: { node: ">=14" } + hasBin: true + + prismjs@1.27.0: + resolution: + { + integrity: sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==, + } + engines: { node: ">=6" } + + prismjs@1.30.0: + resolution: + { + integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==, + } + engines: { node: ">=6" } + + prop-types@15.8.1: + resolution: + { + integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==, + } + + property-information@5.6.0: + resolution: + { + integrity: sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==, + } + + proxy-from-env@2.1.0: + resolution: + { + integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==, + } + engines: { node: ">=10" } + + punycode@2.3.1: + resolution: + { + integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==, + } + engines: { node: ">=6" } + + queue-microtask@1.2.3: + resolution: + { + integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==, + } + + react-copy-to-clipboard@5.1.1: + resolution: + { + integrity: sha512-s+HrzLyJBxrpGTYXF15dTgMjAJpEPZT/Yp6NytAtZMRngejxt6Pt5WrfFxLAcsqUDU6sY1Jz6tyHwIicE1U2Xg==, + } + peerDependencies: + react: ">=15.3.0" + + react-day-picker@8.10.1: + resolution: + { + integrity: sha512-TMx7fNbhLk15eqcMt+7Z7S2KF7mfTId/XJDjKE8f+IUcFn0l08/kI4FiYTL/0yuOLmEcbR4Fwe3GJf/NiiMnPA==, + } + peerDependencies: + date-fns: ^2.28.0 || ^3.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + + react-dom@19.2.5: + resolution: + { + integrity: sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==, + } + peerDependencies: + react: ^19.2.5 + + react-hook-form@7.72.1: + resolution: + { + integrity: sha512-RhwBoy2ygeVZje+C+bwJ8g0NjTdBmDlJvAUHTxRjTmSUKPYsKfMphkS2sgEMotsY03bP358yEYlnUeZy//D9Ig==, + } + engines: { node: ">=18.0.0" } + peerDependencies: + react: ^16.8.0 || ^17 || ^18 || ^19 + + react-is@16.13.1: + resolution: + { + integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==, + } + + react-is@18.3.1: + resolution: + { + integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==, + } + + react-redux@9.2.0: + resolution: + { + integrity: sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==, + } + peerDependencies: + "@types/react": ^18.2.25 || ^19 + react: ^18.0 || ^19 + redux: ^5.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + redux: + optional: true + + react-remove-scroll-bar@2.3.8: + resolution: + { + integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==, + } + engines: { node: ">=10" } + peerDependencies: + "@types/react": "*" + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + + react-remove-scroll@2.7.2: + resolution: + { + integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==, + } + engines: { node: ">=10" } + peerDependencies: + "@types/react": "*" + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + + react-smooth@4.0.4: + resolution: + { + integrity: sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==, + } + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + react-style-singleton@2.2.3: + resolution: + { + integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==, + } + engines: { node: ">=10" } + peerDependencies: + "@types/react": "*" + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + + react-syntax-highlighter@15.6.6: + resolution: + { + integrity: sha512-DgXrc+AZF47+HvAPEmn7Ua/1p10jNoVZVI/LoPiYdtY+OM+/nG5yefLHKJwdKqY1adMuHFbeyBaG9j64ML7vTw==, + } + peerDependencies: + react: ">= 0.14.0" + + react-transition-group@4.4.5: + resolution: + { + integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==, + } + peerDependencies: + react: ">=16.6.0" + react-dom: ">=16.6.0" + + react@19.2.5: + resolution: + { + integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==, + } + engines: { node: ">=0.10.0" } + + read-cache@1.0.0: + resolution: + { + integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==, + } + + readdirp@3.6.0: + resolution: + { + integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==, + } + engines: { node: ">=8.10.0" } + + recharts-scale@0.4.5: + resolution: + { + integrity: sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==, + } + + recharts@2.15.4: + resolution: + { + integrity: sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==, + } + engines: { node: ">=14" } + peerDependencies: + react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + redux-thunk@3.1.0: + resolution: + { + integrity: sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==, + } + peerDependencies: + redux: ^5.0.0 + + redux@5.0.1: + resolution: + { + integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==, + } + + reflect.getprototypeof@1.0.10: + resolution: + { + integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==, + } + engines: { node: ">= 0.4" } + + refractor@3.6.0: + resolution: + { + integrity: sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==, + } + + regexp.prototype.flags@1.5.4: + resolution: + { + integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==, + } + engines: { node: ">= 0.4" } + + reselect@5.1.1: + resolution: + { + integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==, + } + + resolve-from@4.0.0: + resolution: + { + integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==, + } + engines: { node: ">=4" } + + resolve-pkg-maps@1.0.0: + resolution: + { + integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==, + } + + resolve@1.22.12: + resolution: + { + integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==, + } + engines: { node: ">= 0.4" } + hasBin: true + + resolve@2.0.0-next.6: + resolution: + { + integrity: sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA==, + } + engines: { node: ">= 0.4" } + hasBin: true + + reusify@1.1.0: + resolution: + { + integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==, + } + engines: { iojs: ">=1.0.0", node: ">=0.10.0" } + + rimraf@3.0.2: + resolution: + { + integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==, + } + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + run-parallel@1.2.0: + resolution: + { + integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==, + } + + safe-array-concat@1.1.3: + resolution: + { + integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==, + } + engines: { node: ">=0.4" } + + safe-push-apply@1.0.0: + resolution: + { + integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==, + } + engines: { node: ">= 0.4" } + + safe-regex-test@1.1.0: + resolution: + { + integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==, + } + engines: { node: ">= 0.4" } + + scheduler@0.27.0: + resolution: + { + integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==, + } + + semver@6.3.1: + resolution: + { + integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==, + } + hasBin: true + + semver@7.7.4: + resolution: + { + integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==, + } + engines: { node: ">=10" } + hasBin: true + + set-function-length@1.2.2: + resolution: + { + integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==, + } + engines: { node: ">= 0.4" } + + set-function-name@2.0.2: + resolution: + { + integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==, + } + engines: { node: ">= 0.4" } + + set-proto@1.0.0: + resolution: + { + integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==, + } + engines: { node: ">= 0.4" } + + sharp@0.33.5: + resolution: + { + integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + + shebang-command@2.0.0: + resolution: + { + integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==, + } + engines: { node: ">=8" } + + shebang-regex@3.0.0: + resolution: + { + integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==, + } + engines: { node: ">=8" } + + side-channel-list@1.0.1: + resolution: + { + integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==, + } + engines: { node: ">= 0.4" } + + side-channel-map@1.0.1: + resolution: + { + integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==, + } + engines: { node: ">= 0.4" } + + side-channel-weakmap@1.0.2: + resolution: + { + integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==, + } + engines: { node: ">= 0.4" } + + side-channel@1.1.0: + resolution: + { + integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==, + } + engines: { node: ">= 0.4" } + + simple-swizzle@0.2.4: + resolution: + { + integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==, + } + + sonner@1.7.4: + resolution: + { + integrity: sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw==, + } + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + + source-map-js@1.2.1: + resolution: + { + integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==, + } + engines: { node: ">=0.10.0" } + + space-separated-tokens@1.1.5: + resolution: + { + integrity: sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==, + } + + stable-hash@0.0.5: + resolution: + { + integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==, + } + + stop-iteration-iterator@1.1.0: + resolution: + { + integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==, + } + engines: { node: ">= 0.4" } + + streamsearch@1.1.0: + resolution: + { + integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==, + } + engines: { node: ">=10.0.0" } + + string.prototype.includes@2.0.1: + resolution: + { + integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==, + } + engines: { node: ">= 0.4" } + + string.prototype.matchall@4.0.12: + resolution: + { + integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==, + } + engines: { node: ">= 0.4" } + + string.prototype.repeat@1.0.0: + resolution: + { + integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==, + } + + string.prototype.trim@1.2.10: + resolution: + { + integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==, + } + engines: { node: ">= 0.4" } + + string.prototype.trimend@1.0.9: + resolution: + { + integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==, + } + engines: { node: ">= 0.4" } + + string.prototype.trimstart@1.0.8: + resolution: + { + integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==, + } + engines: { node: ">= 0.4" } + + strip-ansi@6.0.1: + resolution: + { + integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==, + } + engines: { node: ">=8" } + + strip-bom@3.0.0: + resolution: + { + integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==, + } + engines: { node: ">=4" } + + strip-json-comments@3.1.1: + resolution: + { + integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==, + } + engines: { node: ">=8" } + + styled-jsx@5.1.6: + resolution: + { + integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==, + } + engines: { node: ">= 12.0.0" } + peerDependencies: + "@babel/core": "*" + babel-plugin-macros: "*" + 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 + + sucrase@3.35.1: + resolution: + { + integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==, + } + engines: { node: ">=16 || 14 >=14.17" } + hasBin: true + + supports-color@7.2.0: + resolution: + { + integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==, + } + engines: { node: ">=8" } + + supports-preserve-symlinks-flag@1.0.0: + resolution: + { + integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==, + } + engines: { node: ">= 0.4" } + + tailwind-merge@2.6.1: + resolution: + { + integrity: sha512-Oo6tHdpZsGpkKG88HJ8RR1rg/RdnEkQEfMoEk2x1XRI3F1AxeU+ijRXpiVUF4UbLfcxxRGw6TbUINKYdWVsQTQ==, + } + + tailwindcss-animate@1.0.7: + resolution: + { + integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==, + } + peerDependencies: + tailwindcss: ">=3.0.0 || insiders" + + tailwindcss@3.4.19: + resolution: + { + integrity: sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==, + } + engines: { node: ">=14.0.0" } + hasBin: true + + text-table@0.2.0: + resolution: + { + integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==, + } + + thenify-all@1.6.0: + resolution: + { + integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==, + } + engines: { node: ">=0.8" } + + thenify@3.3.1: + resolution: + { + integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==, + } + + tiny-invariant@1.3.3: + resolution: + { + integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==, + } + + tinyglobby@0.2.16: + resolution: + { + integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==, + } + engines: { node: ">=12.0.0" } + + to-regex-range@5.0.1: + resolution: + { + integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==, + } + engines: { node: ">=8.0" } + + toggle-selection@1.0.6: + resolution: + { + integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==, + } + + ts-api-utils@2.5.0: + resolution: + { + integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==, + } + engines: { node: ">=18.12" } + peerDependencies: + typescript: ">=4.8.4" + + ts-interface-checker@0.1.13: + resolution: + { + integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==, + } + + tsconfig-paths@3.15.0: + resolution: + { + integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==, + } + + tslib@2.8.1: + resolution: + { + integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==, + } + + type-check@0.4.0: + resolution: + { + integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==, + } + engines: { node: ">= 0.8.0" } + + type-fest@0.20.2: + resolution: + { + integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==, + } + engines: { node: ">=10" } + + typed-array-buffer@1.0.3: + resolution: + { + integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==, + } + engines: { node: ">= 0.4" } + + typed-array-byte-length@1.0.3: + resolution: + { + integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==, + } + engines: { node: ">= 0.4" } + + typed-array-byte-offset@1.0.4: + resolution: + { + integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==, + } + engines: { node: ">= 0.4" } + + typed-array-length@1.0.7: + resolution: + { + integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==, + } + engines: { node: ">= 0.4" } + + typescript@5.9.3: + resolution: + { + integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==, + } + engines: { node: ">=14.17" } + hasBin: true + + unbox-primitive@1.1.0: + resolution: + { + integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==, + } + engines: { node: ">= 0.4" } + + undici-types@6.19.8: + resolution: + { + integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==, + } + + unrs-resolver@1.11.1: + resolution: + { + integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==, + } + + update-browserslist-db@1.2.3: + resolution: + { + integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==, + } + hasBin: true + peerDependencies: + browserslist: ">= 4.21.0" + + uri-js@4.4.1: + resolution: + { + integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==, + } + + use-callback-ref@1.3.3: + resolution: + { + integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==, + } + engines: { node: ">=10" } + peerDependencies: + "@types/react": "*" + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + + use-debounce@10.1.1: + resolution: + { + integrity: sha512-kvds8BHR2k28cFsxW8k3nc/tRga2rs1RHYCqmmGqb90MEeE++oALwzh2COiuBLO1/QXiOuShXoSN2ZpWnMmvuQ==, + } + engines: { node: ">= 16.0.0" } + peerDependencies: + react: "*" + + use-sidecar@1.1.3: + resolution: + { + integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==, + } + engines: { node: ">=10" } + peerDependencies: + "@types/react": "*" + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + + use-sync-external-store@1.6.0: + resolution: + { + integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==, + } + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + util-deprecate@1.0.2: + resolution: + { + integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==, + } + + uuid@9.0.1: + resolution: + { + integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==, + } + hasBin: true + + vaul@0.9.9: + resolution: + { + integrity: sha512-7afKg48srluhZwIkaU+lgGtFCUsYBSGOl8vcc8N/M3YQlZFlynHD15AE+pwrYdc826o7nrIND4lL9Y6b9WWZZQ==, + } + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + + victory-vendor@36.9.2: + resolution: + { + integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==, + } + + which-boxed-primitive@1.1.1: + resolution: + { + integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==, + } + engines: { node: ">= 0.4" } + + which-builtin-type@1.2.1: + resolution: + { + integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==, + } + engines: { node: ">= 0.4" } + + which-collection@1.0.2: + resolution: + { + integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==, + } + engines: { node: ">= 0.4" } + + which-typed-array@1.1.20: + resolution: + { + integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==, + } + engines: { node: ">= 0.4" } + + which@2.0.2: + resolution: + { + integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==, + } + engines: { node: ">= 8" } + hasBin: true + + word-wrap@1.2.5: + resolution: + { + integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==, + } + engines: { node: ">=0.10.0" } + + wrappy@1.0.2: + resolution: + { + integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==, + } + + xtend@4.0.2: + resolution: + { + integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==, + } + engines: { node: ">=0.4" } + + yocto-queue@0.1.0: + resolution: + { + integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==, + } + engines: { node: ">=10" } + + zod@3.25.76: + resolution: + { + integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==, + } + +snapshots: + "@alloc/quick-lru@5.2.0": {} + + "@babel/runtime@7.29.2": {} + + "@emnapi/core@1.9.2": + dependencies: + "@emnapi/wasi-threads": 1.2.1 + tslib: 2.8.1 + optional: true + + "@emnapi/runtime@1.9.2": + dependencies: + tslib: 2.8.1 + optional: true + + "@emnapi/wasi-threads@1.2.1": + dependencies: + tslib: 2.8.1 + optional: true + + "@eslint-community/eslint-utils@4.9.1(eslint@8.57.1)": + dependencies: + eslint: 8.57.1 + eslint-visitor-keys: 3.4.3 + + "@eslint-community/regexpp@4.12.2": {} + + "@eslint/eslintrc@2.1.4": + dependencies: + ajv: 6.14.0 + debug: 4.4.3 + espree: 9.6.1 + globals: 13.24.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + minimatch: 3.1.5 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + "@eslint/js@8.57.1": {} + + "@floating-ui/core@1.7.5": + dependencies: + "@floating-ui/utils": 0.2.11 + + "@floating-ui/dom@1.7.6": + dependencies: + "@floating-ui/core": 1.7.5 + "@floating-ui/utils": 0.2.11 + + "@floating-ui/react-dom@2.1.8(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@floating-ui/dom": 1.7.6 + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + + "@floating-ui/utils@0.2.11": {} + + "@hookform/resolvers@3.10.0(react-hook-form@7.72.1(react@19.2.5))": + dependencies: + react-hook-form: 7.72.1(react@19.2.5) + + "@humanwhocodes/config-array@0.13.0": + dependencies: + "@humanwhocodes/object-schema": 2.0.3 + debug: 4.4.3 + minimatch: 3.1.5 + transitivePeerDependencies: + - supports-color + + "@humanwhocodes/module-importer@1.0.1": {} + + "@humanwhocodes/object-schema@2.0.3": {} + + "@img/sharp-darwin-arm64@0.33.5": + optionalDependencies: + "@img/sharp-libvips-darwin-arm64": 1.0.4 + optional: true + + "@img/sharp-darwin-x64@0.33.5": + optionalDependencies: + "@img/sharp-libvips-darwin-x64": 1.0.4 + optional: true + + "@img/sharp-libvips-darwin-arm64@1.0.4": + optional: true + + "@img/sharp-libvips-darwin-x64@1.0.4": + optional: true + + "@img/sharp-libvips-linux-arm64@1.0.4": + optional: true + + "@img/sharp-libvips-linux-arm@1.0.5": + optional: true + + "@img/sharp-libvips-linux-s390x@1.0.4": + optional: true + + "@img/sharp-libvips-linux-x64@1.0.4": + optional: true + + "@img/sharp-libvips-linuxmusl-arm64@1.0.4": + optional: true + + "@img/sharp-libvips-linuxmusl-x64@1.0.4": + optional: true + + "@img/sharp-linux-arm64@0.33.5": + optionalDependencies: + "@img/sharp-libvips-linux-arm64": 1.0.4 + optional: true + + "@img/sharp-linux-arm@0.33.5": + optionalDependencies: + "@img/sharp-libvips-linux-arm": 1.0.5 + optional: true + + "@img/sharp-linux-s390x@0.33.5": + optionalDependencies: + "@img/sharp-libvips-linux-s390x": 1.0.4 + optional: true + + "@img/sharp-linux-x64@0.33.5": + optionalDependencies: + "@img/sharp-libvips-linux-x64": 1.0.4 + optional: true + + "@img/sharp-linuxmusl-arm64@0.33.5": + optionalDependencies: + "@img/sharp-libvips-linuxmusl-arm64": 1.0.4 + optional: true + + "@img/sharp-linuxmusl-x64@0.33.5": + optionalDependencies: + "@img/sharp-libvips-linuxmusl-x64": 1.0.4 + optional: true + + "@img/sharp-wasm32@0.33.5": + dependencies: + "@emnapi/runtime": 1.9.2 + optional: true + + "@img/sharp-win32-ia32@0.33.5": + optional: true + + "@img/sharp-win32-x64@0.33.5": + optional: true + + "@jridgewell/gen-mapping@0.3.13": + dependencies: + "@jridgewell/sourcemap-codec": 1.5.5 + "@jridgewell/trace-mapping": 0.3.31 + + "@jridgewell/resolve-uri@3.1.2": {} + + "@jridgewell/sourcemap-codec@1.5.5": {} + + "@jridgewell/trace-mapping@0.3.31": + dependencies: + "@jridgewell/resolve-uri": 3.1.2 + "@jridgewell/sourcemap-codec": 1.5.5 + + "@napi-rs/wasm-runtime@0.2.12": + dependencies: + "@emnapi/core": 1.9.2 + "@emnapi/runtime": 1.9.2 + "@tybys/wasm-util": 0.10.1 + optional: true + + "@next/env@15.2.6": {} + + "@next/eslint-plugin-next@15.2.6": + dependencies: + fast-glob: 3.3.1 + + "@next/swc-darwin-arm64@15.2.5": + optional: true + + "@next/swc-darwin-x64@15.2.5": + optional: true + + "@next/swc-linux-arm64-gnu@15.2.5": + optional: true + + "@next/swc-linux-arm64-musl@15.2.5": + optional: true + + "@next/swc-linux-x64-gnu@15.2.5": + optional: true + + "@next/swc-linux-x64-musl@15.2.5": + optional: true + + "@next/swc-win32-arm64-msvc@15.2.5": + optional: true + + "@next/swc-win32-x64-msvc@15.2.5": + optional: true + + "@nodelib/fs.scandir@2.1.5": + dependencies: + "@nodelib/fs.stat": 2.0.5 + run-parallel: 1.2.0 + + "@nodelib/fs.stat@2.0.5": {} + + "@nodelib/fs.walk@1.2.8": + dependencies: + "@nodelib/fs.scandir": 2.1.5 + fastq: 1.20.1 + + "@nolyfill/is-core-module@1.0.39": {} + + "@radix-ui/number@1.1.1": {} + + "@radix-ui/primitive@1.1.3": {} + + "@radix-ui/react-accordion@1.2.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/primitive": 1.1.3 + "@radix-ui/react-collapsible": 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-collection": 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-compose-refs": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-context": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-direction": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-id": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-primitive": 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-use-controllable-state": 1.2.2(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-alert-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/primitive": 1.1.3 + "@radix-ui/react-compose-refs": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-context": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-dialog": 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-primitive": 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-slot": 1.2.3(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/react-primitive": 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-avatar@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/react-context": 1.1.3(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-primitive": 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-use-callback-ref": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-is-hydrated": 0.1.0(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-layout-effect": 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-checkbox@1.3.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/primitive": 1.1.3 + "@radix-ui/react-compose-refs": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-context": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-presence": 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-primitive": 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-use-controllable-state": 1.2.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-previous": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-size": 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-collapsible@1.1.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/primitive": 1.1.3 + "@radix-ui/react-compose-refs": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-context": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-id": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-presence": 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-primitive": 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-use-controllable-state": 1.2.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-layout-effect": 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/react-compose-refs": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-context": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-primitive": 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-slot": 1.2.3(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.14)(react@19.2.5)": + dependencies: + react: 19.2.5 + optionalDependencies: + "@types/react": 19.2.14 + + "@radix-ui/react-context@1.1.2(@types/react@19.2.14)(react@19.2.5)": + dependencies: + react: 19.2.5 + optionalDependencies: + "@types/react": 19.2.14 + + "@radix-ui/react-context@1.1.3(@types/react@19.2.14)(react@19.2.5)": + dependencies: + react: 19.2.5 + optionalDependencies: + "@types/react": 19.2.14 + + "@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/primitive": 1.1.3 + "@radix-ui/react-compose-refs": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-context": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-dismissable-layer": 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-focus-guards": 1.1.3(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-focus-scope": 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-id": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-portal": 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-presence": 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-primitive": 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-slot": 1.2.3(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-controllable-state": 1.2.2(@types/react@19.2.14)(react@19.2.5) + aria-hidden: 1.2.6 + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-direction@1.1.1(@types/react@19.2.14)(react@19.2.5)": + dependencies: + react: 19.2.5 + optionalDependencies: + "@types/react": 19.2.14 + + "@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/primitive": 1.1.3 + "@radix-ui/react-compose-refs": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-primitive": 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-use-callback-ref": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-escape-keydown": 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/primitive": 1.1.3 + "@radix-ui/react-compose-refs": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-context": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-id": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-menu": 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-primitive": 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-use-controllable-state": 1.2.2(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.14)(react@19.2.5)": + dependencies: + react: 19.2.5 + optionalDependencies: + "@types/react": 19.2.14 + + "@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/react-compose-refs": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-primitive": 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-use-callback-ref": 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-hover-card@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/primitive": 1.1.3 + "@radix-ui/react-compose-refs": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-context": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-dismissable-layer": 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-popper": 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-portal": 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-presence": 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-primitive": 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-use-controllable-state": 1.2.2(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-icons@1.3.2(react@19.2.5)": + dependencies: + react: 19.2.5 + + "@radix-ui/react-id@1.1.1(@types/react@19.2.14)(react@19.2.5)": + dependencies: + "@radix-ui/react-use-layout-effect": 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + optionalDependencies: + "@types/react": 19.2.14 + + "@radix-ui/react-label@2.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/react-primitive": 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/primitive": 1.1.3 + "@radix-ui/react-collection": 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-compose-refs": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-context": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-direction": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-dismissable-layer": 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-focus-guards": 1.1.3(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-focus-scope": 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-id": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-popper": 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-portal": 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-presence": 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-primitive": 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-roving-focus": 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-slot": 1.2.3(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-callback-ref": 1.1.1(@types/react@19.2.14)(react@19.2.5) + aria-hidden: 1.2.6 + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/primitive": 1.1.3 + "@radix-ui/react-compose-refs": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-context": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-dismissable-layer": 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-focus-guards": 1.1.3(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-focus-scope": 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-id": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-popper": 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-portal": 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-presence": 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-primitive": 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-slot": 1.2.3(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-controllable-state": 1.2.2(@types/react@19.2.14)(react@19.2.5) + aria-hidden: 1.2.6 + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@floating-ui/react-dom": 2.1.8(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-arrow": 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-compose-refs": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-context": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-primitive": 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-use-callback-ref": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-layout-effect": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-rect": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-size": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/rect": 1.1.1 + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/react-primitive": 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-use-layout-effect": 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/react-compose-refs": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-layout-effect": 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/react-slot": 1.2.3(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-primitive@2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/react-slot": 1.2.4(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-progress@1.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/react-context": 1.1.3(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-primitive": 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-radio-group@1.3.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/primitive": 1.1.3 + "@radix-ui/react-compose-refs": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-context": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-direction": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-presence": 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-primitive": 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-roving-focus": 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-use-controllable-state": 1.2.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-previous": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-size": 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/primitive": 1.1.3 + "@radix-ui/react-collection": 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-compose-refs": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-context": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-direction": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-id": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-primitive": 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-use-callback-ref": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-controllable-state": 1.2.2(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-scroll-area@1.2.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/number": 1.1.1 + "@radix-ui/primitive": 1.1.3 + "@radix-ui/react-compose-refs": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-context": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-direction": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-presence": 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-primitive": 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-use-callback-ref": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-layout-effect": 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-select@2.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/number": 1.1.1 + "@radix-ui/primitive": 1.1.3 + "@radix-ui/react-collection": 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-compose-refs": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-context": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-direction": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-dismissable-layer": 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-focus-guards": 1.1.3(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-focus-scope": 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-id": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-popper": 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-portal": 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-primitive": 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-slot": 1.2.3(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-callback-ref": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-controllable-state": 1.2.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-layout-effect": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-previous": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-visually-hidden": 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + aria-hidden: 1.2.6 + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-separator@1.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/react-primitive": 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-slider@1.3.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/number": 1.1.1 + "@radix-ui/primitive": 1.1.3 + "@radix-ui/react-collection": 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-compose-refs": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-context": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-direction": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-primitive": 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-use-controllable-state": 1.2.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-layout-effect": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-previous": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-size": 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-slot@1.2.3(@types/react@19.2.14)(react@19.2.5)": + dependencies: + "@radix-ui/react-compose-refs": 1.1.2(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + optionalDependencies: + "@types/react": 19.2.14 + + "@radix-ui/react-slot@1.2.4(@types/react@19.2.14)(react@19.2.5)": + dependencies: + "@radix-ui/react-compose-refs": 1.1.2(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + optionalDependencies: + "@types/react": 19.2.14 + + "@radix-ui/react-switch@1.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/primitive": 1.1.3 + "@radix-ui/react-compose-refs": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-context": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-primitive": 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-use-controllable-state": 1.2.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-previous": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-size": 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/primitive": 1.1.3 + "@radix-ui/react-context": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-direction": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-id": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-presence": 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-primitive": 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-roving-focus": 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-use-controllable-state": 1.2.2(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-toast@1.2.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/primitive": 1.1.3 + "@radix-ui/react-collection": 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-compose-refs": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-context": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-dismissable-layer": 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-portal": 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-presence": 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-primitive": 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-use-callback-ref": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-controllable-state": 1.2.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-layout-effect": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-visually-hidden": 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/primitive": 1.1.3 + "@radix-ui/react-compose-refs": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-context": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-dismissable-layer": 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-id": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-popper": 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-portal": 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-presence": 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-primitive": 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-slot": 1.2.3(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-controllable-state": 1.2.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-visually-hidden": 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.14)(react@19.2.5)": + dependencies: + react: 19.2.5 + optionalDependencies: + "@types/react": 19.2.14 + + "@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.14)(react@19.2.5)": + dependencies: + "@radix-ui/react-use-effect-event": 0.0.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-use-layout-effect": 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + optionalDependencies: + "@types/react": 19.2.14 + + "@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.14)(react@19.2.5)": + dependencies: + "@radix-ui/react-use-layout-effect": 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + optionalDependencies: + "@types/react": 19.2.14 + + "@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.14)(react@19.2.5)": + dependencies: + "@radix-ui/react-use-callback-ref": 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + optionalDependencies: + "@types/react": 19.2.14 + + "@radix-ui/react-use-is-hydrated@0.1.0(@types/react@19.2.14)(react@19.2.5)": + dependencies: + react: 19.2.5 + use-sync-external-store: 1.6.0(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + + "@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.14)(react@19.2.5)": + dependencies: + react: 19.2.5 + optionalDependencies: + "@types/react": 19.2.14 + + "@radix-ui/react-use-previous@1.1.1(@types/react@19.2.14)(react@19.2.5)": + dependencies: + react: 19.2.5 + optionalDependencies: + "@types/react": 19.2.14 + + "@radix-ui/react-use-rect@1.1.1(@types/react@19.2.14)(react@19.2.5)": + dependencies: + "@radix-ui/rect": 1.1.1 + react: 19.2.5 + optionalDependencies: + "@types/react": 19.2.14 + + "@radix-ui/react-use-size@1.1.1(@types/react@19.2.14)(react@19.2.5)": + dependencies: + "@radix-ui/react-use-layout-effect": 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + optionalDependencies: + "@types/react": 19.2.14 + + "@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@radix-ui/react-primitive": 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3(@types/react@19.2.14) + + "@radix-ui/rect@1.1.1": {} + + "@reduxjs/toolkit@2.11.2(react-redux@9.2.0(@types/react@19.2.14)(react@19.2.5)(redux@5.0.1))(react@19.2.5)": + dependencies: + "@standard-schema/spec": 1.1.0 + "@standard-schema/utils": 0.3.0 + immer: 11.1.4 + redux: 5.0.1 + redux-thunk: 3.1.0(redux@5.0.1) + reselect: 5.1.1 + optionalDependencies: + react: 19.2.5 + react-redux: 9.2.0(@types/react@19.2.14)(react@19.2.5)(redux@5.0.1) + + "@rtsao/scc@1.1.0": {} + + "@rushstack/eslint-patch@1.16.1": {} + + "@standard-schema/spec@1.1.0": {} + + "@standard-schema/utils@0.3.0": {} + + "@swc/counter@0.1.3": {} + + "@swc/helpers@0.5.15": + dependencies: + tslib: 2.8.1 + + "@tailwindcss/typography@0.5.19(tailwindcss@3.4.19)": + dependencies: + postcss-selector-parser: 6.0.10 + tailwindcss: 3.4.19 + + "@tanstack/react-table@8.21.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5)": + dependencies: + "@tanstack/table-core": 8.21.3 + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + + "@tanstack/table-core@8.21.3": {} + + "@tybys/wasm-util@0.10.1": + dependencies: + tslib: 2.8.1 + optional: true + + "@types/d3-array@3.2.2": {} + + "@types/d3-color@3.1.3": {} + + "@types/d3-ease@3.0.2": {} + + "@types/d3-interpolate@3.0.4": + dependencies: + "@types/d3-color": 3.1.3 + + "@types/d3-path@3.1.1": {} + + "@types/d3-scale@4.0.9": + dependencies: + "@types/d3-time": 3.0.4 + + "@types/d3-shape@3.1.8": + dependencies: + "@types/d3-path": 3.1.1 + + "@types/d3-time@3.0.4": {} + + "@types/d3-timer@3.0.2": {} + + "@types/hast@2.3.10": + dependencies: + "@types/unist": 2.0.11 + + "@types/json5@0.0.29": {} + + "@types/lodash@4.17.24": {} + + "@types/node@22.5.4": + dependencies: + undici-types: 6.19.8 + + "@types/react-copy-to-clipboard@5.0.7": + dependencies: + "@types/react": 19.2.14 + + "@types/react-dom@19.2.3(@types/react@19.2.14)": + dependencies: + "@types/react": 19.2.14 + + "@types/react-syntax-highlighter@15.5.13": + dependencies: + "@types/react": 19.2.14 + + "@types/react@19.2.14": + dependencies: + csstype: 3.2.3 + + "@types/unist@2.0.11": {} + + "@types/use-sync-external-store@0.0.6": {} + + "@types/uuid@9.0.8": {} + + "@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3)": + dependencies: + "@eslint-community/regexpp": 4.12.2 + "@typescript-eslint/parser": 8.58.2(eslint@8.57.1)(typescript@5.9.3) + "@typescript-eslint/scope-manager": 8.58.2 + "@typescript-eslint/type-utils": 8.58.2(eslint@8.57.1)(typescript@5.9.3) + "@typescript-eslint/utils": 8.58.2(eslint@8.57.1)(typescript@5.9.3) + "@typescript-eslint/visitor-keys": 8.58.2 + eslint: 8.57.1 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + "@typescript-eslint/parser@8.58.2(eslint@8.57.1)(typescript@5.9.3)": + dependencies: + "@typescript-eslint/scope-manager": 8.58.2 + "@typescript-eslint/types": 8.58.2 + "@typescript-eslint/typescript-estree": 8.58.2(typescript@5.9.3) + "@typescript-eslint/visitor-keys": 8.58.2 + debug: 4.4.3 + eslint: 8.57.1 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + "@typescript-eslint/project-service@8.58.2(typescript@5.9.3)": + dependencies: + "@typescript-eslint/tsconfig-utils": 8.58.2(typescript@5.9.3) + "@typescript-eslint/types": 8.58.2 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + "@typescript-eslint/scope-manager@8.58.2": + dependencies: + "@typescript-eslint/types": 8.58.2 + "@typescript-eslint/visitor-keys": 8.58.2 + + "@typescript-eslint/tsconfig-utils@8.58.2(typescript@5.9.3)": + dependencies: + typescript: 5.9.3 + + "@typescript-eslint/type-utils@8.58.2(eslint@8.57.1)(typescript@5.9.3)": + dependencies: + "@typescript-eslint/types": 8.58.2 + "@typescript-eslint/typescript-estree": 8.58.2(typescript@5.9.3) + "@typescript-eslint/utils": 8.58.2(eslint@8.57.1)(typescript@5.9.3) + debug: 4.4.3 + eslint: 8.57.1 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + "@typescript-eslint/types@8.58.2": {} + + "@typescript-eslint/typescript-estree@8.58.2(typescript@5.9.3)": + dependencies: + "@typescript-eslint/project-service": 8.58.2(typescript@5.9.3) + "@typescript-eslint/tsconfig-utils": 8.58.2(typescript@5.9.3) + "@typescript-eslint/types": 8.58.2 + "@typescript-eslint/visitor-keys": 8.58.2 + debug: 4.4.3 + minimatch: 10.2.5 + semver: 7.7.4 + tinyglobby: 0.2.16 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + "@typescript-eslint/utils@8.58.2(eslint@8.57.1)(typescript@5.9.3)": + dependencies: + "@eslint-community/eslint-utils": 4.9.1(eslint@8.57.1) + "@typescript-eslint/scope-manager": 8.58.2 + "@typescript-eslint/types": 8.58.2 + "@typescript-eslint/typescript-estree": 8.58.2(typescript@5.9.3) + eslint: 8.57.1 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + "@typescript-eslint/visitor-keys@8.58.2": + dependencies: + "@typescript-eslint/types": 8.58.2 + eslint-visitor-keys: 5.0.1 + + "@ungap/structured-clone@1.3.0": {} + + "@unrs/resolver-binding-android-arm-eabi@1.11.1": + optional: true + + "@unrs/resolver-binding-android-arm64@1.11.1": + optional: true + + "@unrs/resolver-binding-darwin-arm64@1.11.1": + optional: true + + "@unrs/resolver-binding-darwin-x64@1.11.1": + optional: true + + "@unrs/resolver-binding-freebsd-x64@1.11.1": + optional: true + + "@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1": + optional: true + + "@unrs/resolver-binding-linux-arm-musleabihf@1.11.1": + optional: true + + "@unrs/resolver-binding-linux-arm64-gnu@1.11.1": + optional: true + + "@unrs/resolver-binding-linux-arm64-musl@1.11.1": + optional: true + + "@unrs/resolver-binding-linux-ppc64-gnu@1.11.1": + optional: true + + "@unrs/resolver-binding-linux-riscv64-gnu@1.11.1": + optional: true + + "@unrs/resolver-binding-linux-riscv64-musl@1.11.1": + optional: true + + "@unrs/resolver-binding-linux-s390x-gnu@1.11.1": + optional: true + + "@unrs/resolver-binding-linux-x64-gnu@1.11.1": + optional: true + + "@unrs/resolver-binding-linux-x64-musl@1.11.1": + optional: true + + "@unrs/resolver-binding-wasm32-wasi@1.11.1": + dependencies: + "@napi-rs/wasm-runtime": 0.2.12 + optional: true + + "@unrs/resolver-binding-win32-arm64-msvc@1.11.1": + optional: true + + "@unrs/resolver-binding-win32-ia32-msvc@1.11.1": + optional: true + + "@unrs/resolver-binding-win32-x64-msvc@1.11.1": + optional: true + + acorn-jsx@5.3.2(acorn@8.16.0): + dependencies: + acorn: 8.16.0 + + acorn@8.16.0: {} + + ajv@6.14.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-regex@5.0.1: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + any-promise@1.3.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.2 + + arg@5.0.2: {} + + argparse@2.0.1: {} + + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + + aria-query@5.3.2: {} + + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 + + array-includes@3.1.9: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + is-string: 1.1.1 + math-intrinsics: 1.1.0 + + array.prototype.findlast@1.2.5: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + + array.prototype.findlastindex@1.2.6: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + + array.prototype.flat@1.3.3: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-shim-unscopables: 1.1.0 + + array.prototype.flatmap@1.3.3: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-shim-unscopables: 1.1.0 + + array.prototype.tosorted@1.1.4: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-shim-unscopables: 1.1.0 + + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 + + ast-types-flow@0.0.8: {} + + async-function@1.0.0: {} + + asynckit@0.4.0: {} + + autoprefixer@10.5.0(postcss@8.5.10): + dependencies: + browserslist: 4.28.2 + caniuse-lite: 1.0.30001788 + fraction.js: 5.3.4 + picocolors: 1.1.1 + postcss: 8.5.10 + postcss-value-parser: 4.2.0 + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + + axe-core@4.11.3: {} + + axios@1.15.0: + dependencies: + follow-redirects: 1.16.0 + form-data: 4.0.5 + proxy-from-env: 2.1.0 + transitivePeerDependencies: + - debug + + axobject-query@4.1.0: {} + + balanced-match@1.0.2: {} + + balanced-match@4.0.4: {} + + baseline-browser-mapping@2.10.19: {} + + binary-extensions@2.3.0: {} + + brace-expansion@1.1.14: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@5.0.5: + dependencies: + balanced-match: 4.0.4 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.28.2: + dependencies: + baseline-browser-mapping: 2.10.19 + caniuse-lite: 1.0.30001788 + electron-to-chromium: 1.5.337 + node-releases: 2.0.37 + update-browserslist-db: 1.2.3(browserslist@4.28.2) + + busboy@1.6.0: + dependencies: + streamsearch: 1.1.0 + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.9: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + camelcase-css@2.0.1: {} + + caniuse-lite@1.0.30001788: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + character-entities-legacy@1.1.4: {} + + character-entities@1.2.4: {} + + character-reference-invalid@1.1.4: {} + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + + client-only@0.0.1: {} + + clsx@2.1.1: {} + + cmdk@1.1.1(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5): + dependencies: + "@radix-ui/react-compose-refs": 1.1.2(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-dialog": 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + "@radix-ui/react-id": 1.1.1(@types/react@19.2.14)(react@19.2.5) + "@radix-ui/react-primitive": 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + transitivePeerDependencies: + - "@types/react" + - "@types/react-dom" + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + color-string@1.9.1: + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.4 + optional: true + + color@4.2.3: + dependencies: + color-convert: 2.0.1 + color-string: 1.9.1 + optional: true + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + comma-separated-tokens@1.0.8: {} + + commander@4.1.1: {} + + concat-map@0.0.1: {} + + copy-to-clipboard@3.3.3: + dependencies: + toggle-selection: 1.0.6 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + cssesc@3.0.0: {} + + csstype@3.2.3: {} + + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-color@3.1.0: {} + + d3-ease@3.0.1: {} + + d3-format@3.1.2: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-path@3.1.0: {} + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.2 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + + damerau-levenshtein@1.0.8: {} + + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + date-fns@4.1.0: {} + + debug@3.2.7: + dependencies: + ms: 2.1.3 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decimal.js-light@2.5.1: {} + + deep-is@0.1.4: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + delayed-stream@1.0.0: {} + + detect-libc@2.1.2: + optional: true + + detect-node-es@1.1.0: {} + + didyoumean@1.2.2: {} + + dlv@1.1.3: {} + + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 + + doctrine@3.0.0: + dependencies: + esutils: 2.0.3 + + dom-helpers@5.2.1: + dependencies: + "@babel/runtime": 7.29.2 + csstype: 3.2.3 + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + electron-to-chromium@1.5.337: {} + + emoji-regex@9.2.2: {} + + es-abstract@1.24.2: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.9 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-negative-zero: 2.0.3 + is-regex: 1.2.1 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.20 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-iterator-helpers@1.3.2: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-set-tostringtag: 2.1.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + iterator.prototype: 1.1.5 + math-intrinsics: 1.1.0 + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-shim-unscopables@1.1.0: + dependencies: + hasown: 2.0.2 + + es-to-primitive@1.3.0: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + + escalade@3.2.0: {} + + escape-string-regexp@4.0.0: {} + + eslint-config-next@15.2.6(eslint@8.57.1)(typescript@5.9.3): + dependencies: + "@next/eslint-plugin-next": 15.2.6 + "@rushstack/eslint-patch": 1.16.1 + "@typescript-eslint/eslint-plugin": 8.58.2(@typescript-eslint/parser@8.58.2(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3) + "@typescript-eslint/parser": 8.58.2(eslint@8.57.1)(typescript@5.9.3) + eslint: 8.57.1 + eslint-import-resolver-node: 0.3.10 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.58.2(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) + eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) + eslint-plugin-react: 7.37.5(eslint@8.57.1) + eslint-plugin-react-hooks: 5.2.0(eslint@8.57.1) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - eslint-import-resolver-webpack + - eslint-plugin-import-x + - supports-color + + eslint-import-resolver-node@0.3.10: + dependencies: + debug: 3.2.7 + is-core-module: 2.16.1 + resolve: 2.0.0-next.6 + transitivePeerDependencies: + - supports-color + + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1): + dependencies: + "@nolyfill/is-core-module": 1.0.39 + debug: 4.4.3 + eslint: 8.57.1 + get-tsconfig: 4.14.0 + is-bun-module: 2.0.0 + stable-hash: 0.0.5 + tinyglobby: 0.2.16 + unrs-resolver: 1.11.1 + optionalDependencies: + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.58.2(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.58.2(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1): + dependencies: + debug: 3.2.7 + optionalDependencies: + "@typescript-eslint/parser": 8.58.2(eslint@8.57.1)(typescript@5.9.3) + eslint: 8.57.1 + eslint-import-resolver-node: 0.3.10 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1) + transitivePeerDependencies: + - supports-color + + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.58.2(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1): + dependencies: + "@rtsao/scc": 1.1.0 + array-includes: 3.1.9 + array.prototype.findlastindex: 1.2.6 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 8.57.1 + eslint-import-resolver-node: 0.3.10 + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.58.2(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) + hasown: 2.0.2 + is-core-module: 2.16.1 + is-glob: 4.0.3 + minimatch: 3.1.5 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.1 + semver: 6.3.1 + string.prototype.trimend: 1.0.9 + tsconfig-paths: 3.15.0 + optionalDependencies: + "@typescript-eslint/parser": 8.58.2(eslint@8.57.1)(typescript@5.9.3) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-plugin-jsx-a11y@6.10.2(eslint@8.57.1): + dependencies: + aria-query: 5.3.2 + array-includes: 3.1.9 + array.prototype.flatmap: 1.3.3 + ast-types-flow: 0.0.8 + axe-core: 4.11.3 + axobject-query: 4.1.0 + damerau-levenshtein: 1.0.8 + emoji-regex: 9.2.2 + eslint: 8.57.1 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + language-tags: 1.0.9 + minimatch: 3.1.5 + object.fromentries: 2.0.8 + safe-regex-test: 1.1.0 + string.prototype.includes: 2.0.1 + + eslint-plugin-react-hooks@5.2.0(eslint@8.57.1): + dependencies: + eslint: 8.57.1 + + eslint-plugin-react@7.37.5(eslint@8.57.1): + dependencies: + array-includes: 3.1.9 + array.prototype.findlast: 1.2.5 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.3.2 + eslint: 8.57.1 + estraverse: 5.3.0 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.5 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.values: 1.2.1 + prop-types: 15.8.1 + resolve: 2.0.0-next.6 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + string.prototype.repeat: 1.0.0 + + eslint-scope@7.2.2: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@5.0.1: {} + + eslint@8.57.1: + dependencies: + "@eslint-community/eslint-utils": 4.9.1(eslint@8.57.1) + "@eslint-community/regexpp": 4.12.2 + "@eslint/eslintrc": 2.1.4 + "@eslint/js": 8.57.1 + "@humanwhocodes/config-array": 0.13.0 + "@humanwhocodes/module-importer": 1.0.1 + "@nodelib/fs.walk": 1.2.8 + "@ungap/structured-clone": 1.3.0 + ajv: 6.14.0 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.24.0 + graphemer: 1.4.0 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.1 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.5 + natural-compare: 1.4.0 + optionator: 0.9.4 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + + espree@9.6.1: + dependencies: + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) + eslint-visitor-keys: 3.4.3 + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + esutils@2.0.3: {} + + eventemitter3@4.0.7: {} + + fast-deep-equal@3.1.3: {} + + fast-equals@5.4.0: {} + + fast-glob@3.3.1: + dependencies: + "@nodelib/fs.stat": 2.0.5 + "@nodelib/fs.walk": 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-glob@3.3.3: + dependencies: + "@nodelib/fs.stat": 2.0.5 + "@nodelib/fs.walk": 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + + fault@1.0.4: + dependencies: + format: 0.2.2 + + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + + file-entry-cache@6.0.1: + dependencies: + flat-cache: 3.2.0 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@3.2.0: + dependencies: + flatted: 3.4.2 + keyv: 4.5.4 + rimraf: 3.0.2 + + flatted@3.4.2: {} + + follow-redirects@1.16.0: {} + + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + + format@0.2.2: {} + + fraction.js@5.3.4: {} + + framer-motion@12.38.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5): + dependencies: + motion-dom: 12.38.0 + motion-utils: 12.36.0 + tslib: 2.8.1 + optionalDependencies: + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + function.prototype.name@1.1.8: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + functions-have-names: 1.2.3 + hasown: 2.0.2 + is-callable: 1.2.7 + + functions-have-names@1.2.3: {} + + generator-function@2.0.1: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-nonce@1.0.1: {} + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + + get-tsconfig@4.14.0: + dependencies: + resolve-pkg-maps: 1.0.0 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.5 + once: 1.4.0 + path-is-absolute: 1.0.1 + + globals@13.24.0: + dependencies: + type-fest: 0.20.2 + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + + gopd@1.2.0: {} + + graphemer@1.4.0: {} + + has-bigints@1.1.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + hast-util-parse-selector@2.2.5: {} + + hastscript@6.0.0: + dependencies: + "@types/hast": 2.3.10 + comma-separated-tokens: 1.0.8 + hast-util-parse-selector: 2.2.5 + property-information: 5.6.0 + space-separated-tokens: 1.1.5 + + highlight.js@10.7.3: {} + + highlightjs-vue@1.0.0: {} + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + immer@11.1.4: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.1.0 + + internmap@2.0.3: {} + + is-alphabetical@1.0.4: {} + + is-alphanumerical@1.0.4: + dependencies: + is-alphabetical: 1.0.4 + is-decimal: 1.0.4 + + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-arrayish@0.3.4: + optional: true + + is-async-function@2.1.1: + dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-bigint@1.1.0: + dependencies: + has-bigints: 1.1.0 + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-boolean-object@1.2.2: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-bun-module@2.0.0: + dependencies: + semver: 7.7.4 + + is-callable@1.2.7: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-decimal@1.0.4: {} + + is-extglob@2.1.1: {} + + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-generator-function@1.1.2: + dependencies: + call-bound: 1.0.4 + generator-function: 2.0.1 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-hexadecimal@1.0.4: {} + + is-map@2.0.3: {} + + is-negative-zero@2.0.3: {} + + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-path-inside@3.0.3: {} + + is-regex@1.2.1: + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.4 + + is-string@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.20 + + is-weakmap@2.0.2: {} + + is-weakref@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + iterator.prototype@1.1.5: + dependencies: + define-data-property: 1.1.4 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + has-symbols: 1.1.0 + set-function-name: 2.0.2 + + jiti@1.21.7: {} + + js-tokens@4.0.0: {} + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@1.0.2: + dependencies: + minimist: 1.2.8 + + jsx-ast-utils@3.3.5: + dependencies: + array-includes: 3.1.9 + array.prototype.flat: 1.3.3 + object.assign: 4.1.7 + object.values: 1.2.1 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + language-subtag-registry@0.3.23: {} + + language-tags@1.0.9: + dependencies: + language-subtag-registry: 0.3.23 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lilconfig@3.1.3: {} + + lines-and-columns@1.2.4: {} + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + lodash@4.18.1: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lowlight@1.20.0: + dependencies: + fault: 1.0.4 + highlight.js: 10.7.3 + + lucide-react@0.542.0(react@19.2.5): + dependencies: + react: 19.2.5 + + math-intrinsics@1.1.0: {} + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.2 + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + minimatch@10.2.5: + dependencies: + brace-expansion: 5.0.5 + + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.14 + + minimist@1.2.8: {} + + motion-dom@12.38.0: + dependencies: + motion-utils: 12.36.0 + + motion-utils@12.36.0: {} + + ms@2.1.3: {} + + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + + nanoid@3.3.11: {} + + napi-postinstall@0.3.4: {} + + natural-compare@1.4.0: {} + + next-themes@0.4.6(react-dom@19.2.5(react@19.2.5))(react@19.2.5): + dependencies: + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + + next@15.2.6(react-dom@19.2.5(react@19.2.5))(react@19.2.5): + dependencies: + "@next/env": 15.2.6 + "@swc/counter": 0.1.3 + "@swc/helpers": 0.5.15 + busboy: 1.6.0 + caniuse-lite: 1.0.30001788 + postcss: 8.4.31 + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + styled-jsx: 5.1.6(react@19.2.5) + optionalDependencies: + "@next/swc-darwin-arm64": 15.2.5 + "@next/swc-darwin-x64": 15.2.5 + "@next/swc-linux-arm64-gnu": 15.2.5 + "@next/swc-linux-arm64-musl": 15.2.5 + "@next/swc-linux-x64-gnu": 15.2.5 + "@next/swc-linux-x64-musl": 15.2.5 + "@next/swc-win32-arm64-msvc": 15.2.5 + "@next/swc-win32-x64-msvc": 15.2.5 + sharp: 0.33.5 + transitivePeerDependencies: + - "@babel/core" + - babel-plugin-macros + + node-exports-info@1.6.0: + dependencies: + array.prototype.flatmap: 1.3.3 + es-errors: 1.3.0 + object.entries: 1.1.9 + semver: 6.3.1 + + node-releases@2.0.37: {} + + normalize-path@3.0.0: {} + + object-assign@4.1.1: {} + + object-hash@3.0.0: {} + + object-inspect@1.13.4: {} + + object-keys@1.1.1: {} + + object.assign@4.1.7: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + has-symbols: 1.1.0 + object-keys: 1.1.1 + + object.entries@1.1.9: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-object-atoms: 1.1.1 + + object.groupby@1.0.3: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + + object.values@1.2.1: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-entities@2.0.0: + dependencies: + character-entities: 1.2.4 + character-entities-legacy: 1.1.4 + character-reference-invalid: 1.1.4 + is-alphanumerical: 1.0.4 + is-decimal: 1.0.4 + is-hexadecimal: 1.0.4 + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + picocolors@1.1.1: {} + + picomatch@2.3.2: {} + + picomatch@4.0.4: {} + + pify@2.3.0: {} + + pirates@4.0.7: {} + + possible-typed-array-names@1.1.0: {} + + postcss-import@15.1.0(postcss@8.5.10): + dependencies: + postcss: 8.5.10 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.12 + + postcss-js@4.1.0(postcss@8.5.10): + dependencies: + camelcase-css: 2.0.1 + postcss: 8.5.10 + + postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.10): + dependencies: + lilconfig: 3.1.3 + optionalDependencies: + jiti: 1.21.7 + postcss: 8.5.10 + + postcss-nested@6.2.0(postcss@8.5.10): + dependencies: + postcss: 8.5.10 + postcss-selector-parser: 6.1.2 + + postcss-selector-parser@6.0.10: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-selector-parser@6.1.2: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-value-parser@4.2.0: {} + + postcss@8.4.31: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + postcss@8.5.10: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + prettier@3.8.3: {} + + prismjs@1.27.0: {} + + prismjs@1.30.0: {} + + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + + property-information@5.6.0: + dependencies: + xtend: 4.0.2 + + proxy-from-env@2.1.0: {} + + punycode@2.3.1: {} + + queue-microtask@1.2.3: {} + + react-copy-to-clipboard@5.1.1(react@19.2.5): + dependencies: + copy-to-clipboard: 3.3.3 + prop-types: 15.8.1 + react: 19.2.5 + + react-day-picker@8.10.1(date-fns@4.1.0)(react@19.2.5): + dependencies: + date-fns: 4.1.0 + react: 19.2.5 + + react-dom@19.2.5(react@19.2.5): + dependencies: + react: 19.2.5 + scheduler: 0.27.0 + + react-hook-form@7.72.1(react@19.2.5): + dependencies: + react: 19.2.5 + + react-is@16.13.1: {} + + react-is@18.3.1: {} + + react-redux@9.2.0(@types/react@19.2.14)(react@19.2.5)(redux@5.0.1): + dependencies: + "@types/use-sync-external-store": 0.0.6 + react: 19.2.5 + use-sync-external-store: 1.6.0(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + redux: 5.0.1 + + react-remove-scroll-bar@2.3.8(@types/react@19.2.14)(react@19.2.5): + dependencies: + react: 19.2.5 + react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.5) + tslib: 2.8.1 + optionalDependencies: + "@types/react": 19.2.14 + + react-remove-scroll@2.7.2(@types/react@19.2.14)(react@19.2.5): + dependencies: + react: 19.2.5 + react-remove-scroll-bar: 2.3.8(@types/react@19.2.14)(react@19.2.5) + react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.5) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@19.2.14)(react@19.2.5) + use-sidecar: 1.1.3(@types/react@19.2.14)(react@19.2.5) + optionalDependencies: + "@types/react": 19.2.14 + + react-smooth@4.0.4(react-dom@19.2.5(react@19.2.5))(react@19.2.5): + dependencies: + fast-equals: 5.4.0 + prop-types: 15.8.1 + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + react-transition-group: 4.4.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + + react-style-singleton@2.2.3(@types/react@19.2.14)(react@19.2.5): + dependencies: + get-nonce: 1.0.1 + react: 19.2.5 + tslib: 2.8.1 + optionalDependencies: + "@types/react": 19.2.14 + + react-syntax-highlighter@15.6.6(react@19.2.5): + dependencies: + "@babel/runtime": 7.29.2 + highlight.js: 10.7.3 + highlightjs-vue: 1.0.0 + lowlight: 1.20.0 + prismjs: 1.30.0 + react: 19.2.5 + refractor: 3.6.0 + + react-transition-group@4.4.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5): + dependencies: + "@babel/runtime": 7.29.2 + dom-helpers: 5.2.1 + loose-envify: 1.4.0 + prop-types: 15.8.1 + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + + react@19.2.5: {} + + read-cache@1.0.0: + dependencies: + pify: 2.3.0 + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.2 + + recharts-scale@0.4.5: + dependencies: + decimal.js-light: 2.5.1 + + recharts@2.15.4(react-dom@19.2.5(react@19.2.5))(react@19.2.5): + dependencies: + clsx: 2.1.1 + eventemitter3: 4.0.7 + lodash: 4.18.1 + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + react-is: 18.3.1 + react-smooth: 4.0.4(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + recharts-scale: 0.4.5 + tiny-invariant: 1.3.3 + victory-vendor: 36.9.2 + + redux-thunk@3.1.0(redux@5.0.1): + dependencies: + redux: 5.0.1 + + redux@5.0.1: {} + + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + + refractor@3.6.0: + dependencies: + hastscript: 6.0.0 + parse-entities: 2.0.0 + prismjs: 1.27.0 + + regexp.prototype.flags@1.5.4: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 + + reselect@5.1.1: {} + + resolve-from@4.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + resolve@1.22.12: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + resolve@2.0.0-next.6: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.16.1 + node-exports-info: 1.6.0 + object-keys: 1.1.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + reusify@1.1.0: {} + + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-array-concat@1.1.3: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + + scheduler@0.27.0: {} + + semver@6.3.1: {} + + semver@7.7.4: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + + sharp@0.33.5: + dependencies: + color: 4.2.3 + detect-libc: 2.1.2 + semver: 7.7.4 + optionalDependencies: + "@img/sharp-darwin-arm64": 0.33.5 + "@img/sharp-darwin-x64": 0.33.5 + "@img/sharp-libvips-darwin-arm64": 1.0.4 + "@img/sharp-libvips-darwin-x64": 1.0.4 + "@img/sharp-libvips-linux-arm": 1.0.5 + "@img/sharp-libvips-linux-arm64": 1.0.4 + "@img/sharp-libvips-linux-s390x": 1.0.4 + "@img/sharp-libvips-linux-x64": 1.0.4 + "@img/sharp-libvips-linuxmusl-arm64": 1.0.4 + "@img/sharp-libvips-linuxmusl-x64": 1.0.4 + "@img/sharp-linux-arm": 0.33.5 + "@img/sharp-linux-arm64": 0.33.5 + "@img/sharp-linux-s390x": 0.33.5 + "@img/sharp-linux-x64": 0.33.5 + "@img/sharp-linuxmusl-arm64": 0.33.5 + "@img/sharp-linuxmusl-x64": 0.33.5 + "@img/sharp-wasm32": 0.33.5 + "@img/sharp-win32-ia32": 0.33.5 + "@img/sharp-win32-x64": 0.33.5 + optional: true + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.1 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + simple-swizzle@0.2.4: + dependencies: + is-arrayish: 0.3.4 + optional: true + + sonner@1.7.4(react-dom@19.2.5(react@19.2.5))(react@19.2.5): + dependencies: + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + + source-map-js@1.2.1: {} + + space-separated-tokens@1.1.5: {} + + stable-hash@0.0.5: {} + + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + + streamsearch@1.1.0: {} + + string.prototype.includes@2.0.1: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + + string.prototype.matchall@4.0.12: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + regexp.prototype.flags: 1.5.4 + set-function-name: 2.0.2 + side-channel: 1.1.0 + + string.prototype.repeat@1.0.0: + dependencies: + define-properties: 1.2.1 + es-abstract: 1.24.2 + + string.prototype.trim@1.2.10: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-object-atoms: 1.1.1 + has-property-descriptors: 1.0.2 + + string.prototype.trimend@1.0.9: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-bom@3.0.0: {} + + strip-json-comments@3.1.1: {} + + styled-jsx@5.1.6(react@19.2.5): + dependencies: + client-only: 0.0.1 + react: 19.2.5 + + sucrase@3.35.1: + dependencies: + "@jridgewell/gen-mapping": 0.3.13 + commander: 4.1.1 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.7 + tinyglobby: 0.2.16 + ts-interface-checker: 0.1.13 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + tailwind-merge@2.6.1: {} + + tailwindcss-animate@1.0.7(tailwindcss@3.4.19): + dependencies: + tailwindcss: 3.4.19 + + tailwindcss@3.4.19: + dependencies: + "@alloc/quick-lru": 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.3 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.7 + lilconfig: 3.1.3 + micromatch: 4.0.8 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.1.1 + postcss: 8.5.10 + postcss-import: 15.1.0(postcss@8.5.10) + postcss-js: 4.1.0(postcss@8.5.10) + postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.10) + postcss-nested: 6.2.0(postcss@8.5.10) + postcss-selector-parser: 6.1.2 + resolve: 1.22.12 + sucrase: 3.35.1 + transitivePeerDependencies: + - tsx + - yaml + + text-table@0.2.0: {} + + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + + tiny-invariant@1.3.3: {} + + tinyglobby@0.2.16: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + toggle-selection@1.0.6: {} + + ts-api-utils@2.5.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + ts-interface-checker@0.1.13: {} + + tsconfig-paths@3.15.0: + dependencies: + "@types/json5": 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + + tslib@2.8.1: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-fest@0.20.2: {} + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.9 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.9 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + + typed-array-length@1.0.7: + dependencies: + call-bind: 1.0.9 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 + + typescript@5.9.3: {} + + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.4 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + + undici-types@6.19.8: {} + + unrs-resolver@1.11.1: + dependencies: + napi-postinstall: 0.3.4 + optionalDependencies: + "@unrs/resolver-binding-android-arm-eabi": 1.11.1 + "@unrs/resolver-binding-android-arm64": 1.11.1 + "@unrs/resolver-binding-darwin-arm64": 1.11.1 + "@unrs/resolver-binding-darwin-x64": 1.11.1 + "@unrs/resolver-binding-freebsd-x64": 1.11.1 + "@unrs/resolver-binding-linux-arm-gnueabihf": 1.11.1 + "@unrs/resolver-binding-linux-arm-musleabihf": 1.11.1 + "@unrs/resolver-binding-linux-arm64-gnu": 1.11.1 + "@unrs/resolver-binding-linux-arm64-musl": 1.11.1 + "@unrs/resolver-binding-linux-ppc64-gnu": 1.11.1 + "@unrs/resolver-binding-linux-riscv64-gnu": 1.11.1 + "@unrs/resolver-binding-linux-riscv64-musl": 1.11.1 + "@unrs/resolver-binding-linux-s390x-gnu": 1.11.1 + "@unrs/resolver-binding-linux-x64-gnu": 1.11.1 + "@unrs/resolver-binding-linux-x64-musl": 1.11.1 + "@unrs/resolver-binding-wasm32-wasi": 1.11.1 + "@unrs/resolver-binding-win32-arm64-msvc": 1.11.1 + "@unrs/resolver-binding-win32-ia32-msvc": 1.11.1 + "@unrs/resolver-binding-win32-x64-msvc": 1.11.1 + + update-browserslist-db@1.2.3(browserslist@4.28.2): + dependencies: + browserslist: 4.28.2 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + use-callback-ref@1.3.3(@types/react@19.2.14)(react@19.2.5): + dependencies: + react: 19.2.5 + tslib: 2.8.1 + optionalDependencies: + "@types/react": 19.2.14 + + use-debounce@10.1.1(react@19.2.5): + dependencies: + react: 19.2.5 + + use-sidecar@1.1.3(@types/react@19.2.14)(react@19.2.5): + dependencies: + detect-node-es: 1.1.0 + react: 19.2.5 + tslib: 2.8.1 + optionalDependencies: + "@types/react": 19.2.14 + + use-sync-external-store@1.6.0(react@19.2.5): + dependencies: + react: 19.2.5 + + util-deprecate@1.0.2: {} + + uuid@9.0.1: {} + + vaul@0.9.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5): + dependencies: + "@radix-ui/react-dialog": 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + transitivePeerDependencies: + - "@types/react" + - "@types/react-dom" + + victory-vendor@36.9.2: + dependencies: + "@types/d3-array": 3.2.2 + "@types/d3-ease": 3.0.2 + "@types/d3-interpolate": 3.0.4 + "@types/d3-scale": 4.0.9 + "@types/d3-shape": 3.1.8 + "@types/d3-time": 3.0.4 + "@types/d3-timer": 3.0.2 + d3-array: 3.2.4 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-scale: 4.0.2 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-timer: 3.0.1 + + which-boxed-primitive@1.1.1: + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.4 + function.prototype.name: 1.1.8 + has-tostringtag: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.2 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.20 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + + which-typed-array@1.1.20: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.9 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + wrappy@1.0.2: {} + + xtend@4.0.2: {} + + yocto-queue@0.1.0: {} + + zod@3.25.76: {} diff --git a/server/dashboard/postcss.config.js b/server/dashboard/postcss.config.js new file mode 100644 index 000000000..12a703d90 --- /dev/null +++ b/server/dashboard/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/server/dashboard/public/android-chrome-192x192.png b/server/dashboard/public/android-chrome-192x192.png new file mode 100644 index 000000000..96cd3b941 Binary files /dev/null and b/server/dashboard/public/android-chrome-192x192.png differ diff --git a/server/dashboard/public/android-chrome-512x512.png b/server/dashboard/public/android-chrome-512x512.png new file mode 100644 index 000000000..9d003e2a9 Binary files /dev/null and b/server/dashboard/public/android-chrome-512x512.png differ diff --git a/server/dashboard/public/apple-touch-icon.png b/server/dashboard/public/apple-touch-icon.png new file mode 100644 index 000000000..a228f8d93 Binary files /dev/null and b/server/dashboard/public/apple-touch-icon.png differ diff --git a/server/dashboard/public/favicon-16x16.png b/server/dashboard/public/favicon-16x16.png new file mode 100644 index 000000000..8640e2cc9 Binary files /dev/null and b/server/dashboard/public/favicon-16x16.png differ diff --git a/server/dashboard/public/favicon-32x32.png b/server/dashboard/public/favicon-32x32.png new file mode 100644 index 000000000..528d22d07 Binary files /dev/null and b/server/dashboard/public/favicon-32x32.png differ diff --git a/server/dashboard/public/favicon.ico b/server/dashboard/public/favicon.ico new file mode 100644 index 000000000..b4eb2caa8 Binary files /dev/null and b/server/dashboard/public/favicon.ico differ diff --git a/server/dashboard/public/fonts/DMMono-Italic.ttf b/server/dashboard/public/fonts/DMMono-Italic.ttf new file mode 100644 index 000000000..c4471dc3c Binary files /dev/null and b/server/dashboard/public/fonts/DMMono-Italic.ttf differ diff --git a/server/dashboard/public/fonts/DMMono-Light.ttf b/server/dashboard/public/fonts/DMMono-Light.ttf new file mode 100644 index 000000000..1b2d94943 Binary files /dev/null and b/server/dashboard/public/fonts/DMMono-Light.ttf differ diff --git a/server/dashboard/public/fonts/DMMono-LightItalic.ttf b/server/dashboard/public/fonts/DMMono-LightItalic.ttf new file mode 100644 index 000000000..b37eca16c Binary files /dev/null and b/server/dashboard/public/fonts/DMMono-LightItalic.ttf differ diff --git a/server/dashboard/public/fonts/DMMono-Medium.ttf b/server/dashboard/public/fonts/DMMono-Medium.ttf new file mode 100644 index 000000000..f1d6de1d5 Binary files /dev/null and b/server/dashboard/public/fonts/DMMono-Medium.ttf differ diff --git a/server/dashboard/public/fonts/DMMono-MediumItalic.ttf b/server/dashboard/public/fonts/DMMono-MediumItalic.ttf new file mode 100644 index 000000000..224099be2 Binary files /dev/null and b/server/dashboard/public/fonts/DMMono-MediumItalic.ttf differ diff --git a/server/dashboard/public/fonts/DMMono-Regular.ttf b/server/dashboard/public/fonts/DMMono-Regular.ttf new file mode 100644 index 000000000..7efe813da Binary files /dev/null and b/server/dashboard/public/fonts/DMMono-Regular.ttf differ diff --git a/server/dashboard/public/fonts/Fustat-VariableFont_wght.ttf b/server/dashboard/public/fonts/Fustat-VariableFont_wght.ttf new file mode 100644 index 000000000..da034320e Binary files /dev/null and b/server/dashboard/public/fonts/Fustat-VariableFont_wght.ttf differ diff --git a/server/dashboard/public/fonts/InterVariable-Italic.woff2 b/server/dashboard/public/fonts/InterVariable-Italic.woff2 new file mode 100644 index 000000000..b3530f3f5 Binary files /dev/null and b/server/dashboard/public/fonts/InterVariable-Italic.woff2 differ diff --git a/server/dashboard/public/fonts/InterVariable.woff2 b/server/dashboard/public/fonts/InterVariable.woff2 new file mode 100644 index 000000000..5a8d3e72a Binary files /dev/null and b/server/dashboard/public/fonts/InterVariable.woff2 differ diff --git a/server/dashboard/public/fonts/RobotoMono-Bold.ttf b/server/dashboard/public/fonts/RobotoMono-Bold.ttf new file mode 100644 index 000000000..d8841280b Binary files /dev/null and b/server/dashboard/public/fonts/RobotoMono-Bold.ttf differ diff --git a/server/dashboard/public/fonts/RobotoMono-Regular.ttf b/server/dashboard/public/fonts/RobotoMono-Regular.ttf new file mode 100644 index 000000000..6df2b2536 Binary files /dev/null and b/server/dashboard/public/fonts/RobotoMono-Regular.ttf differ diff --git a/server/dashboard/public/images/dark.svg b/server/dashboard/public/images/dark.svg new file mode 100644 index 000000000..e188a0c60 --- /dev/null +++ b/server/dashboard/public/images/dark.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/server/dashboard/public/images/dither.svg b/server/dashboard/public/images/dither.svg new file mode 100644 index 000000000..9e02813aa --- /dev/null +++ b/server/dashboard/public/images/dither.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/server/dashboard/public/images/light.svg b/server/dashboard/public/images/light.svg new file mode 100644 index 000000000..681ad49ed --- /dev/null +++ b/server/dashboard/public/images/light.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/server/dashboard/public/images/logos/aws.svg b/server/dashboard/public/images/logos/aws.svg new file mode 100644 index 000000000..f61cf5755 --- /dev/null +++ b/server/dashboard/public/images/logos/aws.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/server/dashboard/public/images/logos/logo-dark.png b/server/dashboard/public/images/logos/logo-dark.png new file mode 100644 index 000000000..f26db55d7 Binary files /dev/null and b/server/dashboard/public/images/logos/logo-dark.png differ diff --git a/server/dashboard/public/images/logos/logo-light.png b/server/dashboard/public/images/logos/logo-light.png new file mode 100644 index 000000000..4ed32176a Binary files /dev/null and b/server/dashboard/public/images/logos/logo-light.png differ diff --git a/server/dashboard/public/images/logos/nvidia.svg b/server/dashboard/public/images/logos/nvidia.svg new file mode 100644 index 000000000..a14c0ca5b --- /dev/null +++ b/server/dashboard/public/images/logos/nvidia.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/server/dashboard/public/images/micheal.png b/server/dashboard/public/images/micheal.png new file mode 100644 index 000000000..d90c49626 Binary files /dev/null and b/server/dashboard/public/images/micheal.png differ diff --git a/server/dashboard/public/images/no-memories-dark.svg b/server/dashboard/public/images/no-memories-dark.svg new file mode 100644 index 000000000..580228aa9 --- /dev/null +++ b/server/dashboard/public/images/no-memories-dark.svg @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/server/dashboard/public/images/no-memories.svg b/server/dashboard/public/images/no-memories.svg new file mode 100644 index 000000000..03ae32a79 --- /dev/null +++ b/server/dashboard/public/images/no-memories.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/server/dashboard/public/images/no-requests-dark.svg b/server/dashboard/public/images/no-requests-dark.svg new file mode 100644 index 000000000..2e3788d09 --- /dev/null +++ b/server/dashboard/public/images/no-requests-dark.svg @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/server/dashboard/public/images/no-requests.svg b/server/dashboard/public/images/no-requests.svg new file mode 100644 index 000000000..5050339ee --- /dev/null +++ b/server/dashboard/public/images/no-requests.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/server/dashboard/public/images/success-banner.png b/server/dashboard/public/images/success-banner.png new file mode 100644 index 000000000..db7c44973 Binary files /dev/null and b/server/dashboard/public/images/success-banner.png differ diff --git a/server/dashboard/public/images/vercel.png b/server/dashboard/public/images/vercel.png new file mode 100644 index 000000000..7211bfa9c Binary files /dev/null and b/server/dashboard/public/images/vercel.png differ diff --git a/server/dashboard/public/mem0-animation.mp4 b/server/dashboard/public/mem0-animation.mp4 new file mode 100644 index 000000000..e4cf97aec Binary files /dev/null and b/server/dashboard/public/mem0-animation.mp4 differ diff --git a/server/dashboard/public/site.webmanifest b/server/dashboard/public/site.webmanifest new file mode 100644 index 000000000..fa99de77d --- /dev/null +++ b/server/dashboard/public/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "", + "short_name": "", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/server/dashboard/src/app/(auth)/layout.tsx b/server/dashboard/src/app/(auth)/layout.tsx new file mode 100644 index 000000000..d58a08257 --- /dev/null +++ b/server/dashboard/src/app/(auth)/layout.tsx @@ -0,0 +1,44 @@ +import "@/styles/globals.css"; +import React from "react"; +import { Inter, InterDisplay, Roboto, Fustat, DMMono } from "../(root)/fonts"; +import { cn } from "@/lib/utils"; +import { ThemeProvider } from "@/components/theme-provider"; +import { AuthProvider } from "@/lib/auth"; + +export const metadata = { + title: "Mem0 - Log in", + description: "Log in to Mem0", +}; + +export default function AuthLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + + + + {children} + + + + + ); +} diff --git a/server/dashboard/src/app/(auth)/login/login-form.tsx b/server/dashboard/src/app/(auth)/login/login-form.tsx new file mode 100644 index 000000000..7d875c976 --- /dev/null +++ b/server/dashboard/src/app/(auth)/login/login-form.tsx @@ -0,0 +1,233 @@ +"use client"; + +import { useEffect, useState } from "react"; +import Image from "next/image"; +import { useRouter, useSearchParams } from "next/navigation"; +import { useTheme } from "next-themes"; +import { Check, Copy } from "lucide-react"; +import { CopyToClipboard } from "react-copy-to-clipboard"; +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { useAuth } from "@/hooks/use-auth"; +import { getErrorMessage } from "@/lib/error-message"; +import { isValidEmail } from "@/lib/validators"; + +const RESET_COMMAND = + "make reset-admin-password EMAIL= PASSWORD="; + +export default function LoginForm() { + const router = useRouter(); + const searchParams = useSearchParams(); + const { user, isLoading, login } = useAuth(); + const { resolvedTheme } = useTheme(); + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [error, setError] = useState(""); + const [submitting, setSubmitting] = useState(false); + const [mounted, setMounted] = useState(false); + const [copied, setCopied] = useState(false); + + useEffect(() => { + setMounted(true); + }, []); + + useEffect(() => { + if (!isLoading && user) { + router.push(searchParams.get("next") || "/dashboard/requests"); + } + }, [user, isLoading, router, searchParams]); + + const emailValid = isValidEmail(email); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setError(""); + if (!emailValid) { + setError("Enter a valid email address."); + return; + } + setSubmitting(true); + try { + await login(email, password); + router.push(searchParams.get("next") || "/dashboard/requests"); + } catch (err) { + setError(getErrorMessage(err, "Login failed")); + } finally { + setSubmitting(false); + } + }; + + return ( +
+
+
+
+ {mounted && ( + Mem0 + )} +
+

+ Sign in to Mem0 +

+
+ {error && ( +

+ {error} +

+ )} +
+
+ + setEmail(e.target.value)} + placeholder="admin@company.com" + required + autoFocus + /> +
+
+ + setPassword(e.target.value)} + required + /> +
+ +
+ + + + + + + Reset your admin password + + Run this command on the server host. It overwrites the + existing password; anyone already signed in stays signed in + until their session expires. + + +
+ + { + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }} + > + + +
+
+
+
+
+
+ +
+
+
+
+

+ "Mem0 allowed us to unlock true personalized tutoring for + every student, and it took us just a weekend to integrate." +

+
+
+

Michael Tong

+

CTO, RevisionDojo

+
+ Michael Tong +
+
+
+

Trusted by 100k+ Developers

+
+
+ AWS +
+
+ NVIDIA +
+
+ Vercel +
+
+
+
+
+
+ ); +} diff --git a/server/dashboard/src/app/(auth)/login/page.tsx b/server/dashboard/src/app/(auth)/login/page.tsx new file mode 100644 index 000000000..ca18f3937 --- /dev/null +++ b/server/dashboard/src/app/(auth)/login/page.tsx @@ -0,0 +1,10 @@ +import { Suspense } from "react"; +import LoginForm from "./login-form"; + +export default function LoginPage() { + return ( + + + + ); +} diff --git a/server/dashboard/src/app/(root)/clientLayout.tsx b/server/dashboard/src/app/(root)/clientLayout.tsx new file mode 100644 index 000000000..ec6247076 --- /dev/null +++ b/server/dashboard/src/app/(root)/clientLayout.tsx @@ -0,0 +1,49 @@ +"use client"; + +import { useEffect } from "react"; +import { useRouter, usePathname } from "next/navigation"; +import ThemeAwareLogo from "@/components/misc/theme-aware-logo"; +import { LinearProgress } from "@/components/ui/linearProgress"; +import { TooltipProvider } from "@/components/ui/tooltip"; +import { useAuth } from "@/hooks/use-auth"; + +export const SIDEBAR_WIDTH = 180; +export const COLLAPSED_SIDEBAR_WIDTH = 64; +export const COLLAPSED_SIDEBAR_PADDING = 16; +export const COLLAPSED_SIDEBAR_WIDTH_WITHOUT_PADDING = + COLLAPSED_SIDEBAR_WIDTH - COLLAPSED_SIDEBAR_PADDING; + +function AuthLoadingState() { + return ( +
+ + +
+ ); +} + +export const ClientLayout: React.FC<{ children: React.ReactNode }> = ({ + children, +}) => { + const pathname = usePathname(); + const router = useRouter(); + const { user, isLoading } = useAuth(); + const isPublicPage = + pathname.startsWith("/login") || pathname.startsWith("/setup"); + + useEffect(() => { + if (!isPublicPage && !isLoading && !user) { + router.replace("/login"); + } + }, [isLoading, isPublicPage, router, user]); + + if (isLoading && !isPublicPage) { + return ; + } + + if (!isPublicPage && !user) { + return ; + } + + return {children}; +}; diff --git a/server/dashboard/src/app/(root)/dashboard-client-layout.tsx b/server/dashboard/src/app/(root)/dashboard-client-layout.tsx new file mode 100644 index 000000000..dbffce8a5 --- /dev/null +++ b/server/dashboard/src/app/(root)/dashboard-client-layout.tsx @@ -0,0 +1,55 @@ +"use client"; + +import React from "react"; +import { ThemeProvider } from "@/components/theme-provider"; +import "@/styles/globals.css"; +import { ClientLayout } from "./clientLayout"; +import { cn } from "@/lib/utils"; +import { Inter, InterDisplay, Roboto, Fustat, DMMono } from "./fonts"; +import { Provider } from "react-redux"; +import store from "@/store/store"; +import { AuthProvider } from "@/lib/auth"; +import dynamic from "next/dynamic"; + +const Toaster = dynamic( + () => + import("@/components/ui/sonner").then((mod) => ({ default: mod.Toaster })), + { + ssr: false, + }, +); + +export function DashboardClientLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + + + + {children} + + + + + + + ); +} diff --git a/server/dashboard/src/app/(root)/dashboard/analytics/page.tsx b/server/dashboard/src/app/(root)/dashboard/analytics/page.tsx new file mode 100644 index 000000000..5147c6788 --- /dev/null +++ b/server/dashboard/src/app/(root)/dashboard/analytics/page.tsx @@ -0,0 +1,54 @@ +"use client"; + +import { LockedPage } from "@/components/self-hosted/locked-page"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; + +function AnalyticsMockup() { + return ( +
+
+ {[ + { label: "Total Operations", value: "12,847" }, + { label: "Avg Latency", value: "142ms" }, + { label: "Success Rate", value: "99.7%" }, + ].map((stat) => ( + + +

+ {stat.label} +

+

{stat.value}

+
+
+ ))} +
+ + + Operations over time + + +
+ {[40, 65, 45, 80, 55, 90, 70, 85, 60, 95, 75, 50].map((h, i) => ( +
+ ))} +
+ + +
+ ); +} + +export default function AnalyticsPage() { + return ( + } + utmMedium="dashboard-locked-analytics" + /> + ); +} diff --git a/server/dashboard/src/app/(root)/dashboard/api-keys/page.tsx b/server/dashboard/src/app/(root)/dashboard/api-keys/page.tsx new file mode 100644 index 000000000..e38386fe1 --- /dev/null +++ b/server/dashboard/src/app/(root)/dashboard/api-keys/page.tsx @@ -0,0 +1,244 @@ +"use client"; + +import { useState } from "react"; +import { Button } from "@/components/ui/button"; +import { Card } from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import { DataTable } from "@/components/shared/data-table"; +import { TableSkeleton } from "@/components/shared/table-skeleton"; +import { EmptyState } from "@/components/self-hosted/empty-state"; +import DeleteConfirmationModal from "@/components/ui/delete-confirmation-modal"; +import { api } from "@/utils/api"; +import { API_KEY_ENDPOINTS } from "@/utils/api-endpoints"; +import { toast } from "@/components/ui/use-toast"; +import { UpgradeBanner } from "@/components/self-hosted/upgrade-banner"; +import { Plus, Copy, Check, Trash2 } from "lucide-react"; +import { CopyToClipboard } from "react-copy-to-clipboard"; +import { format } from "date-fns"; +import { getErrorMessage } from "@/lib/error-message"; +import { useApiQuery } from "@/hooks/use-api-query"; +import { ApiKey, ApiKeyCreateResponse } from "@/types/api"; + +export default function ApiKeysPage() { + const [createOpen, setCreateOpen] = useState(false); + const [newLabel, setNewLabel] = useState(""); + const [newKey, setNewKey] = useState(""); + const [copied, setCopied] = useState(false); + const [keyToRevoke, setKeyToRevoke] = useState(null); + + const { + data: keys = [], + isLoading, + refetch, + } = useApiQuery( + async () => { + const res = await api.get(API_KEY_ENDPOINTS.BASE); + return res.data ?? []; + }, + { errorToast: "Failed to load API keys", initialData: [] }, + ); + + const handleCreate = async () => { + try { + const res = await api.post(API_KEY_ENDPOINTS.BASE, { + label: newLabel, + }); + setNewKey(res.data.key); + void refetch(); + } catch (error) { + toast({ + title: "Failed to create key", + description: getErrorMessage(error), + variant: "destructive", + }); + } + }; + + const handleRevoke = async () => { + if (!keyToRevoke) return; + try { + await api.delete(API_KEY_ENDPOINTS.BY_ID(keyToRevoke.id)); + toast({ title: "API key revoked", variant: "success" }); + setKeyToRevoke(null); + void refetch(); + } catch (error) { + toast({ + title: "Failed to revoke key", + description: getErrorMessage(error), + variant: "destructive", + }); + } + }; + + const handleDialogClose = (open: boolean) => { + if (!open) { + setNewKey(""); + setNewLabel(""); + setCopied(false); + } + setCreateOpen(open); + }; + + const columns = [ + { key: "label" as keyof ApiKey, label: "Label", width: 150 }, + { + key: "key_prefix" as keyof ApiKey, + label: "Key", + width: 120, + render: (value: string) => ( + {value}... + ), + }, + { + key: "created_at" as keyof ApiKey, + label: "Created", + width: 120, + render: (value: string) => format(new Date(value), "MMM d, yyyy"), + }, + { + key: "last_used_at" as keyof ApiKey, + label: "Last Used", + width: 120, + render: (value: string | null) => + value ? format(new Date(value), "MMM d, yyyy") : "Never", + }, + { + key: "id" as keyof ApiKey, + label: "", + width: 40, + render: (_: string, row: ApiKey) => ( + + ), + }, + ]; + + return ( +
+
+

API Keys

+ + + + + + + Create API Key + + {!newKey ? ( +
+
+ + setNewLabel(e.target.value)} + placeholder="e.g. Production" + /> +
+ +
+ ) : ( +
+
+ +
+ + { + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }} + > + + +
+

+ Save this key -- you won't see it again. +

+
+ +
+ )} +
+
+
+ + {keys.length >= 3 && ( + + )} + + {isLoading ? ( + + ) : keys.length === 0 ? ( + + ) : ( + + row.id} + /> + + )} + + setKeyToRevoke(null)} + onConfirm={handleRevoke} + title="Revoke API key" + description="Applications using this key will immediately stop working. This cannot be undone." + itemName={keyToRevoke?.label ?? ""} + confirmButtonText="Revoke" + /> +
+ ); +} diff --git a/server/dashboard/src/app/(root)/dashboard/categories/page.tsx b/server/dashboard/src/app/(root)/dashboard/categories/page.tsx new file mode 100644 index 000000000..39cc979e6 --- /dev/null +++ b/server/dashboard/src/app/(root)/dashboard/categories/page.tsx @@ -0,0 +1,36 @@ +"use client"; + +import { LockedPage } from "@/components/self-hosted/locked-page"; +import { Card, CardContent } from "@/components/ui/card"; + +function CategoriesMockup() { + const categories = ["Health", "Preferences", "Work"]; + return ( +
+ {categories.map((cat) => ( + + +

{cat}

+ {[1, 2, 3].map((i) => ( +
+ ))} + + + ))} +
+ ); +} + +export default function CategoriesPage() { + return ( + } + utmMedium="dashboard-locked-categories" + /> + ); +} diff --git a/server/dashboard/src/app/(root)/dashboard/components/main-nav.tsx b/server/dashboard/src/app/(root)/dashboard/components/main-nav.tsx new file mode 100644 index 000000000..d577de6ed --- /dev/null +++ b/server/dashboard/src/app/(root)/dashboard/components/main-nav.tsx @@ -0,0 +1,249 @@ +"use client"; + +import * as React from "react"; +import Link from "next/link"; +import { + Activity, + ChartLine, + ChevronDown, + FolderInput, + GalleryVerticalEnd, + KeyRound, + Settings, + Tags, + Users, + WebhookIcon, + Wrench, +} from "lucide-react"; +import { useSelector } from "react-redux"; +import { RootState } from "@/store/store"; +import { Badge } from "@/components/ui/badge"; +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from "@/components/ui/collapsible"; +import { + Sidebar, + SidebarContent, + SidebarGroup, + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + SidebarRail, + SidebarGroupLabel, +} from "@/components/ui/sidebar"; +import { usePathname } from "next/navigation"; +import { cn } from "@/lib/utils"; + +export function MainNav({ + className, + ...props +}: React.HTMLAttributes) { + const pathname = usePathname(); + const isSidebarCollapsed = useSelector( + (state: RootState) => state.layout.isSidebarCollapsed, + ); + const [isCloudOpen, setIsCloudOpen] = React.useState(true); + + return ( + + + + +
+
+ {!isSidebarCollapsed && ( + + ACTIVITY + + )} + {[ + { + title: "Requests", + url: "/dashboard/requests", + icon: Activity, + active: pathname === "/dashboard/requests", + }, + { + title: "Memories", + url: "/dashboard/memories", + icon: GalleryVerticalEnd, + active: pathname === "/dashboard/memories", + }, + { + title: "Entities", + url: "/dashboard/entities", + icon: Users, + active: pathname === "/dashboard/entities", + }, + ].map((item) => ( + + + + + {!isSidebarCollapsed && {item.title}} + + + + ))} +
+ + {isSidebarCollapsed && ( +
+ )} + + + {!isSidebarCollapsed && ( + + + CLOUD FEATURES + + + + )} + + {[ + { + title: "Categories", + url: "/dashboard/categories", + icon: Tags, + }, + { + title: "Webhooks", + url: "/dashboard/webhooks", + icon: WebhookIcon, + }, + { + title: "Analytics", + url: "/dashboard/analytics", + icon: ChartLine, + }, + { + title: "Export", + url: "/dashboard/export", + icon: FolderInput, + }, + ].map((item) => ( + + + + + {!isSidebarCollapsed && ( + <> + {item.title} + + PRO + + + )} + + + + ))} + + + + {isSidebarCollapsed && ( +
+ )} + +
+ {!isSidebarCollapsed && ( + + ACCOUNT + + )} + {[ + { + title: "API Keys", + url: "/dashboard/api-keys", + icon: KeyRound, + active: pathname === "/dashboard/api-keys", + }, + { + title: "Configuration", + url: "/dashboard/configuration", + icon: Wrench, + active: pathname === "/dashboard/configuration", + }, + { + title: "Settings", + url: "/dashboard/settings", + icon: Settings, + active: pathname === "/dashboard/settings", + }, + ].map((item) => ( + + + + + {!isSidebarCollapsed && {item.title}} + + + + ))} +
+
+ + + + + + ); +} diff --git a/server/dashboard/src/app/(root)/dashboard/components/nav-wrapper.tsx b/server/dashboard/src/app/(root)/dashboard/components/nav-wrapper.tsx new file mode 100644 index 000000000..8ecbf3090 --- /dev/null +++ b/server/dashboard/src/app/(root)/dashboard/components/nav-wrapper.tsx @@ -0,0 +1,174 @@ +"use client"; + +import { MainNav } from "./main-nav"; +import { PanelRight, LogOut, Settings, HelpCircle } from "lucide-react"; +import { useCallback } from "react"; +import { + COLLAPSED_SIDEBAR_WIDTH, + COLLAPSED_SIDEBAR_WIDTH_WITHOUT_PADDING, + SIDEBAR_WIDTH, +} from "../../clientLayout"; +import { useDispatch, useSelector } from "react-redux"; +import { cn } from "@/lib/utils"; +import { RootState } from "@/store/store"; +import { toggleSidebar } from "@/store/reducers/layoutReducer"; +import { useAuth } from "@/hooks/use-auth"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { + Tooltip, + TooltipTrigger, + TooltipContent, +} from "@/components/ui/tooltip"; +import Link from "next/link"; +import { Building2 } from "lucide-react"; + +export default function NavWrapper() { + const dispatch = useDispatch(); + const isSidebarCollapsed = useSelector( + (state: RootState) => state.layout.isSidebarCollapsed, + ); + const { user, logout } = useAuth(); + + const instanceName = process.env.NEXT_PUBLIC_INSTANCE_NAME || "Mem0"; + + const handleToggle = useCallback(() => { + dispatch(toggleSidebar()); + }, [dispatch]); + + return ( + <> +
+
+
+
+
+ +
+ {!isSidebarCollapsed && ( + + {instanceName} + + )} +
+
+ + +
+ + {!isSidebarCollapsed && ( +
+
+ + + + + +
+

+ {user?.name} +

+

+ {user?.email} +

+
+ + + + + Settings + + + + + + Log out + +
+
+
+
+ )} +
+ +
+
+ +
+ +
+ + + + + + + Documentation + +
+
+ + ); +} diff --git a/server/dashboard/src/app/(root)/dashboard/configuration/page.tsx b/server/dashboard/src/app/(root)/dashboard/configuration/page.tsx new file mode 100644 index 000000000..7ade13f69 --- /dev/null +++ b/server/dashboard/src/app/(root)/dashboard/configuration/page.tsx @@ -0,0 +1,236 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { toast } from "@/components/ui/use-toast"; +import { UpgradeBanner } from "@/components/self-hosted/upgrade-banner"; +import { getErrorMessage } from "@/lib/error-message"; +import { api } from "@/utils/api"; +import { MEMORY_ENDPOINTS } from "@/utils/api-endpoints"; +import { + buildProviderConfig, + getEffectiveConfig, +} from "@/utils/self-hosted-config"; +import { useAuth } from "@/hooks/use-auth"; +import { useApiQuery } from "@/hooks/use-api-query"; + +type BundledProviders = { + llm: string[]; + embedder: string[]; +}; + +export default function ConfigurationPage() { + const { isAdmin } = useAuth(); + const [isSaving, setIsSaving] = useState(false); + const [llmProvider, setLlmProvider] = useState(""); + const [llmModel, setLlmModel] = useState(""); + const [llmApiKey, setLlmApiKey] = useState(""); + const [embedderProvider, setEmbedderProvider] = useState(""); + const [embedderModel, setEmbedderModel] = useState(""); + + const { data: config, isLoading: isPrefilling } = useApiQuery( + async () => { + const res = await api.get(MEMORY_ENDPOINTS.CONFIGURE); + return getEffectiveConfig(res.data); + }, + { errorToast: "Failed to load server configuration" }, + ); + + const { data: providers } = useApiQuery( + async () => { + const res = await api.get( + MEMORY_ENDPOINTS.CONFIGURE_PROVIDERS, + ); + return res.data; + }, + { errorToast: "Failed to load bundled providers" }, + ); + + useEffect(() => { + if (!config) return; + setLlmProvider((current) => current || config.llm?.provider || ""); + setLlmModel((current) => current || config.llm?.config?.model || ""); + setEmbedderProvider( + (current) => current || config.embedder?.provider || "", + ); + setEmbedderModel( + (current) => current || config.embedder?.config?.model || "", + ); + }, [config]); + + const handleSave = async () => { + setIsSaving(true); + + try { + const llm = buildProviderConfig({ + provider: llmProvider, + model: llmModel, + apiKey: llmApiKey, + }); + const embedder = buildProviderConfig({ + provider: embedderProvider, + model: embedderModel, + }); + + const newConfig: Record = { + version: "v1.1", + }; + + if (llm) { + newConfig.llm = llm; + } + + if (embedder) { + newConfig.embedder = embedder; + } + + await api.post(MEMORY_ENDPOINTS.CONFIGURE, newConfig); + toast({ title: "Configuration saved", variant: "success" }); + } catch (error) { + toast({ + title: "Failed to save configuration", + description: getErrorMessage(error), + variant: "destructive", + }); + } finally { + setIsSaving(false); + } + }; + + return ( +
+
+

Configuration

+ {isPrefilling && ( +

+ Loading effective server configuration... +

+ )} +
+ + + + LLM Provider + + +
+
+ + +
+
+ + setLlmModel(e.target.value)} + disabled={!isAdmin} + /> +
+
+
+ + setLlmApiKey(e.target.value)} + disabled={!isAdmin} + /> +
+
+
+ + + + Embedding Model + + +
+
+ + +
+
+ + setEmbedderModel(e.target.value)} + disabled={!isAdmin} + /> +
+
+
+
+ +

+ Need another provider? Install its Python package, rebuild the image, + and extend the bundled list. See the{" "} + + setup guide + + . +

+ + {isAdmin && ( + + )} + + +
+ ); +} diff --git a/server/dashboard/src/app/(root)/dashboard/entities/page.tsx b/server/dashboard/src/app/(root)/dashboard/entities/page.tsx new file mode 100644 index 000000000..421f42026 --- /dev/null +++ b/server/dashboard/src/app/(root)/dashboard/entities/page.tsx @@ -0,0 +1,134 @@ +"use client"; + +import { useState } from "react"; +import { Trash2 } from "lucide-react"; +import { format } from "date-fns"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { Card } from "@/components/ui/card"; +import { DataTable } from "@/components/shared/data-table"; +import { TableSkeleton } from "@/components/shared/table-skeleton"; +import { EmptyState } from "@/components/self-hosted/empty-state"; +import DeleteConfirmationModal from "@/components/ui/delete-confirmation-modal"; +import { toast } from "@/components/ui/use-toast"; +import { api } from "@/utils/api"; +import { ENTITY_ENDPOINTS } from "@/utils/api-endpoints"; +import { getErrorMessage } from "@/lib/error-message"; +import { useApiQuery } from "@/hooks/use-api-query"; +import { Entity } from "@/types/api"; + +export default function EntitiesPage() { + const [entityToDelete, setEntityToDelete] = useState(null); + + const { + data: entities = [], + isLoading, + refetch, + } = useApiQuery( + async () => { + const res = await api.get(ENTITY_ENDPOINTS.BASE); + return res.data ?? []; + }, + { errorToast: "Failed to load entities", initialData: [] }, + ); + + const handleDelete = async () => { + if (!entityToDelete) return; + try { + await api.delete( + ENTITY_ENDPOINTS.BY_ID(entityToDelete.type, entityToDelete.id), + ); + toast({ title: "Entity deleted", variant: "success" }); + setEntityToDelete(null); + void refetch(); + } catch (error) { + toast({ + title: "Failed to delete entity", + description: getErrorMessage(error), + variant: "destructive", + }); + } + }; + + const columns = [ + { + key: "type" as keyof Entity, + label: "Type", + width: 100, + render: (value: Entity["type"]) => ( + + {value} + + ), + }, + { + key: "id" as keyof Entity, + label: "ID", + width: 280, + render: (value: string) => ( + {value} + ), + }, + { + key: "total_memories" as keyof Entity, + label: "Memories", + width: 100, + align: "right" as const, + }, + { + key: "updated_at" as keyof Entity, + label: "Last Active", + width: 140, + render: (value: string | null) => + value ? format(new Date(value), "MMM d, yyyy") : "--", + }, + { + key: "id" as keyof Entity, + label: "", + width: 40, + render: (_: string, row: Entity) => ( + + ), + }, + ]; + + return ( +
+

Entities

+ + {isLoading ? ( + + ) : entities.length === 0 ? ( + + ) : ( + + `${row.type}:${row.id}`} + /> + + )} + + setEntityToDelete(null)} + onConfirm={handleDelete} + title="Delete entity" + description="All memories associated with this entity will be permanently removed. This cannot be undone." + itemName={entityToDelete?.id ?? ""} + confirmButtonText="Delete" + /> +
+ ); +} diff --git a/server/dashboard/src/app/(root)/dashboard/export/page.tsx b/server/dashboard/src/app/(root)/dashboard/export/page.tsx new file mode 100644 index 000000000..26f8423ce --- /dev/null +++ b/server/dashboard/src/app/(root)/dashboard/export/page.tsx @@ -0,0 +1,65 @@ +"use client"; + +import { LockedPage } from "@/components/self-hosted/locked-page"; +import { Card, CardContent } from "@/components/ui/card"; +import { Label } from "@/components/ui/label"; +import { Button } from "@/components/ui/button"; + +function ExportMockup() { + return ( +
+ + +
+ +
+ {["JSON", "CSV", "Pydantic Schema"].map((fmt) => ( + + ))} +
+
+
+ + + +
+                  {`{
+  "memories": [
+    {
+      "id": "mem_abc123",
+      "content": "User prefers dark mode",
+      "user_id": "user_1",
+      "created_at": "2026-04-10T12:00:00Z"
+    }
+  ],
+  "total": 1247
+}`}
+                
+
+
+
+ +
+
+
+ ); +} + +export default function ExportPage() { + return ( + } + utmMedium="dashboard-locked-export" + /> + ); +} diff --git a/server/dashboard/src/app/(root)/dashboard/layout.tsx b/server/dashboard/src/app/(root)/dashboard/layout.tsx new file mode 100644 index 000000000..36a852c6f --- /dev/null +++ b/server/dashboard/src/app/(root)/dashboard/layout.tsx @@ -0,0 +1,37 @@ +"use client"; + +import NavWrapper from "./components/nav-wrapper"; +import { cn } from "@/lib/utils"; +import { SIDEBAR_WIDTH, COLLAPSED_SIDEBAR_WIDTH } from "../clientLayout"; +import { useSelector } from "react-redux"; +import { RootState } from "@/store/store"; +import { ScrollArea } from "@/components/ui/scroll-area"; + +export default function DashboardLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + const isSidebarCollapsed = useSelector( + (state: RootState) => state.layout.isSidebarCollapsed, + ); + + return ( + <> + +
+ +
+ {children} +
+
+
+ + ); +} diff --git a/server/dashboard/src/app/(root)/dashboard/memories/page.tsx b/server/dashboard/src/app/(root)/dashboard/memories/page.tsx new file mode 100644 index 000000000..66f95447b --- /dev/null +++ b/server/dashboard/src/app/(root)/dashboard/memories/page.tsx @@ -0,0 +1,273 @@ +"use client"; + +import { useState } from "react"; +import { Trash2 } from "lucide-react"; +import { format } from "date-fns"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Card } from "@/components/ui/card"; +import { DataTable } from "@/components/shared/data-table"; +import { TableSkeleton } from "@/components/shared/table-skeleton"; +import { EmptyState } from "@/components/self-hosted/empty-state"; +import DeleteConfirmationModal from "@/components/ui/delete-confirmation-modal"; +import { + Sheet, + SheetContent, + SheetHeader, + SheetTitle, + SheetDescription, +} from "@/components/ui/sheet"; +import { UpgradeBanner } from "@/components/self-hosted/upgrade-banner"; +import { toast } from "@/components/ui/use-toast"; +import { getErrorMessage } from "@/lib/error-message"; +import { api } from "@/utils/api"; +import { MEMORY_ENDPOINTS } from "@/utils/api-endpoints"; +import { useApiQuery } from "@/hooks/use-api-query"; +import { Memory } from "@/types/api"; + +const PAGE_SIZE = 20; + +export default function MemoriesPage() { + const [userId, setUserId] = useState(""); + const [selectedMemory, setSelectedMemory] = useState(null); + const [memoryToDelete, setMemoryToDelete] = useState(null); + const [page, setPage] = useState(0); + const apiUrl = process.env.NEXT_PUBLIC_API_URL || ""; + + const { + data: memories = [], + isLoading, + refetch, + } = useApiQuery( + async () => { + const params = userId.trim() ? { user_id: userId.trim() } : undefined; + const res = await api.get(MEMORY_ENDPOINTS.BASE, { params }); + const raw = res.data?.results ?? res.data ?? []; + return Array.isArray(raw) ? raw : []; + }, + { errorToast: "Failed to load memories", initialData: [] }, + ); + + const totalPages = Math.ceil(memories.length / PAGE_SIZE); + const paginatedMemories = memories.slice( + page * PAGE_SIZE, + (page + 1) * PAGE_SIZE, + ); + + const handleDelete = async () => { + if (!memoryToDelete) return; + try { + await api.delete(MEMORY_ENDPOINTS.BY_ID(memoryToDelete.id)); + toast({ title: "Memory deleted", variant: "success" }); + if (selectedMemory?.id === memoryToDelete.id) setSelectedMemory(null); + setMemoryToDelete(null); + void refetch(); + } catch (error) { + toast({ + title: "Failed to delete memory", + description: getErrorMessage(error), + variant: "destructive", + }); + } + }; + + const columns = [ + { + key: "memory" as keyof Memory, + label: "Content", + width: 400, + render: (value: string) => ( + {value} + ), + }, + { key: "user_id" as keyof Memory, label: "User", width: 100 }, + { key: "agent_id" as keyof Memory, label: "Agent", width: 100 }, + { + key: "created_at" as keyof Memory, + label: "Created", + width: 120, + render: (value: string) => + value ? format(new Date(value), "MMM d, yyyy") : "--", + }, + ]; + + return ( +
+

Memories

+ + {memories.length >= 1000 && ( + + )} + +
+ setUserId(e.target.value)} + onKeyDown={(e) => { + if (e.key === "Enter") { + setPage(0); + refetch(); + } + }} + className="w-64" + /> +
+ + {isLoading ? ( + + ) : memories.length === 0 ? ( + +
+            {`curl -X POST ${apiUrl}/memories \\
+  -H "X-API-Key: " \\
+  -H "Content-Type: application/json" \\
+  -d '{"messages": [{"role": "user", "content": "I like hiking"}], "user_id": "alice"}'`}
+          
+ + REST API reference + +
+ ) : ( + <> + + row.id} + onRowClick={(row) => setSelectedMemory(row)} + getRowClassName={(row) => + selectedMemory?.id === row.id + ? "bg-surface-default-tertiary" + : undefined + } + /> + + {totalPages > 1 && ( +
+ + {page * PAGE_SIZE + 1}– + {Math.min((page + 1) * PAGE_SIZE, memories.length)} of{" "} + {memories.length} + +
+ + +
+
+ )} + + )} + + { + if (!open) setSelectedMemory(null); + }} + > + + + Memory Detail + + View memory content and metadata + + + {selectedMemory && ( +
+
+ +

{selectedMemory.memory}

+
+
+
+ +

+ {selectedMemory.id} +

+
+ {selectedMemory.user_id && ( +
+ +

{selectedMemory.user_id}

+
+ )} + {selectedMemory.agent_id && ( +
+ +

{selectedMemory.agent_id}

+
+ )} + {selectedMemory.created_at && ( +
+ +

+ {new Date(selectedMemory.created_at).toLocaleString()} +

+
+ )} +
+ +
+ )} +
+
+ + setMemoryToDelete(null)} + onConfirm={handleDelete} + title="Delete memory" + description="This memory will be permanently removed. This cannot be undone." + itemName={memoryToDelete?.id ?? ""} + confirmButtonText="Delete" + /> +
+ ); +} diff --git a/server/dashboard/src/app/(root)/dashboard/requests/page.tsx b/server/dashboard/src/app/(root)/dashboard/requests/page.tsx new file mode 100644 index 000000000..3198ac37f --- /dev/null +++ b/server/dashboard/src/app/(root)/dashboard/requests/page.tsx @@ -0,0 +1,277 @@ +"use client"; + +import { useState } from "react"; +import { format, formatDistanceToNow } from "date-fns"; +import { RefreshCw } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent } from "@/components/ui/card"; +import { Badge } from "@/components/ui/badge"; +import { DataTable } from "@/components/shared/data-table"; +import { TableSkeleton } from "@/components/shared/table-skeleton"; +import { EmptyState } from "@/components/self-hosted/empty-state"; +import { api } from "@/utils/api"; +import { REQUEST_ENDPOINTS } from "@/utils/api-endpoints"; +import { useApiQuery } from "@/hooks/use-api-query"; +import { ApiRequestLog } from "@/types/api"; + +type RequestLog = { + id: string; + createdAt: string; + method: string; + path: string; + statusCode: number; + latencyMs: number; + authType: string; +}; + +const REQUEST_LOG_LIMIT = 200; +const PAGE_SIZE = 20; + +const getStatusClassName = (statusCode: number) => { + if (statusCode >= 500) { + return "border-rose-200 bg-rose-50 text-rose-700 dark:border-rose-900/40 dark:bg-rose-950/40 dark:text-rose-300"; + } + + if (statusCode >= 400) { + return "border-amber-200 bg-amber-50 text-amber-700 dark:border-amber-900/40 dark:bg-amber-950/40 dark:text-amber-300"; + } + + return "border-emerald-200 bg-emerald-50 text-emerald-700 dark:border-emerald-900/40 dark:bg-emerald-950/40 dark:text-emerald-300"; +}; + +const getMethodClassName = (method: string) => { + switch (method.toUpperCase()) { + case "POST": + return "border-sky-200 bg-sky-50 text-sky-700 dark:border-sky-900/40 dark:bg-sky-950/40 dark:text-sky-300"; + case "PUT": + case "PATCH": + return "border-amber-200 bg-amber-50 text-amber-700 dark:border-amber-900/40 dark:bg-amber-950/40 dark:text-amber-300"; + case "DELETE": + return "border-rose-200 bg-rose-50 text-rose-700 dark:border-rose-900/40 dark:bg-rose-950/40 dark:text-rose-300"; + default: + return "border-memBorder-primary bg-surface-default-secondary text-onSurface-default-secondary"; + } +}; + +const getAuthLabel = (authType: string) => { + switch (authType.toLowerCase()) { + case "bearer": + return "JWT"; + case "api_key": + return "API Key"; + case "admin_api_key": + return "Admin Key"; + case "disabled": + return "Disabled"; + default: + return "--"; + } +}; + +const normalizeLog = (entry: ApiRequestLog): RequestLog => { + return { + id: entry.id, + createdAt: entry.created_at, + method: entry.method, + path: entry.path, + statusCode: entry.status_code, + latencyMs: entry.latency_ms, + authType: entry.auth_type, + }; +}; + +export default function RequestsPage() { + const [lastUpdated, setLastUpdated] = useState(null); + const [page, setPage] = useState(0); + + const { + data: logs = [], + isLoading, + error, + refetch, + } = useApiQuery( + async () => { + const res = await api.get(REQUEST_ENDPOINTS.BASE, { + params: { limit: REQUEST_LOG_LIMIT }, + }); + setLastUpdated(new Date().toISOString()); + return (res.data ?? []).map(normalizeLog); + }, + { errorToast: "Failed to load request logs", initialData: [] }, + ); + + const totalRequests = logs.length; + const successfulRequests = logs.filter((log) => log.statusCode < 400).length; + const successRate = + totalRequests > 0 + ? Math.round((successfulRequests / totalRequests) * 100) + : 0; + const averageLatency = + totalRequests > 0 + ? Math.round( + logs.reduce((sum, log) => sum + log.latencyMs, 0) / totalRequests, + ) + : 0; + + const columns = [ + { + key: "createdAt" as keyof RequestLog, + label: "Time", + width: 140, + render: (value: string) => ( + + {formatDistanceToNow(new Date(value), { addSuffix: true })} + + ), + }, + { + key: "method" as keyof RequestLog, + label: "Method", + width: 96, + render: (value: string) => ( + + {value.toUpperCase()} + + ), + }, + { + key: "path" as keyof RequestLog, + label: "Path", + width: 360, + render: (value: string) => ( + + {value} + + ), + }, + { + key: "statusCode" as keyof RequestLog, + label: "Status", + width: 120, + render: (value: number) => ( + + {value} + + ), + }, + { + key: "latencyMs" as keyof RequestLog, + label: "Latency", + width: 100, + render: (value: number) => {value} ms, + }, + { + key: "authType" as keyof RequestLog, + label: "Auth", + width: 120, + render: (value: string) => getAuthLabel(value), + }, + ]; + + return ( +
+
+
+

Requests

+

+ Recent request logs from your self-hosted instance. +

+ {lastUpdated && ( +

+ Last updated{" "} + {formatDistanceToNow(new Date(lastUpdated), { addSuffix: true })} +

+ )} +
+ +
+ +
+ {[ + { label: "Total Requests", value: totalRequests }, + { + label: "Success Rate", + value: totalRequests > 0 ? `${successRate}%` : "--", + }, + { + label: "Avg Latency", + value: totalRequests > 0 ? `${averageLatency} ms` : "--", + }, + ].map((card) => ( + + +

+ {card.label} +

+

{card.value}

+
+
+ ))} +
+ + {error && ( + + + {error} + + + )} + + {isLoading ? ( + + ) : logs.length === 0 ? ( + + ) : ( + <> + + row.id} + /> + + {logs.length > PAGE_SIZE && ( +
+ + {page * PAGE_SIZE + 1}– + {Math.min((page + 1) * PAGE_SIZE, logs.length)} of {logs.length} + +
+ + +
+
+ )} + + )} +
+ ); +} diff --git a/server/dashboard/src/app/(root)/dashboard/settings/page.tsx b/server/dashboard/src/app/(root)/dashboard/settings/page.tsx new file mode 100644 index 000000000..36e61e570 --- /dev/null +++ b/server/dashboard/src/app/(root)/dashboard/settings/page.tsx @@ -0,0 +1,218 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { Sun, Moon, Monitor } from "lucide-react"; +import { useTheme } from "next-themes"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { toast } from "@/components/ui/use-toast"; +import { useAuth } from "@/hooks/use-auth"; +import { getErrorMessage } from "@/lib/error-message"; +import { api } from "@/utils/api"; +import { AUTH_ENDPOINTS } from "@/utils/api-endpoints"; + +export default function SettingsPage() { + const { user, refreshUser } = useAuth(); + const { setTheme } = useTheme(); + + const [name, setName] = useState(""); + const [email, setEmail] = useState(""); + const [savingProfile, setSavingProfile] = useState(false); + + const [currentPassword, setCurrentPassword] = useState(""); + const [newPassword, setNewPassword] = useState(""); + const [confirmPassword, setConfirmPassword] = useState(""); + const [savingPassword, setSavingPassword] = useState(false); + + useEffect(() => { + if (user) { + setName(user.name); + setEmail(user.email); + } + }, [user]); + + const profileDirty = + user !== null && (name !== user.name || email !== user.email); + const profileValid = name.trim().length > 0 && email.trim().length > 0; + + const handleSaveProfile = async () => { + setSavingProfile(true); + try { + await api.patch(AUTH_ENDPOINTS.ME, { + name: name.trim(), + email: email.trim(), + }); + await refreshUser(); + toast({ title: "Profile updated", variant: "success" }); + } catch (error) { + toast({ + title: "Failed to update profile", + description: getErrorMessage(error), + variant: "destructive", + }); + } finally { + setSavingProfile(false); + } + }; + + const handleChangePassword = async () => { + if (newPassword !== confirmPassword) { + toast({ + title: "Passwords don't match", + variant: "destructive", + }); + return; + } + + setSavingPassword(true); + try { + await api.post(AUTH_ENDPOINTS.CHANGE_PASSWORD, { + current_password: currentPassword, + new_password: newPassword, + }); + setCurrentPassword(""); + setNewPassword(""); + setConfirmPassword(""); + toast({ title: "Password updated", variant: "success" }); + } catch (error) { + toast({ + title: "Failed to update password", + description: getErrorMessage(error), + variant: "destructive", + }); + } finally { + setSavingPassword(false); + } + }; + + return ( +
+

Settings

+ + + + Profile + + +
+
+ + setName(e.target.value)} + /> +
+
+ + setEmail(e.target.value)} + /> +
+
+ +
+
+ + + + Password + + +
+ + setCurrentPassword(e.target.value)} + /> +
+
+
+ + setNewPassword(e.target.value)} + placeholder="Min 8 characters" + /> +
+
+ + setConfirmPassword(e.target.value)} + /> +
+
+ +
+
+ + + + Appearance + + +
+ + Theme + + + + +
+
+
+
+ ); +} diff --git a/server/dashboard/src/app/(root)/dashboard/webhooks/page.tsx b/server/dashboard/src/app/(root)/dashboard/webhooks/page.tsx new file mode 100644 index 000000000..25ce6aa5b --- /dev/null +++ b/server/dashboard/src/app/(root)/dashboard/webhooks/page.tsx @@ -0,0 +1,53 @@ +"use client"; + +import { LockedPage } from "@/components/self-hosted/locked-page"; +import { Card, CardContent } from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; +import { Checkbox } from "@/components/ui/checkbox"; +import { Label } from "@/components/ui/label"; +import { Button } from "@/components/ui/button"; + +function WebhooksMockup() { + return ( + + +
+ + +
+
+ +
+ {[ + "memory.created", + "memory.updated", + "memory.deleted", + "search.performed", + ].map((event) => ( +
+ + +
+ ))} +
+
+
+ + +
+ +
+
+ ); +} + +export default function WebhooksPage() { + return ( + } + utmMedium="dashboard-locked-webhooks" + /> + ); +} diff --git a/server/dashboard/src/app/(root)/fonts.tsx b/server/dashboard/src/app/(root)/fonts.tsx new file mode 100644 index 000000000..da850865c --- /dev/null +++ b/server/dashboard/src/app/(root)/fonts.tsx @@ -0,0 +1,86 @@ +import localFont from "next/font/local"; + +export const Inter = localFont({ + src: [ + { + path: "../../../public/fonts/InterVariable.woff2", + weight: "100 900", + style: "normal", + }, + { + path: "../../../public/fonts/InterVariable-Italic.woff2", + weight: "100 900", + style: "italic", + }, + ], + variable: "--font-inter", + display: "swap", +}); + +export const InterDisplay = Inter; + +export const Roboto = localFont({ + src: [ + { + path: "../../../public/fonts/RobotoMono-Regular.ttf", + weight: "400", + style: "normal", + }, + { + path: "../../../public/fonts/RobotoMono-Bold.ttf", + weight: "700", + style: "normal", + }, + ], + variable: "--font-roboto-mono", + display: "swap", +}); + +export const Fustat = localFont({ + src: [ + { + path: "../../../public/fonts/Fustat-VariableFont_wght.ttf", + weight: "200 800", + style: "normal", + }, + ], + variable: "--font-fustat", + display: "swap", +}); + +export const DMMono = localFont({ + src: [ + { + path: "../../../public/fonts/DMMono-Light.ttf", + weight: "300", + style: "normal", + }, + { + path: "../../../public/fonts/DMMono-LightItalic.ttf", + weight: "300", + style: "italic", + }, + { + path: "../../../public/fonts/DMMono-Regular.ttf", + weight: "400", + style: "normal", + }, + { + path: "../../../public/fonts/DMMono-Italic.ttf", + weight: "400", + style: "italic", + }, + { + path: "../../../public/fonts/DMMono-Medium.ttf", + weight: "500", + style: "normal", + }, + { + path: "../../../public/fonts/DMMono-MediumItalic.ttf", + weight: "500", + style: "italic", + }, + ], + variable: "--font-dm-mono", + display: "swap", +}); diff --git a/server/dashboard/src/app/(root)/layout.tsx b/server/dashboard/src/app/(root)/layout.tsx new file mode 100644 index 000000000..97aca07ea --- /dev/null +++ b/server/dashboard/src/app/(root)/layout.tsx @@ -0,0 +1,15 @@ +import { Metadata } from "next"; +import { DashboardClientLayout } from "./dashboard-client-layout"; + +export const metadata: Metadata = { + title: "Dashboard | Mem0", + description: "Mem0 Dashboard", +}; + +export default function DashboardLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return {children}; +} diff --git a/server/dashboard/src/app/api/auth/refresh/route.ts b/server/dashboard/src/app/api/auth/refresh/route.ts new file mode 100644 index 000000000..cc827c41a --- /dev/null +++ b/server/dashboard/src/app/api/auth/refresh/route.ts @@ -0,0 +1,61 @@ +import { cookies } from "next/headers"; +import { NextRequest, NextResponse } from "next/server"; +import { AUTH_ENDPOINTS } from "@/utils/api-endpoints"; +import { getServerApiUrl } from "@/lib/server-api-url"; + +const COOKIE_NAME = "mem0_refresh_token"; +const COOKIE_OPTIONS = { + httpOnly: true, + secure: process.env.NODE_ENV === "production", + sameSite: "lax" as const, + path: "/", + maxAge: 30 * 24 * 60 * 60, // 30 days +}; + +export async function POST() { + const cookieStore = await cookies(); + const refreshToken = cookieStore.get(COOKIE_NAME)?.value; + + if (!refreshToken) { + return NextResponse.json({ error: "No refresh token" }, { status: 401 }); + } + + const res = await fetch(`${getServerApiUrl()}${AUTH_ENDPOINTS.REFRESH}`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ refresh_token: refreshToken }), + }); + + if (!res.ok) { + // Refresh token is invalid β€” clear cookie + cookieStore.delete(COOKIE_NAME); + return NextResponse.json({ error: "Refresh failed" }, { status: 401 }); + } + + const data = await res.json(); + + cookieStore.set(COOKIE_NAME, data.refresh_token, COOKIE_OPTIONS); + + return NextResponse.json({ access_token: data.access_token }); +} + +export async function PUT(request: NextRequest) { + const body = await request.json(); + const cookieStore = await cookies(); + + if (!body.refresh_token) { + return NextResponse.json( + { error: "Missing refresh_token" }, + { status: 400 }, + ); + } + + cookieStore.set(COOKIE_NAME, body.refresh_token, COOKIE_OPTIONS); + return NextResponse.json({ ok: true }); +} + +export async function DELETE() { + const cookieStore = await cookies(); + cookieStore.delete(COOKIE_NAME); + return NextResponse.json({ ok: true }); +} diff --git a/server/dashboard/src/app/api/health/route.ts b/server/dashboard/src/app/api/health/route.ts new file mode 100644 index 000000000..eda4598e3 --- /dev/null +++ b/server/dashboard/src/app/api/health/route.ts @@ -0,0 +1,6 @@ +export const GET = async () => { + return new Response(JSON.stringify({ status: "ok" }), { + status: 200, + headers: { "Content-Type": "application/json" }, + }); +}; diff --git a/server/dashboard/src/app/favicon.ico b/server/dashboard/src/app/favicon.ico new file mode 100644 index 000000000..b4eb2caa8 Binary files /dev/null and b/server/dashboard/src/app/favicon.ico differ diff --git a/server/dashboard/src/app/setup/layout.tsx b/server/dashboard/src/app/setup/layout.tsx new file mode 100644 index 000000000..200fb8835 --- /dev/null +++ b/server/dashboard/src/app/setup/layout.tsx @@ -0,0 +1,42 @@ +import "@/styles/globals.css"; +import { Inter, Fustat, Roboto, DMMono, InterDisplay } from "../(root)/fonts"; +import { cn } from "@/lib/utils"; +import { ThemeProvider } from "@/components/theme-provider"; +import { AuthProvider } from "@/lib/auth"; + +export const metadata = { + title: "Setup | Mem0", + description: "Set up your Mem0 instance", +}; + +export default function SetupLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + + + + {children} + + + + + ); +} diff --git a/server/dashboard/src/app/setup/page.tsx b/server/dashboard/src/app/setup/page.tsx new file mode 100644 index 000000000..ccf69f038 --- /dev/null +++ b/server/dashboard/src/app/setup/page.tsx @@ -0,0 +1,760 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { useRouter } from "next/navigation"; +import { Check, Copy } from "lucide-react"; +import { CopyToClipboard } from "react-copy-to-clipboard"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Card, CardContent } from "@/components/ui/card"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { useAuth } from "@/hooks/use-auth"; +import { getErrorMessage } from "@/lib/error-message"; +import { cn } from "@/lib/utils"; +import { api } from "@/utils/api"; +import { + API_KEY_ENDPOINTS, + AUTH_ENDPOINTS, + MEMORY_ENDPOINTS, +} from "@/utils/api-endpoints"; +import { + buildProviderConfig, + getEffectiveConfig, +} from "@/utils/self-hosted-config"; +import { isValidEmail } from "@/lib/validators"; + +type BundledProviders = { + llm: string[]; + embedder: string[]; +}; + +const STEPS = [ + "Admin Account", + "Providers", + "API Key", + "Use Case", + "Quick Test", +]; +const STEP_TITLES = [ + "Create your admin account", + "Review provider configuration", + "Your API key", + "Tell us your use case", + "Test your setup", +]; +const SUPPORTED_PROVIDERS_URL = + "https://docs.mem0.ai/open-source/setup#supported-providers"; + +const USE_CASE_PRESETS = [ + "Personal assistant", + "Coding agent", + "Customer support", + "Research", + "Therapy / journaling", +]; + +const DEFAULT_TEST_MESSAGE = "I like to hike on weekends."; + +export default function SetupPage() { + const router = useRouter(); + const { register } = useAuth(); + const [step, setStep] = useState(0); + const [isLoading, setIsLoading] = useState(false); + const [isPrefillingConfig, setIsPrefillingConfig] = useState(false); + const [error, setError] = useState(""); + + const [name, setName] = useState(""); + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [confirmPassword, setConfirmPassword] = useState(""); + + const [llmProvider, setLlmProvider] = useState(""); + const [llmModel, setLlmModel] = useState(""); + const [llmApiKey, setLlmApiKey] = useState(""); + const [embedderProvider, setEmbedderProvider] = useState(""); + const [embedderModel, setEmbedderModel] = useState(""); + const [serverHasLlmKey, setServerHasLlmKey] = useState(false); + const [providers, setProviders] = useState(null); + const [initialLlmProvider, setInitialLlmProvider] = useState(""); + const [initialLlmModel, setInitialLlmModel] = useState(""); + const [initialEmbedderProvider, setInitialEmbedderProvider] = useState(""); + const [initialEmbedderModel, setInitialEmbedderModel] = useState(""); + + const [apiKey, setApiKey] = useState(""); + const [keyLabel, setKeyLabel] = useState(""); + const [copied, setCopied] = useState(false); + const [testSuccess, setTestSuccess] = useState(false); + + const [useCase, setUseCase] = useState(""); + const [customInstructions, setCustomInstructions] = useState(""); + const [testMessage, setTestMessage] = useState(DEFAULT_TEST_MESSAGE); + const [isGeneratingInstructions, setIsGeneratingInstructions] = + useState(false); + + const apiUrl = process.env.NEXT_PUBLIC_API_URL || ""; + + useEffect(() => { + if (step !== 1) { + setIsPrefillingConfig(false); + return; + } + + let active = true; + setIsPrefillingConfig(true); + + const loadConfig = async () => { + try { + const [configRes, providersRes] = await Promise.all([ + api.get(MEMORY_ENDPOINTS.CONFIGURE), + api.get(MEMORY_ENDPOINTS.CONFIGURE_PROVIDERS), + ]); + const config = getEffectiveConfig(configRes.data); + + if (!active) { + return; + } + + const llmProv = config?.llm?.provider || ""; + const llmMod = config?.llm?.config?.model || ""; + const embProv = config?.embedder?.provider || ""; + const embMod = config?.embedder?.config?.model || ""; + + setLlmProvider(llmProv); + setLlmModel(llmMod); + setEmbedderProvider(embProv); + setEmbedderModel(embMod); + setInitialLlmProvider(llmProv); + setInitialLlmModel(llmMod); + setInitialEmbedderProvider(embProv); + setInitialEmbedderModel(embMod); + setServerHasLlmKey(!!config?.llm?.config?.api_key); + setProviders(providersRes.data); + } catch (err) { + if (active) { + setError(getErrorMessage(err, "Could not read server configuration")); + } + } finally { + if (active) { + setIsPrefillingConfig(false); + } + } + }; + + void loadConfig(); + + return () => { + active = false; + }; + }, [step]); + + const handleStep1 = async (e: React.FormEvent) => { + e.preventDefault(); + + if (!isValidEmail(email)) { + setError("Enter a valid email address."); + return; + } + + if (password !== confirmPassword) { + setError("Passwords don't match"); + return; + } + + if (password.length < 8) { + setError("Password must be at least 8 characters"); + return; + } + + setError(""); + setIsLoading(true); + + try { + await register(name, email, password); + setStep(1); + } catch (err) { + setError(getErrorMessage(err, "Registration failed")); + } finally { + setIsLoading(false); + } + }; + + const handleStep2 = async (e: React.FormEvent) => { + e.preventDefault(); + setError(""); + + const dirty = + !!llmApiKey || + llmProvider !== initialLlmProvider || + llmModel !== initialLlmModel || + embedderProvider !== initialEmbedderProvider || + embedderModel !== initialEmbedderModel; + + if (!dirty) { + setStep(2); + return; + } + + setIsLoading(true); + try { + const llm = buildProviderConfig({ + provider: llmProvider, + model: llmModel, + apiKey: llmApiKey, + }); + const embedder = buildProviderConfig({ + provider: embedderProvider, + model: embedderModel, + apiKey: + llmApiKey && embedderProvider === llmProvider ? llmApiKey : undefined, + }); + + const payload: Record = { version: "v1.1" }; + if (llm) payload.llm = llm; + if (embedder) payload.embedder = embedder; + + await api.post(MEMORY_ENDPOINTS.CONFIGURE, payload); + if (llmApiKey) setServerHasLlmKey(true); + setLlmApiKey(""); + setInitialLlmProvider(llmProvider); + setInitialLlmModel(llmModel); + setInitialEmbedderProvider(embedderProvider); + setInitialEmbedderModel(embedderModel); + setStep(2); + } catch (err) { + setError(getErrorMessage(err, "Failed to save configuration")); + } finally { + setIsLoading(false); + } + }; + + const handleStep3 = async (e: React.FormEvent) => { + e.preventDefault(); + setError(""); + setIsLoading(true); + + try { + const res = await api.post(API_KEY_ENDPOINTS.BASE, { + label: keyLabel.trim() || "My First Key", + }); + setApiKey(res.data.key); + } catch (err) { + setError(getErrorMessage(err, "Failed to create API key")); + } finally { + setIsLoading(false); + } + }; + + const handleContinueToUseCase = (e: React.FormEvent) => { + e.preventDefault(); + setStep(3); + }; + + const handleContinueToQuickTest = () => { + setError(""); + setStep(4); + }; + + const handleGoToDashboard = (e: React.FormEvent) => { + e.preventDefault(); + router.push("/dashboard/requests"); + }; + + const handleTest = async (e: React.FormEvent) => { + e.preventDefault(); + setError(""); + setIsLoading(true); + + try { + const res = await fetch(`${apiUrl}/memories`, { + method: "POST", + headers: { "Content-Type": "application/json", "X-API-Key": apiKey }, + body: JSON.stringify({ + messages: [{ role: "user", content: testMessage }], + user_id: "setup-test", + }), + }); + + if (!res.ok) { + const body = await res.text(); + let detail = body; + try { + detail = JSON.parse(body).detail ?? body; + } catch {} + throw new Error( + `Test failed (${res.status}): ${detail || res.statusText}`, + ); + } + + setTestSuccess(true); + void api + .post(AUTH_ENDPOINTS.ONBOARDING_COMPLETE, { use_case: useCase }) + .catch(() => {}); + } catch (err) { + setError(getErrorMessage(err, "Test failed")); + } finally { + setIsLoading(false); + } + }; + + return ( +
+
+
+ {STEPS.map((label, i) => ( +
+
+ {i < step ? : i + 1} +
+ {i < STEPS.length - 1 && ( +
+ )} +
+ ))} +
+

+ {STEPS[step]} +

+ + + +
+

+ {STEP_TITLES[step]} +

+ {isPrefillingConfig && step === 1 && ( +

+ Checking server configuration... +

+ )} +
+ {error && ( +

{error}

+ )} + + {step === 0 && ( +
+
+ + setName(e.target.value)} + placeholder="Your name" + /> +
+
+ + setEmail(e.target.value)} + placeholder="admin@company.com" + /> +
+
+ + setPassword(e.target.value)} + placeholder="Min 8 characters" + /> +
+
+ + setConfirmPassword(e.target.value)} + /> +
+ +
+ )} + + {step === 1 && ( +
+ {!serverHasLlmKey && ( +
+

+ No LLM provider API key is configured on the server. Paste + one below to continue β€” it will be saved to the server and + used for all memory operations. +

+
+ )} + +
+
+ + +
+
+ + setLlmModel(e.target.value)} + placeholder="gpt-4.1-nano-2025-04-14" + className="font-mono text-sm" + /> +
+
+ +
+ + setLlmApiKey(e.target.value)} + placeholder={ + serverHasLlmKey + ? "Leave blank to keep existing key" + : "sk-..." + } + className="font-mono text-sm" + /> +

+ Also used for the embedder when it shares the same provider. +

+
+ +
+
+ + +
+
+ + setEmbedderModel(e.target.value)} + placeholder="text-embedding-3-small" + className="font-mono text-sm" + /> +
+
+ +

+ Need another provider? Install its Python package and rebuild + the image. See{" "} + + supported providers + + . +

+ + +
+ )} + + {step === 2 && !apiKey && ( +
+
+ + setKeyLabel(e.target.value)} + placeholder="My First Key" + /> +
+ +
+ )} + + {step === 2 && apiKey && ( +
+
+ +
+ + { + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }} + > + + +
+

+ Save this key. You will not see it again. +

+
+ +
+ )} + + {step === 3 && ( +
+
+ +