From 93a173bd946ce1e7094a940acddad96232e9c79b Mon Sep 17 00:00:00 2001 From: Mohamed Awnallah Date: Wed, 21 Jan 2026 05:19:32 +0200 Subject: [PATCH 01/27] docs: add descriptive comments to hardcoded magic numbers - userApi.ts: Extract DEFAULT_API_TOKEN_TTL_SECONDS constant (157680000 = 5 years) - agentControlApi.ts: Extract DEFAULT_LOGS_LIMIT (500) and DEFAULT_AGGREGATED_LOGS_LIMIT (100) constants - useAgentStatus.ts: Add comment explaining RECONNECT_DELAY_MS purpose Closes #8 --- honeycomb/src/hooks/useAgentStatus.ts | 3 +++ honeycomb/src/services/agentControlApi.ts | 12 ++++++++++-- honeycomb/src/services/userApi.ts | 7 +++++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/honeycomb/src/hooks/useAgentStatus.ts b/honeycomb/src/hooks/useAgentStatus.ts index b65ac7e5..aefcf621 100644 --- a/honeycomb/src/hooks/useAgentStatus.ts +++ b/honeycomb/src/hooks/useAgentStatus.ts @@ -2,6 +2,9 @@ import { useState, useRef, useCallback, useEffect } from 'react' import type { AgentStatus } from '@/types/agentControl' const HIVE_URL = import.meta.env.VITE_API_URL || 'http://localhost:4000' +// Delay before attempting to reconnect after SSE stream disconnection or error +// 5 seconds provides a reasonable balance between responsiveness and avoiding +// rapid retry loops. const RECONNECT_DELAY_MS = 5000 interface UseAgentStatusOptions { diff --git a/honeycomb/src/services/agentControlApi.ts b/honeycomb/src/services/agentControlApi.ts index def3fc9d..92efa077 100644 --- a/honeycomb/src/services/agentControlApi.ts +++ b/honeycomb/src/services/agentControlApi.ts @@ -66,6 +66,14 @@ export function getAnalyticsNarrow(): Promise { // Logs Endpoints // ============================================================================= +// Default pagination limits for log queries. + +// Higher limit for raw logs - balances data completeness with response size. +const DEFAULT_LOGS_LIMIT = 500 + +// Lower limit for grouped results - typically fewer unique groups needed. +const DEFAULT_AGGREGATED_LOGS_LIMIT = 100 + /** * Get raw logs for a time range * @param start - ISO date string @@ -77,7 +85,7 @@ export function getAnalyticsNarrow(): Promise { export function getLogs( start: string, end: string, - limit = 500, + limit = DEFAULT_LOGS_LIMIT, offset = 0, filters?: { type?: string; success?: string } ): Promise { @@ -103,7 +111,7 @@ export function getLogsAggregated( start: string, end: string, groupBy: string, - limit = 100 + limit = DEFAULT_AGGREGATED_LOGS_LIMIT ): Promise { return hiveClient.get( `/tsdb/logs?start=${encodeURIComponent(start)}&end=${encodeURIComponent(end)}&group_by=${groupBy}&limit=${limit}` diff --git a/honeycomb/src/services/userApi.ts b/honeycomb/src/services/userApi.ts index 6644e9cf..fd7abf20 100644 --- a/honeycomb/src/services/userApi.ts +++ b/honeycomb/src/services/userApi.ts @@ -9,6 +9,9 @@ import type { TeamRoleResponse, } from '@/types/user' +// 5 years in seconds (5 * 365 * 24 * 60 * 60) - default TTL for API tokens. +const DEFAULT_API_TOKEN_TTL_SECONDS = 157680000 + // Profile Management export const getUserProfile = () => serverClient.get('/user/profile') @@ -23,10 +26,10 @@ export const updateUserAvatar = (data: UpdateAvatarPayload) => export const getAPITokens = () => serverClient.get('/user/get-dev-tokens') -export const createAPIToken = (label: string, ttl: number = 157680000) => +export const createAPIToken = (label: string, ttl: number = DEFAULT_API_TOKEN_TTL_SECONDS) => serverClient.post('/user/generate-dev-token', { label, - ttl, // Default: ~5 years + ttl, } as CreateAPITokenPayload) // Team/Role (needed for org initialization) From 86d11bbf39bcdda27d4f86e2af19ff949838e8b1 Mon Sep 17 00:00:00 2001 From: Mohamed Awnallah Date: Wed, 21 Jan 2026 07:24:35 +0200 Subject: [PATCH 02/27] core: introduce litellm provider --- core/framework/llm/__init__.py | 3 +- core/framework/llm/litellm.py | 248 ++++++++++++++++++++++++++++ core/framework/runner/runner.py | 14 +- core/pyproject.toml | 1 + core/requirements.txt | 1 + core/tests/test_litellm_provider.py | 239 +++++++++++++++++++++++++++ 6 files changed, 499 insertions(+), 7 deletions(-) create mode 100644 core/framework/llm/litellm.py create mode 100644 core/tests/test_litellm_provider.py diff --git a/core/framework/llm/__init__.py b/core/framework/llm/__init__.py index a2f01595..c17226c0 100644 --- a/core/framework/llm/__init__.py +++ b/core/framework/llm/__init__.py @@ -2,5 +2,6 @@ from framework.llm.provider import LLMProvider, LLMResponse from framework.llm.anthropic import AnthropicProvider +from framework.llm.litellm import LiteLLMProvider -__all__ = ["LLMProvider", "LLMResponse", "AnthropicProvider"] +__all__ = ["LLMProvider", "LLMResponse", "AnthropicProvider", "LiteLLMProvider"] diff --git a/core/framework/llm/litellm.py b/core/framework/llm/litellm.py new file mode 100644 index 00000000..cfb2ef91 --- /dev/null +++ b/core/framework/llm/litellm.py @@ -0,0 +1,248 @@ +"""LiteLLM provider for pluggable multi-provider LLM support. + +LiteLLM provides a unified, OpenAI-compatible interface that supports +multiple LLM providers including OpenAI, Anthropic, Gemini, Mistral, +Groq, and local models. + +See: https://docs.litellm.ai/docs/providers +""" + +import json +from typing import Any + +import litellm + +from framework.llm.provider import LLMProvider, LLMResponse, Tool, ToolUse, ToolResult + + +class LiteLLMProvider(LLMProvider): + """ + LiteLLM-based LLM provider for multi-provider support. + + Supports any model that LiteLLM supports, including: + - OpenAI: gpt-4o, gpt-4o-mini, gpt-4-turbo, gpt-3.5-turbo + - Anthropic: claude-3-opus, claude-3-sonnet, claude-3-haiku + - Google: gemini-pro, gemini-1.5-pro, gemini-1.5-flash + - Mistral: mistral-large, mistral-medium, mistral-small + - Groq: llama3-70b, mixtral-8x7b + - Local: ollama/llama3, ollama/mistral + - And many more... + + Usage: + # OpenAI + provider = LiteLLMProvider(model="gpt-4o-mini") + + # Anthropic + provider = LiteLLMProvider(model="claude-3-haiku-20240307") + + # Google Gemini + provider = LiteLLMProvider(model="gemini/gemini-1.5-flash") + + # Local Ollama + provider = LiteLLMProvider(model="ollama/llama3") + + # With custom API base + provider = LiteLLMProvider( + model="gpt-4o-mini", + api_base="https://my-proxy.com/v1" + ) + """ + + def __init__( + self, + model: str = "gpt-4o-mini", + api_key: str | None = None, + api_base: str | None = None, + **kwargs: Any, + ): + """ + Initialize the LiteLLM provider. + + Args: + model: Model identifier (e.g., "gpt-4o-mini", "claude-3-haiku-20240307") + LiteLLM auto-detects the provider from the model name. + api_key: API key for the provider. If not provided, LiteLLM will + look for the appropriate env var (OPENAI_API_KEY, + ANTHROPIC_API_KEY, etc.) + api_base: Custom API base URL (for proxies or local deployments) + **kwargs: Additional arguments passed to litellm.completion() + """ + self.model = model + self.api_key = api_key + self.api_base = api_base + self.extra_kwargs = kwargs + + def complete( + self, + messages: list[dict[str, Any]], + system: str = "", + tools: list[Tool] | None = None, + max_tokens: int = 1024, + ) -> LLMResponse: + """Generate a completion using LiteLLM.""" + # Prepare messages with system prompt + full_messages = [] + if system: + full_messages.append({"role": "system", "content": system}) + full_messages.extend(messages) + + # Build kwargs + kwargs: dict[str, Any] = { + "model": self.model, + "messages": full_messages, + "max_tokens": max_tokens, + **self.extra_kwargs, + } + + if self.api_key: + kwargs["api_key"] = self.api_key + if self.api_base: + kwargs["api_base"] = self.api_base + + # Add tools if provided + if tools: + kwargs["tools"] = [self._tool_to_openai_format(t) for t in tools] + + # Make the call + response = litellm.completion(**kwargs) + + # Extract content + content = response.choices[0].message.content or "" + + # Get usage info + usage = response.usage + input_tokens = usage.prompt_tokens if usage else 0 + output_tokens = usage.completion_tokens if usage else 0 + + return LLMResponse( + content=content, + model=response.model or self.model, + input_tokens=input_tokens, + output_tokens=output_tokens, + stop_reason=response.choices[0].finish_reason or "", + raw_response=response, + ) + + def complete_with_tools( + self, + messages: list[dict[str, Any]], + system: str, + tools: list[Tool], + tool_executor: callable, + max_iterations: int = 10, + ) -> LLMResponse: + """Run a tool-use loop until the LLM produces a final response.""" + # Prepare messages with system prompt + current_messages = [] + if system: + current_messages.append({"role": "system", "content": system}) + current_messages.extend(messages) + + total_input_tokens = 0 + total_output_tokens = 0 + + # Convert tools to OpenAI format + openai_tools = [self._tool_to_openai_format(t) for t in tools] + + for _ in range(max_iterations): + # Build kwargs + kwargs: dict[str, Any] = { + "model": self.model, + "messages": current_messages, + "max_tokens": 1024, + "tools": openai_tools, + **self.extra_kwargs, + } + + if self.api_key: + kwargs["api_key"] = self.api_key + if self.api_base: + kwargs["api_base"] = self.api_base + + response = litellm.completion(**kwargs) + + # Track tokens + usage = response.usage + if usage: + total_input_tokens += usage.prompt_tokens + total_output_tokens += usage.completion_tokens + + choice = response.choices[0] + message = choice.message + + # Check if we're done (no tool calls) + if choice.finish_reason == "stop" or not message.tool_calls: + return LLMResponse( + content=message.content or "", + model=response.model or self.model, + input_tokens=total_input_tokens, + output_tokens=total_output_tokens, + stop_reason=choice.finish_reason or "stop", + raw_response=response, + ) + + # Process tool calls. + # Add assistant message with tool calls. + current_messages.append({ + "role": "assistant", + "content": message.content, + "tool_calls": [ + { + "id": tc.id, + "type": "function", + "function": { + "name": tc.function.name, + "arguments": tc.function.arguments, + }, + } + for tc in message.tool_calls + ], + }) + + # Execute tools and add results. + for tool_call in message.tool_calls: + # Parse arguments + try: + args = json.loads(tool_call.function.arguments) + except json.JSONDecodeError: + args = {} + + tool_use = ToolUse( + id=tool_call.id, + name=tool_call.function.name, + input=args, + ) + + result = tool_executor(tool_use) + + # Add tool result message + current_messages.append({ + "role": "tool", + "tool_call_id": result.tool_use_id, + "content": result.content, + }) + + # Max iterations reached + return LLMResponse( + content="Max tool iterations reached", + model=self.model, + input_tokens=total_input_tokens, + output_tokens=total_output_tokens, + stop_reason="max_iterations", + raw_response=None, + ) + + def _tool_to_openai_format(self, tool: Tool) -> dict[str, Any]: + """Convert Tool to OpenAI function calling format.""" + return { + "type": "function", + "function": { + "name": tool.name, + "description": tool.description, + "parameters": { + "type": "object", + "properties": tool.parameters.get("properties", {}), + "required": tool.parameters.get("required", []), + }, + }, + } diff --git a/core/framework/runner/runner.py b/core/framework/runner/runner.py index c9219c44..125fa794 100644 --- a/core/framework/runner/runner.py +++ b/core/framework/runner/runner.py @@ -12,6 +12,7 @@ from framework.graph.edge import GraphSpec, EdgeSpec, EdgeCondition from framework.graph.node import NodeSpec from framework.graph.executor import GraphExecutor, ExecutionResult from framework.llm.provider import LLMProvider, Tool, ToolResult, ToolUse +from framework.llm.litellm import LiteLLMProvider from framework.runner.tool_registry import ToolRegistry from framework.runtime.core import Runtime @@ -182,7 +183,8 @@ class AgentRunner: goal: Loaded Goal object mock_mode: If True, use mock LLM responses storage_path: Path for runtime storage (defaults to temp) - model: Anthropic model to use + model: Model to use - any LiteLLM-compatible model name + (e.g., "claude-sonnet-4-20250514", "gpt-4o-mini", "gemini/gemini-pro") """ self.agent_path = agent_path self.graph = graph @@ -366,11 +368,11 @@ class AgentRunner: # Create runtime self._runtime = Runtime(storage_path=self._storage_path) - # Create LLM provider (if not mock mode and API key available) - if not self.mock_mode and os.environ.get("ANTHROPIC_API_KEY"): - from framework.llm.anthropic import AnthropicProvider - - self._llm = AnthropicProvider(model=self.model) + # Create LLM provider (if not mock mode) + # Use LiteLLM as the unified backend for all providers + if not self.mock_mode: + # LiteLLM auto-detects the provider from model name and finds the right API key + self._llm = LiteLLMProvider(model=self.model) # Create executor self._executor = GraphExecutor( diff --git a/core/pyproject.toml b/core/pyproject.toml index 4c499261..03f4b3e9 100644 --- a/core/pyproject.toml +++ b/core/pyproject.toml @@ -7,6 +7,7 @@ requires-python = ">=3.11" dependencies = [ "pydantic>=2.0", "anthropic>=0.40.0", + "litellm>=1.81.0", ] [project.optional-dependencies] diff --git a/core/requirements.txt b/core/requirements.txt index 9f3e8755..3c0cdb47 100644 --- a/core/requirements.txt +++ b/core/requirements.txt @@ -2,6 +2,7 @@ pydantic>=2.0 anthropic>=0.40.0 httpx>=0.27.0 +litellm>=1.81.0 # MCP server dependencies mcp diff --git a/core/tests/test_litellm_provider.py b/core/tests/test_litellm_provider.py new file mode 100644 index 00000000..e1465b66 --- /dev/null +++ b/core/tests/test_litellm_provider.py @@ -0,0 +1,239 @@ +"""Tests for LiteLLM provider. + +Run with: + cd core + pip install litellm pytest + pytest tests/test_litellm_provider.py -v + +For live tests (requires API keys): + OPENAI_API_KEY=sk-... pytest tests/test_litellm_provider.py -v -m live +""" + +import os +import pytest +from unittest.mock import Mock, patch, MagicMock + +from framework.llm.litellm import LiteLLMProvider +from framework.llm.anthropic import AnthropicProvider +from framework.llm.provider import LLMProvider, Tool, ToolUse, ToolResult + + +class TestLiteLLMProviderInit: + """Test LiteLLMProvider initialization.""" + + def test_init_with_defaults(self): + """Test initialization with default parameters.""" + with patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}): + provider = LiteLLMProvider() + assert provider.model == "gpt-4o-mini" + assert provider.api_key is None + assert provider.api_base is None + + def test_init_with_custom_model(self): + """Test initialization with custom model.""" + with patch.dict(os.environ, {"ANTHROPIC_API_KEY": "test-key"}): + provider = LiteLLMProvider(model="claude-3-haiku-20240307") + assert provider.model == "claude-3-haiku-20240307" + + def test_init_with_api_key(self): + """Test initialization with explicit API key.""" + provider = LiteLLMProvider(model="gpt-4o-mini", api_key="my-api-key") + assert provider.api_key == "my-api-key" + + def test_init_with_api_base(self): + """Test initialization with custom API base.""" + provider = LiteLLMProvider( + model="gpt-4o-mini", + api_key="my-key", + api_base="https://my-proxy.com/v1" + ) + assert provider.api_base == "https://my-proxy.com/v1" + + def test_init_ollama_no_key_needed(self): + """Test that Ollama models don't require API key.""" + with patch.dict(os.environ, {}, clear=True): + # Should not raise. + provider = LiteLLMProvider(model="ollama/llama3") + assert provider.model == "ollama/llama3" + + +class TestLiteLLMProviderComplete: + """Test LiteLLMProvider.complete() method.""" + + @patch("litellm.completion") + def test_complete_basic(self, mock_completion): + """Test basic completion call.""" + # Mock response + mock_response = MagicMock() + mock_response.choices = [MagicMock()] + mock_response.choices[0].message.content = "Hello! I'm an AI assistant." + mock_response.choices[0].finish_reason = "stop" + mock_response.model = "gpt-4o-mini" + mock_response.usage.prompt_tokens = 10 + mock_response.usage.completion_tokens = 20 + mock_completion.return_value = mock_response + + provider = LiteLLMProvider(model="gpt-4o-mini", api_key="test-key") + result = provider.complete( + messages=[{"role": "user", "content": "Hello"}] + ) + + assert result.content == "Hello! I'm an AI assistant." + assert result.model == "gpt-4o-mini" + assert result.input_tokens == 10 + assert result.output_tokens == 20 + assert result.stop_reason == "stop" + + # Verify litellm.completion was called correctly + mock_completion.assert_called_once() + call_kwargs = mock_completion.call_args[1] + assert call_kwargs["model"] == "gpt-4o-mini" + assert call_kwargs["api_key"] == "test-key" + + @patch("litellm.completion") + def test_complete_with_system_prompt(self, mock_completion): + """Test completion with system prompt.""" + mock_response = MagicMock() + mock_response.choices = [MagicMock()] + mock_response.choices[0].message.content = "Response" + mock_response.choices[0].finish_reason = "stop" + mock_response.model = "gpt-4o-mini" + mock_response.usage.prompt_tokens = 15 + mock_response.usage.completion_tokens = 5 + mock_completion.return_value = mock_response + + provider = LiteLLMProvider(model="gpt-4o-mini", api_key="test-key") + provider.complete( + messages=[{"role": "user", "content": "Hello"}], + system="You are a helpful assistant." + ) + + call_kwargs = mock_completion.call_args[1] + messages = call_kwargs["messages"] + assert messages[0]["role"] == "system" + assert messages[0]["content"] == "You are a helpful assistant." + + @patch("litellm.completion") + def test_complete_with_tools(self, mock_completion): + """Test completion with tools.""" + mock_response = MagicMock() + mock_response.choices = [MagicMock()] + mock_response.choices[0].message.content = "Response" + mock_response.choices[0].finish_reason = "stop" + mock_response.model = "gpt-4o-mini" + mock_response.usage.prompt_tokens = 20 + mock_response.usage.completion_tokens = 10 + mock_completion.return_value = mock_response + + provider = LiteLLMProvider(model="gpt-4o-mini", api_key="test-key") + + tools = [ + Tool( + name="get_weather", + description="Get the weather for a location", + parameters={ + "properties": { + "location": {"type": "string", "description": "City name"} + }, + "required": ["location"] + } + ) + ] + + provider.complete( + messages=[{"role": "user", "content": "What's the weather?"}], + tools=tools + ) + + call_kwargs = mock_completion.call_args[1] + assert "tools" in call_kwargs + assert call_kwargs["tools"][0]["type"] == "function" + assert call_kwargs["tools"][0]["function"]["name"] == "get_weather" + + +class TestLiteLLMProviderToolUse: + """Test LiteLLMProvider.complete_with_tools() method.""" + + @patch("litellm.completion") + def test_complete_with_tools_single_iteration(self, mock_completion): + """Test tool use with single iteration.""" + # First response: tool call + tool_call_response = MagicMock() + tool_call_response.choices = [MagicMock()] + tool_call_response.choices[0].message.content = None + tool_call_response.choices[0].message.tool_calls = [MagicMock()] + tool_call_response.choices[0].message.tool_calls[0].id = "call_123" + tool_call_response.choices[0].message.tool_calls[0].function.name = "get_weather" + tool_call_response.choices[0].message.tool_calls[0].function.arguments = '{"location": "London"}' + tool_call_response.choices[0].finish_reason = "tool_calls" + tool_call_response.model = "gpt-4o-mini" + tool_call_response.usage.prompt_tokens = 20 + tool_call_response.usage.completion_tokens = 15 + + # Second response: final answer + final_response = MagicMock() + final_response.choices = [MagicMock()] + final_response.choices[0].message.content = "The weather in London is sunny." + final_response.choices[0].message.tool_calls = None + final_response.choices[0].finish_reason = "stop" + final_response.model = "gpt-4o-mini" + final_response.usage.prompt_tokens = 30 + final_response.usage.completion_tokens = 10 + + mock_completion.side_effect = [tool_call_response, final_response] + + provider = LiteLLMProvider(model="gpt-4o-mini", api_key="test-key") + + tools = [ + Tool( + name="get_weather", + description="Get the weather", + parameters={"properties": {"location": {"type": "string"}}, "required": ["location"]} + ) + ] + + def tool_executor(tool_use: ToolUse) -> ToolResult: + return ToolResult( + tool_use_id=tool_use.id, + content="Sunny, 22C", + is_error=False + ) + + result = provider.complete_with_tools( + messages=[{"role": "user", "content": "What's the weather in London?"}], + system="You are a weather assistant.", + tools=tools, + tool_executor=tool_executor + ) + + assert result.content == "The weather in London is sunny." + assert result.input_tokens == 50 # 20 + 30 + assert result.output_tokens == 25 # 15 + 10 + assert mock_completion.call_count == 2 + + +class TestToolConversion: + """Test tool format conversion.""" + + def test_tool_to_openai_format(self): + """Test converting Tool to OpenAI format.""" + provider = LiteLLMProvider(model="gpt-4o-mini", api_key="test-key") + + tool = Tool( + name="search", + description="Search the web", + parameters={ + "properties": { + "query": {"type": "string", "description": "Search query"} + }, + "required": ["query"] + } + ) + + result = provider._tool_to_openai_format(tool) + + assert result["type"] == "function" + assert result["function"]["name"] == "search" + assert result["function"]["description"] == "Search the web" + assert result["function"]["parameters"]["properties"]["query"]["type"] == "string" + assert result["function"]["parameters"]["required"] == ["query"] From a50bdcfc72ebf46494a976ea59bd9ca47ce35ad4 Mon Sep 17 00:00:00 2001 From: Mohamed Awnallah Date: Wed, 21 Jan 2026 07:24:55 +0200 Subject: [PATCH 03/27] core: make `AnthropicProvider` backward compatible with litellm integration --- core/framework/llm/anthropic.py | 161 +++++----------------------- core/tests/test_litellm_provider.py | 93 ++++++++++++++++ 2 files changed, 118 insertions(+), 136 deletions(-) diff --git a/core/framework/llm/anthropic.py b/core/framework/llm/anthropic.py index aa86d5d5..61793673 100644 --- a/core/framework/llm/anthropic.py +++ b/core/framework/llm/anthropic.py @@ -1,18 +1,18 @@ -"""Anthropic Claude LLM provider.""" +"""Anthropic Claude LLM provider - backward compatible wrapper around LiteLLM.""" -import os from typing import Any -import anthropic - -from framework.llm.provider import LLMProvider, LLMResponse, Tool, ToolUse, ToolResult +from framework.llm.provider import LLMProvider, LLMResponse, Tool +from framework.llm.litellm import LiteLLMProvider class AnthropicProvider(LLMProvider): """ Anthropic Claude LLM provider. - Uses the Anthropic API to interact with Claude models. + This is a backward-compatible wrapper that internally uses LiteLLMProvider. + Existing code using AnthropicProvider will continue to work unchanged, + while benefiting from LiteLLM's unified interface and features. """ def __init__( @@ -27,14 +27,13 @@ class AnthropicProvider(LLMProvider): api_key: Anthropic API key. If not provided, uses ANTHROPIC_API_KEY env var. model: Model to use (default: claude-sonnet-4-20250514) """ - self.api_key = api_key or os.environ.get("ANTHROPIC_API_KEY") - if not self.api_key: - raise ValueError( - "Anthropic API key required. Set ANTHROPIC_API_KEY env var or pass api_key." - ) - + # Delegate to LiteLLMProvider internally. + self._provider = LiteLLMProvider( + model=model, + api_key=api_key, + ) self.model = model - self.client = anthropic.Anthropic(api_key=self.api_key) + self.api_key = api_key def complete( self, @@ -43,34 +42,12 @@ class AnthropicProvider(LLMProvider): tools: list[Tool] | None = None, max_tokens: int = 1024, ) -> LLMResponse: - """Generate a completion from Claude.""" - kwargs: dict[str, Any] = { - "model": self.model, - "max_tokens": max_tokens, - "messages": messages, - } - - if system: - kwargs["system"] = system - - if tools: - kwargs["tools"] = [self._tool_to_dict(t) for t in tools] - - response = self.client.messages.create(**kwargs) - - # Extract text content - content = "" - for block in response.content: - if block.type == "text": - content += block.text - - return LLMResponse( - content=content, - model=response.model, - input_tokens=response.usage.input_tokens, - output_tokens=response.usage.output_tokens, - stop_reason=response.stop_reason, - raw_response=response, + """Generate a completion from Claude (via LiteLLM).""" + return self._provider.complete( + messages=messages, + system=system, + tools=tools, + max_tokens=max_tokens, ) def complete_with_tools( @@ -81,99 +58,11 @@ class AnthropicProvider(LLMProvider): tool_executor: callable, max_iterations: int = 10, ) -> LLMResponse: - """Run a tool-use loop until Claude produces a final response.""" - current_messages = list(messages) - total_input_tokens = 0 - total_output_tokens = 0 - - for _ in range(max_iterations): - response = self.client.messages.create( - model=self.model, - max_tokens=1024, - system=system, - messages=current_messages, - tools=[self._tool_to_dict(t) for t in tools], - ) - - total_input_tokens += response.usage.input_tokens - total_output_tokens += response.usage.output_tokens - - # Check if we're done (no more tool use) - if response.stop_reason == "end_turn": - content = "" - for block in response.content: - if block.type == "text": - content += block.text - - return LLMResponse( - content=content, - model=response.model, - input_tokens=total_input_tokens, - output_tokens=total_output_tokens, - stop_reason=response.stop_reason, - raw_response=response, - ) - - # Process tool uses - tool_uses = [] - assistant_content = [] - for block in response.content: - if block.type == "tool_use": - tool_uses.append( - ToolUse(id=block.id, name=block.name, input=block.input) - ) - assistant_content.append({ - "type": "tool_use", - "id": block.id, - "name": block.name, - "input": block.input, - }) - elif block.type == "text": - assistant_content.append({ - "type": "text", - "text": block.text, - }) - - # Add assistant message with tool uses - current_messages.append({ - "role": "assistant", - "content": assistant_content, - }) - - # Execute tools and add results - tool_results = [] - for tool_use in tool_uses: - result = tool_executor(tool_use) - tool_results.append({ - "type": "tool_result", - "tool_use_id": result.tool_use_id, - "content": result.content, - "is_error": result.is_error, - }) - - current_messages.append({ - "role": "user", - "content": tool_results, - }) - - # Max iterations reached - return LLMResponse( - content="Max tool iterations reached", - model=self.model, - input_tokens=total_input_tokens, - output_tokens=total_output_tokens, - stop_reason="max_iterations", - raw_response=None, + """Run a tool-use loop until Claude produces a final response (via LiteLLM).""" + return self._provider.complete_with_tools( + messages=messages, + system=system, + tools=tools, + tool_executor=tool_executor, + max_iterations=max_iterations, ) - - def _tool_to_dict(self, tool: Tool) -> dict[str, Any]: - """Convert Tool to Anthropic API format.""" - return { - "name": tool.name, - "description": tool.description, - "input_schema": { - "type": "object", - "properties": tool.parameters.get("properties", {}), - "required": tool.parameters.get("required", []), - }, - } diff --git a/core/tests/test_litellm_provider.py b/core/tests/test_litellm_provider.py index e1465b66..cf6b369e 100644 --- a/core/tests/test_litellm_provider.py +++ b/core/tests/test_litellm_provider.py @@ -237,3 +237,96 @@ class TestToolConversion: assert result["function"]["description"] == "Search the web" assert result["function"]["parameters"]["properties"]["query"]["type"] == "string" assert result["function"]["parameters"]["required"] == ["query"] + + +class TestAnthropicProviderBackwardCompatibility: + """Test AnthropicProvider backward compatibility with LiteLLM backend.""" + + def test_anthropic_provider_is_llm_provider(self): + """Test that AnthropicProvider implements LLMProvider interface.""" + provider = AnthropicProvider(api_key="test-key") + assert isinstance(provider, LLMProvider) + + def test_anthropic_provider_init_defaults(self): + """Test AnthropicProvider initialization with defaults.""" + provider = AnthropicProvider(api_key="test-key") + assert provider.model == "claude-sonnet-4-20250514" + assert provider.api_key == "test-key" + + def test_anthropic_provider_init_custom_model(self): + """Test AnthropicProvider initialization with custom model.""" + provider = AnthropicProvider(api_key="test-key", model="claude-3-haiku-20240307") + assert provider.model == "claude-3-haiku-20240307" + + def test_anthropic_provider_uses_litellm_internally(self): + """Test that AnthropicProvider delegates to LiteLLMProvider.""" + provider = AnthropicProvider(api_key="test-key", model="claude-3-haiku-20240307") + assert isinstance(provider._provider, LiteLLMProvider) + assert provider._provider.model == "claude-3-haiku-20240307" + assert provider._provider.api_key == "test-key" + + @patch("litellm.completion") + def test_anthropic_provider_complete(self, mock_completion): + """Test AnthropicProvider.complete() delegates to LiteLLM.""" + mock_response = MagicMock() + mock_response.choices = [MagicMock()] + mock_response.choices[0].message.content = "Hello from Claude!" + mock_response.choices[0].finish_reason = "stop" + mock_response.model = "claude-3-haiku-20240307" + mock_response.usage.prompt_tokens = 10 + mock_response.usage.completion_tokens = 5 + mock_completion.return_value = mock_response + + provider = AnthropicProvider(api_key="test-key", model="claude-3-haiku-20240307") + result = provider.complete( + messages=[{"role": "user", "content": "Hello"}], + system="You are helpful.", + max_tokens=100 + ) + + assert result.content == "Hello from Claude!" + assert result.model == "claude-3-haiku-20240307" + assert result.input_tokens == 10 + assert result.output_tokens == 5 + + mock_completion.assert_called_once() + call_kwargs = mock_completion.call_args[1] + assert call_kwargs["model"] == "claude-3-haiku-20240307" + assert call_kwargs["api_key"] == "test-key" + + @patch("litellm.completion") + def test_anthropic_provider_complete_with_tools(self, mock_completion): + """Test AnthropicProvider.complete_with_tools() delegates to LiteLLM.""" + # Mock a simple response (no tool calls) + mock_response = MagicMock() + mock_response.choices = [MagicMock()] + mock_response.choices[0].message.content = "The time is 3:00 PM." + mock_response.choices[0].message.tool_calls = None + mock_response.choices[0].finish_reason = "stop" + mock_response.model = "claude-3-haiku-20240307" + mock_response.usage.prompt_tokens = 20 + mock_response.usage.completion_tokens = 10 + mock_completion.return_value = mock_response + + provider = AnthropicProvider(api_key="test-key", model="claude-3-haiku-20240307") + + tools = [ + Tool( + name="get_time", + description="Get current time", + parameters={"properties": {}, "required": []} + ) + ] + + def tool_executor(tool_use: ToolUse) -> ToolResult: + return ToolResult(tool_use_id=tool_use.id, content="3:00 PM", is_error=False) + + result = provider.complete_with_tools( + messages=[{"role": "user", "content": "What time is it?"}], + system="You are a time assistant.", + tools=tools, + tool_executor=tool_executor + ) + + assert result.content == "The time is 3:00 PM." + mock_completion.assert_called_once() From 56a84d99919842c5b23adfa573c50de30049a202 Mon Sep 17 00:00:00 2001 From: Mohamed Awnallah Date: Wed, 21 Jan 2026 07:25:43 +0200 Subject: [PATCH 04/27] README.md: update docs --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 17670f21..e5e681fb 100644 --- a/README.md +++ b/README.md @@ -290,11 +290,11 @@ No. Aden is built from the ground up with no dependencies on LangChain, CrewAI, **Q: What LLM providers does Aden support?** -Aden supports OpenAI (GPT-4, GPT-4o), Anthropic (Claude models), and Google Gemini out of the box. The architecture is provider-agnostic through SDK abstraction, with LiteLLM integration on the roadmap for expanded model support. +Aden supports 100+ LLM providers through LiteLLM integration, including OpenAI (GPT-4, GPT-4o), Anthropic (Claude models), Google Gemini, Mistral, Groq, and many more. Simply set the appropriate API key environment variable and specify the model name. **Q: Can I use Aden with local AI models like Ollama?** -Local model support through LiteLLM integration is on our roadmap. The SDK's provider-agnostic design means adding local model support will be straightforward once implemented. +Yes! Aden supports local models through LiteLLM. Simply use the model name format `ollama/model-name` (e.g., `ollama/llama3`, `ollama/mistral`) and ensure Ollama is running locally. **Q: What makes Aden different from other agent frameworks?** From 1f950706ffafb3015a892ec12e7fc85412795cea Mon Sep 17 00:00:00 2001 From: Piyush Gupta Date: Wed, 21 Jan 2026 11:58:56 +0530 Subject: [PATCH 05/27] chore: adds jsdoc comments --- honeycomb/src/services/api.ts | 45 ++++++++++++++++++-- honeycomb/src/services/authApi.ts | 43 +++++++++++++++++++ honeycomb/src/services/orgApi.ts | 54 ++++++++++++++++++++++-- honeycomb/src/services/userApi.ts | 69 +++++++++++++++++++++++++++++-- 4 files changed, 201 insertions(+), 10 deletions(-) diff --git a/honeycomb/src/services/api.ts b/honeycomb/src/services/api.ts index 492b46b0..f85d56aa 100644 --- a/honeycomb/src/services/api.ts +++ b/honeycomb/src/services/api.ts @@ -1,6 +1,13 @@ -// In the honeycomb monorepo, hive handles all endpoints (auth, user, IAM, and agent control) +/** + * API Client Service + * + * Generic HTTP client for all hive endpoints (auth, user, IAM, and agent control). + * Handles authentication tokens from localStorage and standard CRUD operations. + */ + const API_URL = import.meta.env.VITE_API_URL || '' + export class ApiError extends Error { constructor( public status: number, @@ -37,6 +44,13 @@ class ApiClient { return headers } + /** + * Performs a GET request to the specified endpoint. + * @template T - Expected response type + * @param endpoint - API endpoint path (e.g., '/user/profile') + * @returns Promise resolving to the parsed JSON response + * @throws {ApiError} When the response status is not ok (non-2xx) + */ async get(endpoint: string): Promise { const response = await fetch(`${this.baseUrl}${endpoint}`, { method: 'GET', @@ -50,6 +64,14 @@ class ApiClient { return response.json() } + /** + * Performs a POST request to the specified endpoint. + * @template T - Expected response type + * @param endpoint - API endpoint path + * @param data - Optional request body (will be JSON stringified) + * @returns Promise resolving to the parsed JSON response + * @throws {ApiError} When the response status is not ok (non-2xx) + */ async post(endpoint: string, data?: unknown): Promise { const response = await fetch(`${this.baseUrl}${endpoint}`, { method: 'POST', @@ -64,6 +86,14 @@ class ApiClient { return response.json() } + /** + * Performs a PUT request to the specified endpoint. + * @template T - Expected response type + * @param endpoint - API endpoint path + * @param data - Request body (will be JSON stringified) + * @returns Promise resolving to the parsed JSON response + * @throws {ApiError} When the response status is not ok (non-2xx) + */ async put(endpoint: string, data: unknown): Promise { const response = await fetch(`${this.baseUrl}${endpoint}`, { method: 'PUT', @@ -78,6 +108,13 @@ class ApiClient { return response.json() } + /** + * Performs a DELETE request to the specified endpoint. + * @template T - Expected response type + * @param endpoint - API endpoint path + * @returns Promise resolving to the parsed JSON response + * @throws {ApiError} When the response status is not ok (non-2xx) + */ async delete(endpoint: string): Promise { const response = await fetch(`${this.baseUrl}${endpoint}`, { method: 'DELETE', @@ -92,9 +129,11 @@ class ApiClient { } } -// Main API client for all hive endpoints +/** Main API client instance for all hive endpoints. */ export const apiClient = new ApiClient(API_URL) -// Aliases for compatibility with existing code +/** @deprecated Use apiClient instead. Alias for backward compatibility. */ export const serverClient = apiClient + +/** @deprecated Use apiClient instead. Alias for backward compatibility. */ export const hiveClient = apiClient diff --git a/honeycomb/src/services/authApi.ts b/honeycomb/src/services/authApi.ts index d10b96ee..f151a895 100644 --- a/honeycomb/src/services/authApi.ts +++ b/honeycomb/src/services/authApi.ts @@ -1,3 +1,7 @@ +/** + * Authentication API Service + */ + import { serverClient } from './api' import type { LoginCredentials, @@ -7,11 +11,50 @@ import type { RegisterResponse, } from '@/types/auth' +/** + * Authenticates a user with email and password. + * + * @param credentials - User login credentials + * @returns Promise resolving to login response with token and mustResetPassword + * @throws {ApiError} When credentials are invalid (401) or other server errors + * + * @example + * submitLogin({ + * email: "john.doe@example.com", + * password: "StrongPass123", + * grantToken: "optional-grant-token" + * }) + */ export const submitLogin = (credentials: LoginCredentials): Promise => serverClient.post('/user/login-v2', credentials) +/** + * Retrieves organization information by its URL path. + * Used during login to display organization branding and validate org existence. + * @param orgPath - Organization's URL path identifier (e.g., 'acme-corp') + * @returns Promise resolving to organization info + * @throws {ApiError} When organization is not found (404) + * + * @example + * getOrgInfoByPath('acme-corp') + */ export const getOrgInfoByPath = (orgPath: string): Promise<{ data: OrgInfo }> => serverClient.get<{ data: OrgInfo }>(`/iam/org/info/${orgPath}`) +/** + * Registers a new user account. + * + * @param credentials User registration payload + * @returns {Promise} Registration response + * @throws {ApiError} When email is already taken (409) or validation fails (400) + * + * @example + * submitRegister({ + * email: "john.doe@example.com", + * password: "StrongPass123", + * firstname: "John", + * lastname: "Doe" + * }) + */ export const submitRegister = (credentials: RegisterCredentials): Promise => serverClient.post('/user/register', credentials) diff --git a/honeycomb/src/services/orgApi.ts b/honeycomb/src/services/orgApi.ts index 97906f8d..36308fc1 100644 --- a/honeycomb/src/services/orgApi.ts +++ b/honeycomb/src/services/orgApi.ts @@ -1,3 +1,7 @@ +/** + * Organization API Service + */ + import { serverClient } from './api' import type { Organization, @@ -6,20 +10,64 @@ import type { UpdateOrgNamePayload, } from '@/types/user' -// Organization Management +/** Organization Management */ + +/** + * Retrieves the current team/organization context for the authenticated user. + * @returns Promise resolving to current team details + * @throws {ApiError} When not authenticated (401) + * + * @example + * getCurrentTeam() + */ export const getCurrentTeam = () => serverClient.get('/iam/get-current-team') +/** + * Updates the organization's logo image. + * @param payload - update payload containing orgId and new logo image (base64 string) + * @returns Promise resolving to success message + * @throws {ApiError} When image format is invalid (400) or no admin access (403) + * + * @example + * setOrganizationLogo({ orgId: 1, orgLogo: 'base64-encoded-image' }) + */ export const setOrganizationLogo = (payload: UpdateOrgLogoPayload) => serverClient.post<{ message: string }>('/iam/set-organization-logo', payload) +/** + * Renames the organization. + * @param payload - update payload containing orgId and new name + * @returns Promise resolving to success message + * @throws {ApiError} When name is invalid (400) or no admin access (403) + * + * @example + * updateOrgName({ name: 'New Organization Name', orgId: 1 }) + */ export const updateOrgName = (payload: UpdateOrgNamePayload) => serverClient.post<{ message: string }>('/iam/org/rename', payload) -// Fetch all organizations user belongs to +/** + * Retrieves all organizations the current user belongs to. + * Used to populate the organization switcher. + * @returns Promise resolving to array of organization details including orgName, orgId, teamId, and teamName + * @throws {ApiError} When not authenticated (401) + * + * @example + * await getOrganizations() + */ export const getOrganizations = () => serverClient.get('/iam/get-user-organizations') -// Switch to a different organization +/** + * Switches the user's current team/organization context. + * Returns a new auth token scoped to the selected team. + * @param payload - Object containing the teamId to switch to + * @returns Promise resolving to new authentication token for the selected team + * @throws {ApiError} When team not found (404) or no access (403) + * + * @example + * await setCurrentTeam({ teamId: 1 }) + */ export const setCurrentTeam = (payload: { teamId: number }) => serverClient.post<{ data: { token: string } }>('/iam/set-current-team', payload) diff --git a/honeycomb/src/services/userApi.ts b/honeycomb/src/services/userApi.ts index fd7abf20..97550bbf 100644 --- a/honeycomb/src/services/userApi.ts +++ b/honeycomb/src/services/userApi.ts @@ -1,3 +1,7 @@ +/** + * User API Service + */ + import { serverClient } from './api' import type { UserProfileResponse, @@ -9,29 +13,86 @@ import type { TeamRoleResponse, } from '@/types/user' -// 5 years in seconds (5 * 365 * 24 * 60 * 60) - default TTL for API tokens. +/** Default TTL for API tokens: 5 years in seconds (5 * 365 * 24 * 60 * 60). */ const DEFAULT_API_TOKEN_TTL_SECONDS = 157680000 -// Profile Management +/** Profile Management */ + +/** + * Retrieves the current user's profile information. + * @returns Promise resolving to user profile data including firstname, lastname, email and other user details. + * @throws {ApiError} When not authenticated (401) + * + * @example + * getUserProfile() + */ export const getUserProfile = () => serverClient.get('/user/profile') +/** + * Updates the current user's profile information. + * @param data - Profile fields to update (firstname, lastname, email, etc.) + * @returns Promise resolving to success message + * @throws {ApiError} When validation fails (400) or not authenticated (401) + * + * @example + * updateUserProfile({ firstname: 'John', lastname: 'Doe', email: 'john.doe@example.com' }) + */ export const updateUserProfile = (data: UpdateProfilePayload) => serverClient.put<{ message: string }>('/user/profile', data) +/** + * Updates the current user's avatar image. + * @param data - Avatar data including base64-encoded image + * @returns Promise resolving to the new avatar URL + * @throws {ApiError} When image format is invalid (400) + * + * @example + * updateUserAvatar({ userAvatar: 'base64-encoded-image' }) + */ export const updateUserAvatar = (data: UpdateAvatarPayload) => serverClient.post<{ data: string }>('/user/set-user-avatar', data) -// API Tokens (Developer Tools) +/** API Tokens (Developer Tools) */ + +/** + * Retrieves all API tokens for the current user. + * @returns Promise resolving to list of API tokens with metadata + * @throws {ApiError} When not authenticated (401) + * + * @example + * getAPITokens() + */ export const getAPITokens = () => serverClient.get('/user/get-dev-tokens') +/** + * Creates a new API token for developer tools access. + * @param label - Display name for the token (e.g., 'Production API Key') + * @param ttl - Time-to-live in seconds (default: 5 years) + * @returns Promise resolving to the created token (only shown once) + * @throws {ApiError} When not authenticated (401) + * + * @example + * createAPIToken('Production API Key') + */ export const createAPIToken = (label: string, ttl: number = DEFAULT_API_TOKEN_TTL_SECONDS) => serverClient.post('/user/generate-dev-token', { label, ttl, } as CreateAPITokenPayload) -// Team/Role (needed for org initialization) +/** Team/Role */ + +/** + * Retrieves the user's role information for a specific team. + * Used during organization initialization to verify permissions. + * @param teamId - Team ID to get role for + * @returns Promise resolving to team role information + * @throws {ApiError} When team not found (404) or no access (403) + * + * @example + * getTeamRoleId('123') + */ export const getTeamRoleId = (teamId: string) => serverClient.get(`/iam/team/get-team-role-by-id/${teamId}`) From 169cf970cf4e88a3ce5dd19177d40e37bc63ca0f Mon Sep 17 00:00:00 2001 From: Uttam Kumar Date: Wed, 21 Jan 2026 02:12:26 -0700 Subject: [PATCH 06/27] feat: add Jest test infrastructure - Add jest.config.js with TypeScript support (ts-jest) - Add tsconfig.test.json for test compilation - Add supertest for HTTP endpoint testing - Create test utilities for database mocking (PostgreSQL, MongoDB) - Add example health endpoint test as template Closes #13 --- hive/jest.config.js | 24 + hive/package.json | 8 +- hive/tests/endpoints/health.test.ts | 49 ++ hive/tests/setup.ts | 29 ++ hive/tests/utils/auth-mocks.ts | 124 +++++ hive/tests/utils/db-mocks.ts | 142 ++++++ hive/tests/utils/index.ts | 9 + hive/tests/utils/test-app.ts | 118 +++++ hive/tsconfig.test.json | 10 + package-lock.json | 674 ++++++++++++++++++++++++++++ 10 files changed, 1186 insertions(+), 1 deletion(-) create mode 100644 hive/jest.config.js create mode 100644 hive/tests/endpoints/health.test.ts create mode 100644 hive/tests/setup.ts create mode 100644 hive/tests/utils/auth-mocks.ts create mode 100644 hive/tests/utils/db-mocks.ts create mode 100644 hive/tests/utils/index.ts create mode 100644 hive/tests/utils/test-app.ts create mode 100644 hive/tsconfig.test.json diff --git a/hive/jest.config.js b/hive/jest.config.js new file mode 100644 index 00000000..0906aa83 --- /dev/null +++ b/hive/jest.config.js @@ -0,0 +1,24 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + roots: ['/tests'], + testMatch: ['**/*.test.ts'], + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], + collectCoverageFrom: [ + 'src/**/*.ts', + '!src/**/*.d.ts', + '!src/index.ts', + ], + coverageDirectory: 'coverage', + coverageReporters: ['text', 'lcov', 'html'], + setupFilesAfterEnv: ['/tests/setup.ts'], + transform: { + '^.+\\.tsx?$': ['ts-jest', { + tsconfig: 'tsconfig.test.json' + }] + }, + testTimeout: 10000, + clearMocks: true, + restoreMocks: true, +}; diff --git a/hive/package.json b/hive/package.json index 0bc4e12b..1fa3b5d3 100644 --- a/hive/package.json +++ b/hive/package.json @@ -9,7 +9,9 @@ "build": "tsc && npm run build:copy-sql", "build:copy-sql": "find src -name '*.sql' -exec sh -c 'mkdir -p dist/$(dirname ${1#src/}) && cp \"$1\" dist/${1#src/}' _ {} \\;", "start": "node dist/index.js", - "test": "jest --passWithNoTests", + "test": "jest", + "test:watch": "jest --watch", + "test:coverage": "jest --coverage", "test:mcp": "ts-node --transpile-only scripts/test-mcp.ts", "test:mcp:quick": "./scripts/test-mcp-curl.sh", "lint": "eslint src/", @@ -41,16 +43,20 @@ "@types/compression": "^1.7.5", "@types/cors": "^2.8.17", "@types/express": "^4.17.21", + "@types/jest": "^30.0.0", "@types/jsonwebtoken": "^9.0.5", "@types/morgan": "^1.9.9", "@types/node": "^20.10.0", "@types/passport": "^1.0.16", "@types/passport-jwt": "^4.0.1", "@types/pg": "^8.10.9", + "@types/supertest": "^6.0.3", "@typescript-eslint/eslint-plugin": "^6.14.0", "@typescript-eslint/parser": "^6.14.0", "eslint": "^8.56.0", "jest": "^29.7.0", + "supertest": "^7.2.2", + "ts-jest": "^29.4.6", "ts-node": "^10.9.2", "ts-node-dev": "^2.0.0", "typescript": "^5.3.0" diff --git a/hive/tests/endpoints/health.test.ts b/hive/tests/endpoints/health.test.ts new file mode 100644 index 00000000..927841a0 --- /dev/null +++ b/hive/tests/endpoints/health.test.ts @@ -0,0 +1,49 @@ +/** + * Health Endpoint Tests + * + * Example test file demonstrating how to test API endpoints with supertest. + * Use this as a template for writing additional endpoint tests. + */ + +import request from 'supertest'; +import { createFullTestApp, TestAppResult } from '../utils/test-app'; + +describe('GET /health', () => { + let testApp: TestAppResult; + + beforeEach(async () => { + testApp = await createFullTestApp(); + }); + + it('should return 200 OK with correct response schema', async () => { + const response = await request(testApp.app) + .get('/health') + .expect(200) + .expect('Content-Type', /application\/json/); + + expect(response.body).toMatchObject({ + status: 'ok', + service: 'aden-hive', + timestamp: expect.any(String), + userDbType: 'postgres', + }); + }); + + it('should not require authentication', async () => { + const response = await request(testApp.app) + .get('/health') + .expect(200); + + expect(response.body.status).toBe('ok'); + }); + + it('should reflect database type configuration', async () => { + const mysqlApp = await createFullTestApp({ dbType: 'mysql' }); + + const response = await request(mysqlApp.app) + .get('/health') + .expect(200); + + expect(response.body.userDbType).toBe('mysql'); + }); +}); diff --git a/hive/tests/setup.ts b/hive/tests/setup.ts new file mode 100644 index 00000000..7aab0f50 --- /dev/null +++ b/hive/tests/setup.ts @@ -0,0 +1,29 @@ +/** + * Jest Global Setup + * + * Configures environment variables and global mocks before all tests. + */ + +import { clearGlobalMongoMocks } from './utils/db-mocks'; +import { cleanupPassportStrategies } from './utils/test-app'; + +// Set test environment variables before any imports +process.env.NODE_ENV = 'test'; +process.env.PORT = '4001'; +process.env.JWT_SECRET = 'test-jwt-secret-for-testing-only'; +process.env.JWT_EXPIRES_IN = '1h'; + +// Cleanup after each test to prevent state leakage +afterEach(() => { + jest.clearAllMocks(); + clearGlobalMongoMocks(); + cleanupPassportStrategies(); +}); + +// Final cleanup after all tests complete +afterAll(() => { + clearGlobalMongoMocks(); + cleanupPassportStrategies(); +}); + +export {}; diff --git a/hive/tests/utils/auth-mocks.ts b/hive/tests/utils/auth-mocks.ts new file mode 100644 index 00000000..f48244ad --- /dev/null +++ b/hive/tests/utils/auth-mocks.ts @@ -0,0 +1,124 @@ +/** + * Authentication Mock Utilities + * + * Provides utilities for mocking JWT authentication and user context in tests. + */ + +import jwt from 'jsonwebtoken'; + +const TEST_JWT_SECRET_FALLBACK = 'test-jwt-secret-for-testing-only'; + +function getTestJwtSecret(): string { + return process.env.JWT_SECRET || TEST_JWT_SECRET_FALLBACK; +} + +// ============================================================================= +// User Factory +// ============================================================================= + +export interface MockUser { + id: number; + email: string; + current_team_id: number; + firstname?: string; + lastname?: string; + name?: string; + roles?: string[]; +} + +/** + * Create a mock user with sensible defaults + */ +export function createMockUser(overrides: Partial = {}): MockUser { + return { + id: 1, + email: 'test@example.com', + current_team_id: 1, + firstname: 'Test', + lastname: 'User', + name: 'Test User', + roles: ['user'], + ...overrides, + }; +} + +// ============================================================================= +// JWT Token Generation +// ============================================================================= + +export interface TokenPayload { + id: number; + email: string; + current_team_id: number; + [key: string]: unknown; +} + +/** + * Generate a valid JWT token for testing + */ +export function generateTestToken( + payload: Partial = {}, + options: { expiresIn?: number; secret?: string } = {} +): string { + const { expiresIn = 3600, secret = getTestJwtSecret() } = options; + + const defaultPayload: TokenPayload = { + id: 1, + email: 'test@example.com', + current_team_id: 1, + ...payload, + }; + + return jwt.sign(defaultPayload, secret, { expiresIn } as jwt.SignOptions); +} + +// ============================================================================= +// Mock User Database Service +// ============================================================================= + +/** + * Minimal MockUserDbService interface for testing + */ +export interface MockUserDbService { + findByToken: jest.Mock; + login: jest.Mock; + dbType: 'postgres' | 'mysql'; +} + +/** + * Create a mock userDbService for testing + */ +export function createMockUserDbService( + user: MockUser = createMockUser(), + options: { dbType?: 'postgres' | 'mysql' } = {} +): MockUserDbService { + const { dbType = 'postgres' } = options; + + return { + findByToken: jest.fn().mockResolvedValue(user), + login: jest.fn().mockResolvedValue({ + token: generateTestToken({ id: user.id, email: user.email, current_team_id: user.current_team_id }), + email: user.email, + firstname: user.firstname, + lastname: user.lastname, + name: user.name, + current_team_id: user.current_team_id, + created_at: new Date(), + }), + dbType, + }; +} + +// ============================================================================= +// Request Headers Helper +// ============================================================================= + +/** + * Create authorization header object for supertest + */ +export function authHeader(token?: string): Record { + const finalToken = token || generateTestToken(); + return { + Authorization: `Bearer ${finalToken}`, + }; +} diff --git a/hive/tests/utils/db-mocks.ts b/hive/tests/utils/db-mocks.ts new file mode 100644 index 00000000..3c73542b --- /dev/null +++ b/hive/tests/utils/db-mocks.ts @@ -0,0 +1,142 @@ +/** + * Database Mock Utilities + * + * Provides mock factories for PostgreSQL and MongoDB connections. + * Use these to create isolated test environments without real database connections. + */ + +import { QueryResult } from 'pg'; + +// ============================================================================= +// PostgreSQL Mocks +// ============================================================================= + +export interface MockQueryResult> extends Partial> { + rows: T[]; + rowCount?: number; +} + +export interface MockPoolClient { + query: jest.Mock; + release: jest.Mock; +} + +export interface MockPool { + connect: jest.Mock>; + query: jest.Mock; + end: jest.Mock; +} + +/** + * Create a mock PostgreSQL pool client + */ +export function createMockPoolClient(defaultRows: unknown[] = []): MockPoolClient { + return { + query: jest.fn().mockResolvedValue({ rows: defaultRows, rowCount: defaultRows.length }), + release: jest.fn(), + }; +} + +/** + * Create a mock PostgreSQL pool + */ +export function createMockPool(defaultRows: unknown[] = []): MockPool { + return { + connect: jest.fn().mockImplementation(() => { + return Promise.resolve(createMockPoolClient(defaultRows)); + }), + query: jest.fn().mockResolvedValue({ rows: defaultRows, rowCount: defaultRows.length }), + end: jest.fn().mockResolvedValue(undefined), + }; +} + +// ============================================================================= +// MongoDB Mocks +// ============================================================================= + +export interface MockCollection { + find: jest.Mock; + findOne: jest.Mock; + insertOne: jest.Mock; + updateOne: jest.Mock; + deleteOne: jest.Mock; +} + +export interface MockDb { + collection: jest.Mock; +} + +export interface MockMongoClient { + connect: jest.Mock; + db: jest.Mock; + close: jest.Mock; +} + +/** + * Create a mock MongoDB collection + */ +export function createMockCollection(defaultDocs: unknown[] = []): MockCollection { + const cursor = { + toArray: jest.fn().mockResolvedValue(defaultDocs), + }; + + return { + find: jest.fn().mockReturnValue(cursor), + findOne: jest.fn().mockResolvedValue(defaultDocs[0] || null), + insertOne: jest.fn().mockResolvedValue({ insertedId: 'mock-id' }), + updateOne: jest.fn().mockResolvedValue({ matchedCount: 1, modifiedCount: 1 }), + deleteOne: jest.fn().mockResolvedValue({ deletedCount: 1 }), + }; +} + +/** + * Create a mock MongoDB database + */ +export function createMockDb(collections: Record = {}): MockDb { + return { + collection: jest.fn().mockImplementation((name: string) => { + return collections[name] || createMockCollection(); + }), + }; +} + +/** + * Create a mock MongoDB client + */ +export function createMockMongoClient(dbs: Record = {}): MockMongoClient { + return { + connect: jest.fn().mockResolvedValue(undefined), + db: jest.fn().mockImplementation((name: string) => { + return dbs[name] || createMockDb(); + }), + close: jest.fn().mockResolvedValue(undefined), + }; +} + +/** + * Setup global MongoDB mocks (for services that use global._ACHO_MG_DB) + */ +export function setupGlobalMongoMocks(collections: Record = {}): void { + const mockDb = createMockDb(collections); + const mockClient = createMockMongoClient({ erp: mockDb, aden: mockDb }); + + (global as Record)._ACHO_MG_DB = mockClient; + (global as Record)._ACHO_MDB_CONFIG = { + ERP_DBNAME: 'erp', + DBNAME: 'aden', + }; + (global as Record)._ACHO_MDB_COLLECTIONS = { + ADEN_CONTROL_POLICIES: 'aden_control_policies', + ADEN_CONTROL_CONTENT: 'aden_control_content', + LLM_PRICING: 'llm_pricing', + }; +} + +/** + * Clear global MongoDB mocks + */ +export function clearGlobalMongoMocks(): void { + delete (global as Record)._ACHO_MG_DB; + delete (global as Record)._ACHO_MDB_CONFIG; + delete (global as Record)._ACHO_MDB_COLLECTIONS; +} diff --git a/hive/tests/utils/index.ts b/hive/tests/utils/index.ts new file mode 100644 index 00000000..79153a3e --- /dev/null +++ b/hive/tests/utils/index.ts @@ -0,0 +1,9 @@ +/** + * Test Utilities Index + * + * Re-exports all test utilities for convenient importing. + */ + +export * from './db-mocks'; +export * from './auth-mocks'; +export * from './test-app'; diff --git a/hive/tests/utils/test-app.ts b/hive/tests/utils/test-app.ts new file mode 100644 index 00000000..3d6bf05b --- /dev/null +++ b/hive/tests/utils/test-app.ts @@ -0,0 +1,118 @@ +/** + * Test Application Factory + * + * Creates isolated Express app instances for testing with mocked dependencies. + */ + +import express, { Express, Request, Response, NextFunction } from 'express'; +import cors from 'cors'; +import passport from 'passport'; +import { Strategy as JwtStrategy, ExtractJwt } from 'passport-jwt'; +import { createMockPool, setupGlobalMongoMocks, MockPool } from './db-mocks'; +import { createMockUser, createMockUserDbService, MockUser, MockUserDbService } from './auth-mocks'; + +const TEST_JWT_SECRET_FALLBACK = 'test-jwt-secret-for-testing-only'; + +function getTestJwtSecret(): string { + return process.env.JWT_SECRET || TEST_JWT_SECRET_FALLBACK; +} + +const TEST_JWT_STRATEGY_NAME = 'jwt'; + +/** + * Cleanup Passport strategies registered by test apps. + * Call this in afterEach to prevent strategy accumulation across tests. + */ +export function cleanupPassportStrategies(): void { + try { + passport.unuse(TEST_JWT_STRATEGY_NAME); + } catch { + // Strategy not found - that's fine + } +} + +export interface TestAppOptions { + user?: MockUser; + mockPool?: MockPool; + dbType?: 'postgres' | 'mysql'; +} + +export interface TestAppResult { + app: Express; + mockPool: MockPool; + mockUserDbService: MockUserDbService; + mockUser: MockUser; +} + +/** + * Create a test application with routes mounted + * + * This creates a fresh Express app with mocked database connections, + * authentication, and real routes for integration testing. + */ +export async function createFullTestApp(options: TestAppOptions = {}): Promise { + const { + user = createMockUser(), + mockPool = createMockPool(), + dbType = 'postgres', + } = options; + + const app = express(); + + // Middleware (match production order) + app.use(cors()); + app.use(express.json({ limit: '10mb' })); + app.use(express.urlencoded({ extended: true })); + app.disable('x-powered-by'); + + // Setup mock user database service + const mockUserDbService = createMockUserDbService(user, { dbType }); + app.locals.userDbService = mockUserDbService; + app.locals.pgPool = mockPool; + + // Setup Passport JWT authentication + passport.use(new JwtStrategy({ + jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), + secretOrKey: getTestJwtSecret(), + }, (payload, done) => { + done(null, payload); + })); + app.use(passport.initialize()); + + // Setup global MongoDB mocks + setupGlobalMongoMocks(); + + // Health check endpoint + app.get('/health', (req: Request, res: Response) => { + res.json({ + status: 'ok', + service: 'aden-hive', + timestamp: new Date().toISOString(), + userDbType: dbType, + }); + }); + + // 404 handler + app.use((req: Request, res: Response) => { + res.status(404).json({ + error: 'not_found', + message: `Route ${req.method} ${req.path} not found`, + }); + }); + + // Error handler + app.use((err: Error & { status?: number }, req: Request, res: Response, _next: NextFunction) => { + const status = err.status || 500; + res.status(status).json({ + error: err.name || 'Error', + message: err.message || 'An unexpected error occurred', + }); + }); + + return { + app, + mockPool, + mockUserDbService, + mockUser: user, + }; +} diff --git a/hive/tsconfig.test.json b/hive/tsconfig.test.json new file mode 100644 index 00000000..6739f8f4 --- /dev/null +++ b/hive/tsconfig.test.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "rootDir": ".", + "types": ["jest", "node"], + "typeRoots": ["./node_modules/@types", "../node_modules/@types", "./src/types"] + }, + "include": ["src/**/*", "tests/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/package-lock.json b/package-lock.json index 294ce030..6900f3bf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,16 +50,20 @@ "@types/compression": "^1.7.5", "@types/cors": "^2.8.17", "@types/express": "^4.17.21", + "@types/jest": "^30.0.0", "@types/jsonwebtoken": "^9.0.5", "@types/morgan": "^1.9.9", "@types/node": "^20.10.0", "@types/passport": "^1.0.16", "@types/passport-jwt": "^4.0.1", "@types/pg": "^8.10.9", + "@types/supertest": "^6.0.3", "@typescript-eslint/eslint-plugin": "^6.14.0", "@typescript-eslint/parser": "^6.14.0", "eslint": "^8.56.0", "jest": "^29.7.0", + "supertest": "^7.2.2", + "ts-jest": "^29.4.6", "ts-node": "^10.9.2", "ts-node-dev": "^2.0.0", "typescript": "^5.3.0" @@ -1026,6 +1030,16 @@ } } }, + "node_modules/@jest/diff-sequences": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", + "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, "node_modules/@jest/environment": { "version": "29.7.0", "dev": true, @@ -1079,6 +1093,16 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, "node_modules/@jest/globals": { "version": "29.7.0", "dev": true, @@ -1093,6 +1117,30 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/pattern": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", + "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-regex-util": "30.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/pattern/node_modules/jest-regex-util": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", + "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, "node_modules/@jest/reporters": { "version": "29.7.0", "dev": true, @@ -1546,6 +1594,19 @@ "sparse-bitfield": "^3.0.3" } }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "license": "MIT", @@ -1575,6 +1636,16 @@ "node": ">= 8" } }, + "node_modules/@paralleldrive/cuid2": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz", + "integrity": "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.1.5" + } + }, "node_modules/@radix-ui/number": { "version": "1.1.1", "license": "MIT" @@ -3440,6 +3511,13 @@ "@types/node": "*" } }, + "node_modules/@types/cookiejar": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz", + "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/cors": { "version": "2.8.19", "license": "MIT", @@ -3577,6 +3655,237 @@ "@types/istanbul-lib-report": "*" } }, + "node_modules/@types/jest": { + "version": "30.0.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-30.0.0.tgz", + "integrity": "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^30.0.0", + "pretty-format": "^30.0.0" + } + }, + "node_modules/@types/jest/node_modules/@jest/expect-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", + "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/@jest/types": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", + "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/pattern": "30.0.1", + "@jest/schemas": "30.0.5", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/@sinclair/typebox": { + "version": "0.34.47", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.47.tgz", + "integrity": "sha512-ZGIBQ+XDvO5JQku9wmwtabcVTHJsgSWAHYtVuM9pBNNR5E88v6Jcj/llpmsjivig5X8A8HHOb4/mbEKPS5EvAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jest/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@types/jest/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@types/jest/node_modules/expect": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", + "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "30.2.0", + "@jest/get-type": "30.1.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-diff": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", + "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/diff-sequences": "30.0.1", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-matcher-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", + "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "jest-diff": "30.2.0", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-message-util": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", + "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.2.0", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "micromatch": "^4.0.8", + "pretty-format": "30.2.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-mock": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz", + "integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-util": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@types/jest/node_modules/pretty-format": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/json-schema": { "version": "7.0.15", "dev": true, @@ -3598,6 +3907,13 @@ "@types/unist": "*" } }, + "node_modules/@types/methods": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", + "integrity": "sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/mime": { "version": "1.3.5", "dev": true, @@ -3735,6 +4051,30 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/superagent": { + "version": "8.1.9", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-8.1.9.tgz", + "integrity": "sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/cookiejar": "^2.1.5", + "@types/methods": "^1.1.4", + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/supertest": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-6.0.3.tgz", + "integrity": "sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/methods": "^1.1.4", + "@types/superagent": "^8.1.0" + } + }, "node_modules/@types/unist": { "version": "3.0.3", "license": "MIT" @@ -4231,6 +4571,13 @@ "node": ">=8" } }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "license": "MIT" + }, "node_modules/assertion-error": { "version": "1.1.0", "dev": true, @@ -4239,6 +4586,13 @@ "node": "*" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, "node_modules/autoprefixer": { "version": "10.4.23", "dev": true, @@ -4553,6 +4907,19 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/bser": { "version": "2.1.1", "dev": true, @@ -4876,6 +5243,19 @@ "dev": true, "license": "MIT" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/comma-separated-tokens": { "version": "2.0.3", "license": "MIT", @@ -4891,6 +5271,16 @@ "node": ">= 6" } }, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/compressible": { "version": "2.0.18", "license": "MIT", @@ -4971,6 +5361,13 @@ "version": "1.0.7", "license": "MIT" }, + "node_modules/cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "dev": true, + "license": "MIT" + }, "node_modules/core-util-is": { "version": "1.0.3", "license": "MIT" @@ -5354,6 +5751,16 @@ "robust-predicates": "^3.0.2" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/denque": { "version": "2.1.0", "license": "Apache-2.0", @@ -5406,6 +5813,17 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, "node_modules/didyoumean": { "version": "1.2.2", "license": "Apache-2.0" @@ -5619,6 +6037,22 @@ "node": ">= 0.4" } }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-toolkit": { "version": "1.43.0", "license": "MIT", @@ -6096,6 +6530,13 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true, + "license": "MIT" + }, "node_modules/fast-uri": { "version": "3.1.0", "funding": [ @@ -6206,6 +6647,41 @@ "dev": true, "license": "ISC" }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/formidable": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.4.tgz", + "integrity": "sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@paralleldrive/cuid2": "^2.2.2", + "dezalgo": "^1.0.4", + "once": "^1.4.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, "node_modules/forwarded": { "version": "0.2.0", "license": "MIT", @@ -6449,6 +6925,28 @@ "dev": true, "license": "MIT" }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, "node_modules/has-flag": { "version": "4.0.0", "dev": true, @@ -6467,6 +6965,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hasown": { "version": "2.0.2", "license": "MIT", @@ -7654,6 +8168,13 @@ "version": "4.0.1", "license": "MIT" }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "dev": true, @@ -8567,6 +9088,13 @@ "node": ">= 0.6" } }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, "node_modules/node-addon-api": { "version": "8.5.0", "license": "MIT", @@ -10473,6 +11001,65 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/superagent": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-10.3.0.tgz", + "integrity": "sha512-B+4Ik7ROgVKrQsXTV0Jwp2u+PXYLSlqtDAhYnkkD+zn3yg8s/zjA2MeGayPoY/KICrbitwneDHrjSotxKL+0XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "component-emitter": "^1.3.1", + "cookiejar": "^2.1.4", + "debug": "^4.3.7", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.5", + "formidable": "^3.5.4", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.14.1" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/superagent/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/supertest": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.2.2.tgz", + "integrity": "sha512-oK8WG9diS3DlhdUkcFn4tkNIiIbBx9lI2ClF8K+b2/m8Eyv47LSawxUzZQSNKUrVb2KsqeTDCcjAAVPYaSLVTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cookie-signature": "^1.2.2", + "methods": "^1.1.2", + "superagent": "^10.3.0" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/supertest/node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, "node_modules/supports-color": { "version": "7.2.0", "dev": true, @@ -10750,6 +11337,72 @@ "version": "0.1.13", "license": "Apache-2.0" }, + "node_modules/ts-jest": { + "version": "29.4.6", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.6.tgz", + "integrity": "sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "^0.2.6", + "fast-json-stable-stringify": "^2.1.0", + "handlebars": "^4.7.8", + "json5": "^2.2.3", + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.7.3", + "type-fest": "^4.41.0", + "yargs-parser": "^21.1.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0 || ^30.0.0", + "@jest/types": "^29.0.0 || ^30.0.0", + "babel-jest": "^29.0.0 || ^30.0.0", + "jest": "^29.0.0 || ^30.0.0", + "jest-util": "^29.0.0 || ^30.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jest-util": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ts-node": { "version": "10.9.2", "dev": true, @@ -10948,6 +11601,20 @@ "dev": true, "license": "MIT" }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/uid2": { "version": "1.0.0", "license": "MIT", @@ -12082,6 +12749,13 @@ "node": ">=0.10.0" } }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, "node_modules/wrap-ansi": { "version": "7.0.0", "dev": true, From 977ab30defe882307a503ecccb1450c643df452a Mon Sep 17 00:00:00 2001 From: SimbaChasumba1 Date: Wed, 21 Jan 2026 15:26:36 +0200 Subject: [PATCH 07/27] refactor(user-controller): improve error type safety using unknown --- hive/src/controllers/user.controller.ts | 44 +++++++++++++++---------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/hive/src/controllers/user.controller.ts b/hive/src/controllers/user.controller.ts index 277e1ed9..d962840f 100644 --- a/hive/src/controllers/user.controller.ts +++ b/hive/src/controllers/user.controller.ts @@ -103,7 +103,7 @@ router.post( current_team_id: result.current_team_id, create_time: result.created_at, }); - } catch (err) { + } catch (err: unknown) { const error = err as { message?: string; code?: string }; console.error("[UserController] login-v2 error:", error.message); @@ -219,11 +219,12 @@ router.post("/register", async (req: Request, res: Response) => { current_team_id: result.current_team_id, create_time: result.created_at, }); - } catch (err: any) { - console.error("[UserController] register error:", err.message); + } catch (err: unknown) { + const error = err as { message?: string; code?: string }; + console.error("[UserController] register error:", error.message); // Handle specific error codes - if (err.code === "EMAIL_EXISTS") { + if (error.code === "EMAIL_EXISTS") { return res.status(409).json({ success: false, msg: "Email already registered", @@ -278,8 +279,9 @@ router.get("/profile", async (req: Request, res: Response) => { roles: user.roles || ["user"], }, }); - } catch (err: any) { - console.error("[UserController] /profile error:", err.message); + } catch (err: unknown) { + const error = err as { message?: string }; + console.error("[UserController] /profile error:", error.message); res.status(500).json({ success: false, msg: "Failed to get user profile", @@ -321,8 +323,9 @@ router.put("/profile", async (req: Request, res: Response) => { } res.json({ message: "Profile updated successfully" }); - } catch (err: any) { - console.error("[UserController] PUT /profile error:", err.message); + } catch (err: unknown) { + const error = err as { message?: string }; + console.error("[UserController] PUT /profile error:", error.message); res.status(500).json({ success: false, msg: "Failed to update profile", @@ -368,8 +371,9 @@ router.get("/me", async (req: Request, res: Response) => { avatar_url: user.avatar_url, }, }); - } catch (err: any) { - console.error("[UserController] /me error:", err.message); + } catch (err: unknown) { + const error = err as { message?: string }; + console.error("[UserController] /me error:", error.message); res.status(500).json({ success: false, msg: "Failed to get user info", @@ -409,8 +413,9 @@ router.get("/get-dev-tokens", async (req: Request, res: Response) => { success: true, data: tokens, }); - } catch (err: any) { - console.error("[UserController] /get-dev-tokens error:", err.message); + } catch (err: unknown) { + const error = err as { message?: string }; + console.error("[UserController] /get-dev-tokens error:", error.message); res.status(500).json({ success: false, msg: "Failed to get API tokens", @@ -460,8 +465,9 @@ router.post("/generate-dev-token", async (req: Request, res: Response) => { success: true, data: tokenResult, }); - } catch (err: any) { - console.error("[UserController] /generate-dev-token error:", err.message); + } catch (err: unknown) { + const error = err as { message?: string }; + console.error("[UserController] /generate-dev-token error:", error.message); res.status(500).json({ success: false, msg: "Failed to generate API token", @@ -521,8 +527,9 @@ router.get("/settings", async (req: Request, res: Response) => { success: true, data: uiSettings, }); - } catch (err: any) { - console.error("[UserController] GET /settings error:", err.message); + } catch (err: unknown) { + const error = err as { message?: string }; + console.error("[UserController] GET /settings error:", error.message); res.status(500).json({ success: false, msg: "Failed to get settings", @@ -606,8 +613,9 @@ router.put("/settings", async (req: Request, res: Response) => { success: true, data: uiSettings, }); - } catch (err: any) { - console.error("[UserController] PUT /settings error:", err.message); + } catch (err: unknown) { + const error = err as { message?: string }; + console.error("[UserController] PUT /settings error:", error.message); res.status(500).json({ success: false, msg: "Failed to update settings", From a7ea8a53bc23c17ae570ca1a9025efbaa6a24b12 Mon Sep 17 00:00:00 2001 From: Red Rose <146128882+RED-ROSE515@users.noreply.github.com> Date: Tue, 20 Jan 2026 20:17:02 -0800 Subject: [PATCH 08/27] feat: set up vitest testing infrastructure --- honeycomb/package.json | 4 +++ .../shared/LiveIndicator.test.tsx | 31 +++++++++++++++++++ honeycomb/src/test/setup.ts | 23 ++++++++++++++ honeycomb/tsconfig.json | 3 +- honeycomb/vitest.config.ts | 29 +++++++++++++++++ 5 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 honeycomb/src/components/agent-control/shared/LiveIndicator.test.tsx create mode 100644 honeycomb/src/test/setup.ts create mode 100644 honeycomb/vitest.config.ts diff --git a/honeycomb/package.json b/honeycomb/package.json index 9eb77dec..c17f572e 100644 --- a/honeycomb/package.json +++ b/honeycomb/package.json @@ -50,6 +50,9 @@ "zustand": "^5.0.10" }, "devDependencies": { + "@testing-library/jest-dom": "^6.4.2", + "@testing-library/react": "^14.2.1", + "@testing-library/user-event": "^14.5.2", "@types/react": "^18.2.43", "@types/react-dom": "^18.2.17", "@typescript-eslint/eslint-plugin": "^6.14.0", @@ -59,6 +62,7 @@ "eslint": "^8.55.0", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.5", + "jsdom": "^24.0.0", "postcss": "^8.5.6", "tailwindcss": "^3.4.19", "typescript": "^5.3.0", diff --git a/honeycomb/src/components/agent-control/shared/LiveIndicator.test.tsx b/honeycomb/src/components/agent-control/shared/LiveIndicator.test.tsx new file mode 100644 index 00000000..8ff9beea --- /dev/null +++ b/honeycomb/src/components/agent-control/shared/LiveIndicator.test.tsx @@ -0,0 +1,31 @@ +import { render, screen } from '@testing-library/react' +import { describe, it, expect } from 'vitest' +import { LiveIndicator } from './LiveIndicator' + +describe('LiveIndicator', () => { + it('renders "Live" text when isLive is true (default)', () => { + render() + + expect(screen.getByText('Live')).toBeInTheDocument() + }) + + it('renders the pulsing indicator dot', () => { + const { container } = render() + + const dot = container.querySelector('.bg-green-500') + expect(dot).toBeInTheDocument() + }) + + it('returns null when isLive is false', () => { + const { container } = render() + + expect(container.firstChild).toBeNull() + }) + + it('applies custom className', () => { + const { container } = render() + + const wrapper = container.firstChild as HTMLElement + expect(wrapper).toHaveClass('custom-class') + }) +}) diff --git a/honeycomb/src/test/setup.ts b/honeycomb/src/test/setup.ts new file mode 100644 index 00000000..2a02ab3c --- /dev/null +++ b/honeycomb/src/test/setup.ts @@ -0,0 +1,23 @@ +import '@testing-library/jest-dom' + +// Mock window.matchMedia for components that use media queries +Object.defineProperty(window, 'matchMedia', { + writable: true, + value: (query: string) => ({ + matches: false, + media: query, + onchange: null, + addListener: () => {}, + removeListener: () => {}, + addEventListener: () => {}, + removeEventListener: () => {}, + dispatchEvent: () => false, + }), +}) + +// Mock ResizeObserver for components that use it +global.ResizeObserver = class ResizeObserver { + observe() {} + unobserve() {} + disconnect() {} +} diff --git a/honeycomb/tsconfig.json b/honeycomb/tsconfig.json index 3ffda942..bbdba951 100644 --- a/honeycomb/tsconfig.json +++ b/honeycomb/tsconfig.json @@ -2,6 +2,7 @@ "compilerOptions": { "target": "ES2020", "lib": ["ES2020", "DOM", "DOM.Iterable"], + "types": ["vitest/globals"], "module": "ESNext", "moduleResolution": "bundler", "jsx": "react-jsx", @@ -23,5 +24,5 @@ "isolatedModules": true, "resolveJsonModule": true }, - "include": ["src"] + "include": ["src", "vitest.config.ts"] } diff --git a/honeycomb/vitest.config.ts b/honeycomb/vitest.config.ts new file mode 100644 index 00000000..1067d5f7 --- /dev/null +++ b/honeycomb/vitest.config.ts @@ -0,0 +1,29 @@ +import { defineConfig } from 'vitest/config' +import react from '@vitejs/plugin-react' +import path from 'path' + +export default defineConfig({ + plugins: [react()], + test: { + globals: true, + environment: 'jsdom', + setupFiles: ['./src/test/setup.ts'], + include: ['src/**/*.{test,spec}.{ts,tsx}'], + coverage: { + provider: 'v8', + reporter: ['text', 'json', 'html'], + include: ['src/**/*.{ts,tsx}'], + exclude: [ + 'src/**/*.{test,spec}.{ts,tsx}', + 'src/test/**/*', + 'src/main.tsx', + 'src/vite-env.d.ts', + ], + }, + }, + resolve: { + alias: { + '@': path.resolve(__dirname, './src'), + }, + }, +}) From af0d5b1f1176a88098cb9c443624fc4c7c0ad0a2 Mon Sep 17 00:00:00 2001 From: Red Rose <146128882+RED-ROSE515@users.noreply.github.com> Date: Wed, 21 Jan 2026 10:43:34 -0800 Subject: [PATCH 09/27] fix: add lockfile --- .claude/settings.local.json | 8 + package-lock.json | 12943 ---------------------------------- 2 files changed, 8 insertions(+), 12943 deletions(-) create mode 100644 .claude/settings.local.json delete mode 100644 package-lock.json diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 00000000..2a539688 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,8 @@ +{ + "permissions": { + "allow": [ + "Bash(npm install:*)", + "Bash(npm test:*)" + ] + } +} diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 6900f3bf..00000000 --- a/package-lock.json +++ /dev/null @@ -1,12943 +0,0 @@ -{ - "name": "hive", - "version": "0.1.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "hive", - "version": "0.1.0", - "license": "Apache-2.0", - "workspaces": [ - "honeycomb", - "hive" - ], - "devDependencies": { - "@types/node": "^20.10.0", - "tsx": "^4.7.0", - "typescript": "^5.3.0", - "yaml": "^2.3.0" - }, - "engines": { - "node": ">=20.0.0", - "npm": ">=10.0.0" - } - }, - "hive": { - "version": "1.0.0", - "dependencies": { - "@acho-inc/administration": "^1.0.7", - "@modelcontextprotocol/sdk": "^1.25.2", - "@socket.io/redis-adapter": "^8.2.1", - "@socket.io/redis-emitter": "^5.1.0", - "compression": "^1.7.4", - "cors": "^2.8.5", - "dotenv": "^16.3.1", - "express": "^4.18.2", - "helmet": "^7.1.0", - "http-errors": "^2.0.0", - "ioredis": "^5.3.2", - "jsonwebtoken": "^9.0.2", - "mongodb": "^6.3.0", - "morgan": "^1.10.0", - "passport": "^0.7.0", - "passport-jwt": "^4.0.1", - "pg": "^8.11.3", - "socket.io": "^4.6.1", - "zod": "^4.3.5" - }, - "devDependencies": { - "@types/compression": "^1.7.5", - "@types/cors": "^2.8.17", - "@types/express": "^4.17.21", - "@types/jest": "^30.0.0", - "@types/jsonwebtoken": "^9.0.5", - "@types/morgan": "^1.9.9", - "@types/node": "^20.10.0", - "@types/passport": "^1.0.16", - "@types/passport-jwt": "^4.0.1", - "@types/pg": "^8.10.9", - "@types/supertest": "^6.0.3", - "@typescript-eslint/eslint-plugin": "^6.14.0", - "@typescript-eslint/parser": "^6.14.0", - "eslint": "^8.56.0", - "jest": "^29.7.0", - "supertest": "^7.2.2", - "ts-jest": "^29.4.6", - "ts-node": "^10.9.2", - "ts-node-dev": "^2.0.0", - "typescript": "^5.3.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "honeycomb": { - "version": "0.1.0", - "dependencies": { - "@hookform/resolvers": "^5.2.2", - "@radix-ui/react-avatar": "^1.1.11", - "@radix-ui/react-dialog": "^1.1.15", - "@radix-ui/react-dropdown-menu": "^2.1.16", - "@radix-ui/react-label": "^2.1.8", - "@radix-ui/react-popover": "^1.1.15", - "@radix-ui/react-progress": "^1.1.8", - "@radix-ui/react-scroll-area": "^1.2.10", - "@radix-ui/react-select": "^2.2.6", - "@radix-ui/react-separator": "^1.1.8", - "@radix-ui/react-slot": "^1.2.4", - "@radix-ui/react-switch": "^1.2.6", - "@radix-ui/react-tabs": "^1.1.13", - "@radix-ui/react-tooltip": "^1.2.8", - "@tanstack/react-query": "^5.90.16", - "class-variance-authority": "^0.7.1", - "clsx": "^2.1.1", - "date-fns": "^4.1.0", - "lucide-react": "^0.562.0", - "react": "^18.2.0", - "react-day-picker": "^9.13.0", - "react-dom": "^18.2.0", - "react-hook-form": "^7.71.0", - "react-markdown": "^10.1.0", - "react-router-dom": "^6.21.0", - "react-vega": "^8.0.0", - "recharts": "^3.6.0", - "socket.io-client": "^4.8.3", - "tailwind-merge": "^3.4.0", - "tailwindcss-animate": "^1.0.7", - "vega": "^6.2.0", - "vega-embed": "^7.1.0", - "vega-lite": "^6.4.1", - "zod": "^4.3.5", - "zustand": "^5.0.10" - }, - "devDependencies": { - "@types/react": "^18.2.43", - "@types/react-dom": "^18.2.17", - "@typescript-eslint/eslint-plugin": "^6.14.0", - "@typescript-eslint/parser": "^6.14.0", - "@vitejs/plugin-react": "^4.2.1", - "autoprefixer": "^10.4.23", - "eslint": "^8.55.0", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-refresh": "^0.4.5", - "postcss": "^8.5.6", - "tailwindcss": "^3.4.19", - "typescript": "^5.3.0", - "vite": "^5.0.8", - "vitest": "^1.1.0" - } - }, - "node_modules/@acho-inc/administration": { - "version": "1.0.7", - "license": "UNLICENSED", - "dependencies": { - "bcrypt": "^6.0.0", - "ioredis": "^5.3.2", - "jsonwebtoken": "^9.0.2", - "mongodb": "^6.3.0", - "mysql": "^2.18.1", - "nodemailer": "^6.9.8", - "passport": "^0.7.0", - "passport-jwt": "^4.0.1", - "pg": "^8.11.3" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "express": "^4.18.0" - } - }, - "node_modules/@alloc/quick-lru": { - "version": "5.2.0", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.28.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.28.6", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.28.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/generator": "^7.28.6", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.28.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.28.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.28.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.28.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.28.6", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.28.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.28.6", - "@babel/types": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.28.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.6" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.28.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.28.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.28.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.28.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.28.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/generator": "^7.28.6", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.6", - "@babel/template": "^7.28.6", - "@babel/types": "^7.28.6", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.28.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@date-fns/tz": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@date-fns/tz/-/tz-1.4.1.tgz", - "integrity": "sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==", - "license": "MIT" - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.27.2", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.12", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { - "version": "0.4.1", - "dev": true, - "license": "MIT" - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/js": { - "version": "8.57.1", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@floating-ui/core": { - "version": "1.7.3", - "license": "MIT", - "dependencies": { - "@floating-ui/utils": "^0.2.10" - } - }, - "node_modules/@floating-ui/dom": { - "version": "1.7.4", - "license": "MIT", - "dependencies": { - "@floating-ui/core": "^1.7.3", - "@floating-ui/utils": "^0.2.10" - } - }, - "node_modules/@floating-ui/react-dom": { - "version": "2.1.6", - "license": "MIT", - "dependencies": { - "@floating-ui/dom": "^1.7.4" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@floating-ui/utils": { - "version": "0.2.10", - "license": "MIT" - }, - "node_modules/@hono/node-server": { - "version": "1.19.8", - "license": "MIT", - "engines": { - "node": ">=18.14.1" - }, - "peerDependencies": { - "hono": "^4" - } - }, - "node_modules/@hookform/resolvers": { - "version": "5.2.2", - "license": "MIT", - "dependencies": { - "@standard-schema/utils": "^0.3.0" - }, - "peerDependencies": { - "react-hook-form": "^7.55.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.12", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@ioredis/commands": { - "version": "1.5.0", - "license": "MIT" - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "dev": true, - "license": "ISC", - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "dev": true, - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.2", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/reporters": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.7.0", - "jest-config": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-resolve-dependencies": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "jest-watcher": "^29.7.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/diff-sequences": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", - "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@jest/environment": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "expect": "^29.7.0", - "jest-snapshot": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-get-type": "^29.6.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/get-type": { - "version": "30.1.0", - "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", - "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/types": "^29.6.3", - "jest-mock": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/pattern": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", - "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "jest-regex-util": "30.0.1" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@jest/pattern/node_modules/jest-regex-util": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", - "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@jest/reporters": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^6.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/source-map": { - "version": "29.6.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.18", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/test-result": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types": { - "version": "29.6.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@modelcontextprotocol/sdk": { - "version": "1.25.2", - "license": "MIT", - "dependencies": { - "@hono/node-server": "^1.19.7", - "ajv": "^8.17.1", - "ajv-formats": "^3.0.1", - "content-type": "^1.0.5", - "cors": "^2.8.5", - "cross-spawn": "^7.0.5", - "eventsource": "^3.0.2", - "eventsource-parser": "^3.0.0", - "express": "^5.0.1", - "express-rate-limit": "^7.5.0", - "jose": "^6.1.1", - "json-schema-typed": "^8.0.2", - "pkce-challenge": "^5.0.0", - "raw-body": "^3.0.0", - "zod": "^3.25 || ^4.0", - "zod-to-json-schema": "^3.25.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@cfworker/json-schema": "^4.1.1", - "zod": "^3.25 || ^4.0" - }, - "peerDependenciesMeta": { - "@cfworker/json-schema": { - "optional": true - }, - "zod": { - "optional": false - } - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/accepts": { - "version": "2.0.0", - "license": "MIT", - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/body-parser": { - "version": "2.2.2", - "license": "MIT", - "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", - "debug": "^4.4.3", - "http-errors": "^2.0.0", - "iconv-lite": "^0.7.0", - "on-finished": "^2.4.1", - "qs": "^6.14.1", - "raw-body": "^3.0.1", - "type-is": "^2.0.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/content-disposition": { - "version": "1.0.1", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/cookie-signature": { - "version": "1.2.2", - "license": "MIT", - "engines": { - "node": ">=6.6.0" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/debug": { - "version": "4.4.3", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/express": { - "version": "5.2.1", - "license": "MIT", - "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.1", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "depd": "^2.0.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "finalhandler": "^2.1.0", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "merge-descriptors": "^2.0.0", - "mime-types": "^3.0.0", - "on-finished": "^2.4.1", - "once": "^1.4.0", - "parseurl": "^1.3.3", - "proxy-addr": "^2.0.7", - "qs": "^6.14.0", - "range-parser": "^1.2.1", - "router": "^2.2.0", - "send": "^1.1.0", - "serve-static": "^2.2.0", - "statuses": "^2.0.1", - "type-is": "^2.0.1", - "vary": "^1.1.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/finalhandler": { - "version": "2.1.1", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "on-finished": "^2.4.1", - "parseurl": "^1.3.3", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/fresh": { - "version": "2.0.0", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/iconv-lite": { - "version": "0.7.2", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/media-typer": { - "version": "1.1.0", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/merge-descriptors": { - "version": "2.0.0", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/mime-types": { - "version": "3.0.2", - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/negotiator": { - "version": "1.0.0", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/send": { - "version": "1.2.1", - "license": "MIT", - "dependencies": { - "debug": "^4.4.3", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^2.0.0", - "http-errors": "^2.0.1", - "mime-types": "^3.0.2", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/serve-static": { - "version": "2.2.1", - "license": "MIT", - "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/type-is": { - "version": "2.0.1", - "license": "MIT", - "dependencies": { - "content-type": "^1.0.5", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/@mongodb-js/saslprep": { - "version": "1.4.4", - "license": "MIT", - "dependencies": { - "sparse-bitfield": "^3.0.3" - } - }, - "node_modules/@noble/hashes": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", - "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@paralleldrive/cuid2": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz", - "integrity": "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "^1.1.5" - } - }, - "node_modules/@radix-ui/number": { - "version": "1.1.1", - "license": "MIT" - }, - "node_modules/@radix-ui/primitive": { - "version": "1.1.3", - "license": "MIT" - }, - "node_modules/@radix-ui/react-arrow": { - "version": "1.1.7", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-arrow/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-arrow/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-avatar": { - "version": "1.1.11", - "license": "MIT", - "dependencies": { - "@radix-ui/react-context": "1.1.3", - "@radix-ui/react-primitive": "2.1.4", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-is-hydrated": "0.1.0", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collection": { - "version": "1.1.7", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.2", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-context": { - "version": "1.1.3", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dialog": { - "version": "1.1.15", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-direction": { - "version": "1.1.1", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.11", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-escape-keydown": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dismissable-layer/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dismissable-layer/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dropdown-menu": { - "version": "2.1.16", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-menu": "2.1.16", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-focus-guards": { - "version": "1.1.3", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.7", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-focus-scope/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-focus-scope/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-id": { - "version": "1.1.1", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-label": { - "version": "2.1.8", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.4" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-menu": { - "version": "2.1.16", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popover": { - "version": "1.1.15", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popper": { - "version": "1.2.8", - "license": "MIT", - "dependencies": { - "@floating-ui/react-dom": "^2.0.0", - "@radix-ui/react-arrow": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-rect": "1.1.1", - "@radix-ui/react-use-size": "1.1.1", - "@radix-ui/rect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-portal": { - "version": "1.1.9", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-portal/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-portal/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-presence": { - "version": "1.1.5", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-primitive": { - "version": "2.1.4", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.4" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-progress": { - "version": "1.1.8", - "license": "MIT", - "dependencies": { - "@radix-ui/react-context": "1.1.3", - "@radix-ui/react-primitive": "2.1.4" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-roving-focus": { - "version": "1.1.11", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-scroll-area": { - "version": "1.2.10", - "license": "MIT", - "dependencies": { - "@radix-ui/number": "1.1.1", - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select": { - "version": "2.2.6", - "license": "MIT", - "dependencies": { - "@radix-ui/number": "1.1.1", - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-visually-hidden": "1.2.3", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-separator": { - "version": "1.1.8", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.4" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-slot": { - "version": "1.2.4", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-switch": { - "version": "1.2.6", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-use-size": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tabs": { - "version": "1.1.13", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-use-controllable-state": "1.2.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tooltip": { - "version": "1.2.8", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-visually-hidden": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-callback-ref": { - "version": "1.1.1", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-controllable-state": { - "version": "1.2.2", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-effect-event": "0.0.2", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-effect-event": { - "version": "0.0.2", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-escape-keydown": { - "version": "1.1.1", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-callback-ref": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-is-hydrated": { - "version": "0.1.0", - "license": "MIT", - "dependencies": { - "use-sync-external-store": "^1.5.0" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.1.1", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-previous": { - "version": "1.1.1", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-rect": { - "version": "1.1.1", - "license": "MIT", - "dependencies": { - "@radix-ui/rect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-size": { - "version": "1.1.1", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-visually-hidden": { - "version": "1.2.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/rect": { - "version": "1.1.1", - "license": "MIT" - }, - "node_modules/@reduxjs/toolkit": { - "version": "2.11.2", - "license": "MIT", - "dependencies": { - "@standard-schema/spec": "^1.0.0", - "@standard-schema/utils": "^0.3.0", - "immer": "^11.0.0", - "redux": "^5.0.1", - "redux-thunk": "^3.1.0", - "reselect": "^5.1.0" - }, - "peerDependencies": { - "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 - } - } - }, - "node_modules/@reduxjs/toolkit/node_modules/immer": { - "version": "11.1.3", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, - "node_modules/@remix-run/router": { - "version": "1.23.2", - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.27", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.55.1", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.55.1", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "dev": true, - "license": "MIT" - }, - "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "10.3.0", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sinonjs/commons": "^3.0.0" - } - }, - "node_modules/@socket.io/component-emitter": { - "version": "3.1.2", - "license": "MIT" - }, - "node_modules/@socket.io/redis-adapter": { - "version": "8.3.0", - "license": "MIT", - "dependencies": { - "debug": "~4.3.1", - "notepack.io": "~3.0.1", - "uid2": "1.0.0" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "socket.io-adapter": "^2.5.4" - } - }, - "node_modules/@socket.io/redis-emitter": { - "version": "5.1.0", - "license": "MIT", - "dependencies": { - "debug": "~4.3.1", - "notepack.io": "~3.0.1", - "socket.io-parser": "~4.2.1" - } - }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "license": "MIT" - }, - "node_modules/@standard-schema/utils": { - "version": "0.3.0", - "license": "MIT" - }, - "node_modules/@tanstack/query-core": { - "version": "5.90.16", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/react-query": { - "version": "5.90.16", - "license": "MIT", - "dependencies": { - "@tanstack/query-core": "5.90.16" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "react": "^18 || ^19" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.12", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.2" - } - }, - "node_modules/@types/body-parser": { - "version": "1.19.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/compression": { - "version": "1.8.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/express": "*", - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.38", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/cookiejar": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz", - "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/cors": { - "version": "2.8.19", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/d3-array": { - "version": "3.2.2", - "license": "MIT" - }, - "node_modules/@types/d3-color": { - "version": "3.1.3", - "license": "MIT" - }, - "node_modules/@types/d3-ease": { - "version": "3.0.2", - "license": "MIT" - }, - "node_modules/@types/d3-interpolate": { - "version": "3.0.4", - "license": "MIT", - "dependencies": { - "@types/d3-color": "*" - } - }, - "node_modules/@types/d3-path": { - "version": "3.1.1", - "license": "MIT" - }, - "node_modules/@types/d3-scale": { - "version": "4.0.9", - "license": "MIT", - "dependencies": { - "@types/d3-time": "*" - } - }, - "node_modules/@types/d3-shape": { - "version": "3.1.8", - "license": "MIT", - "dependencies": { - "@types/d3-path": "*" - } - }, - "node_modules/@types/d3-time": { - "version": "3.0.4", - "license": "MIT" - }, - "node_modules/@types/d3-timer": { - "version": "3.0.2", - "license": "MIT" - }, - "node_modules/@types/debug": { - "version": "4.1.12", - "license": "MIT", - "dependencies": { - "@types/ms": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "license": "MIT" - }, - "node_modules/@types/estree-jsx": { - "version": "1.0.5", - "license": "MIT", - "dependencies": { - "@types/estree": "*" - } - }, - "node_modules/@types/express": { - "version": "4.17.25", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "^1" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.19.8", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/geojson": { - "version": "7946.0.16", - "license": "MIT" - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.9", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/hast": { - "version": "3.0.4", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/@types/http-errors": { - "version": "2.0.5", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/jest": { - "version": "30.0.0", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-30.0.0.tgz", - "integrity": "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==", - "dev": true, - "license": "MIT", - "dependencies": { - "expect": "^30.0.0", - "pretty-format": "^30.0.0" - } - }, - "node_modules/@types/jest/node_modules/@jest/expect-utils": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", - "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/get-type": "30.1.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@types/jest/node_modules/@jest/schemas": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", - "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.34.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@types/jest/node_modules/@jest/types": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", - "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/pattern": "30.0.1", - "@jest/schemas": "30.0.5", - "@types/istanbul-lib-coverage": "^2.0.6", - "@types/istanbul-reports": "^3.0.4", - "@types/node": "*", - "@types/yargs": "^17.0.33", - "chalk": "^4.1.2" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@types/jest/node_modules/@sinclair/typebox": { - "version": "0.34.47", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.47.tgz", - "integrity": "sha512-ZGIBQ+XDvO5JQku9wmwtabcVTHJsgSWAHYtVuM9pBNNR5E88v6Jcj/llpmsjivig5X8A8HHOb4/mbEKPS5EvAw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/jest/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@types/jest/node_modules/ci-info": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", - "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@types/jest/node_modules/expect": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", - "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/expect-utils": "30.2.0", - "@jest/get-type": "30.1.0", - "jest-matcher-utils": "30.2.0", - "jest-message-util": "30.2.0", - "jest-mock": "30.2.0", - "jest-util": "30.2.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@types/jest/node_modules/jest-diff": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", - "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/diff-sequences": "30.0.1", - "@jest/get-type": "30.1.0", - "chalk": "^4.1.2", - "pretty-format": "30.2.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@types/jest/node_modules/jest-matcher-utils": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", - "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/get-type": "30.1.0", - "chalk": "^4.1.2", - "jest-diff": "30.2.0", - "pretty-format": "30.2.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@types/jest/node_modules/jest-message-util": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", - "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@jest/types": "30.2.0", - "@types/stack-utils": "^2.0.3", - "chalk": "^4.1.2", - "graceful-fs": "^4.2.11", - "micromatch": "^4.0.8", - "pretty-format": "30.2.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.6" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@types/jest/node_modules/jest-mock": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz", - "integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "30.2.0", - "@types/node": "*", - "jest-util": "30.2.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@types/jest/node_modules/jest-util": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", - "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "30.2.0", - "@types/node": "*", - "chalk": "^4.1.2", - "ci-info": "^4.2.0", - "graceful-fs": "^4.2.11", - "picomatch": "^4.0.2" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@types/jest/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/@types/jest/node_modules/pretty-format": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", - "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "30.0.5", - "ansi-styles": "^5.2.0", - "react-is": "^18.3.1" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@types/jest/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/jsonwebtoken": { - "version": "9.0.10", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/ms": "*", - "@types/node": "*" - } - }, - "node_modules/@types/mdast": { - "version": "4.0.4", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/@types/methods": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", - "integrity": "sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/mime": { - "version": "1.3.5", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/morgan": { - "version": "1.9.10", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/ms": { - "version": "2.1.0", - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "20.19.29", - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@types/passport": { - "version": "1.0.17", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/express": "*" - } - }, - "node_modules/@types/passport-jwt": { - "version": "4.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/jsonwebtoken": "*", - "@types/passport-strategy": "*" - } - }, - "node_modules/@types/passport-strategy": { - "version": "0.2.38", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/express": "*", - "@types/passport": "*" - } - }, - "node_modules/@types/pg": { - "version": "8.16.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "pg-protocol": "*", - "pg-types": "^2.2.0" - } - }, - "node_modules/@types/prop-types": { - "version": "15.7.15", - "license": "MIT" - }, - "node_modules/@types/qs": { - "version": "6.14.0", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/react": { - "version": "18.3.27", - "license": "MIT", - "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.2.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.3.7", - "devOptional": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^18.0.0" - } - }, - "node_modules/@types/semver": { - "version": "7.7.1", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/send": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.15.10", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/http-errors": "*", - "@types/node": "*", - "@types/send": "<1" - } - }, - "node_modules/@types/serve-static/node_modules/@types/send": { - "version": "0.17.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@types/stack-utils": { - "version": "2.0.3", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/strip-bom": { - "version": "3.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/strip-json-comments": { - "version": "0.0.30", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/superagent": { - "version": "8.1.9", - "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-8.1.9.tgz", - "integrity": "sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/cookiejar": "^2.1.5", - "@types/methods": "^1.1.4", - "@types/node": "*", - "form-data": "^4.0.0" - } - }, - "node_modules/@types/supertest": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-6.0.3.tgz", - "integrity": "sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/methods": "^1.1.4", - "@types/superagent": "^8.1.0" - } - }, - "node_modules/@types/unist": { - "version": "3.0.3", - "license": "MIT" - }, - "node_modules/@types/use-sync-external-store": { - "version": "0.0.6", - "license": "MIT" - }, - "node_modules/@types/webidl-conversions": { - "version": "7.0.3", - "license": "MIT" - }, - "node_modules/@types/whatwg-url": { - "version": "11.0.5", - "license": "MIT", - "dependencies": { - "@types/webidl-conversions": "*" - } - }, - "node_modules/@types/yargs": { - "version": "17.0.35", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "dev": true, - "license": "MIT" - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.21.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/type-utils": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.4", - "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "6.21.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "6.21.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "6.21.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "6.21.0", - "dev": true, - "license": "MIT", - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "6.21.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "semver": "^7.5.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.21.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "license": "ISC" - }, - "node_modules/@vitejs/plugin-react": { - "version": "4.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.28.0", - "@babel/plugin-transform-react-jsx-self": "^7.27.1", - "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.27", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.17.0" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" - } - }, - "node_modules/@vitest/expect": { - "version": "1.6.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/spy": "1.6.1", - "@vitest/utils": "1.6.1", - "chai": "^4.3.10" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "1.6.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/utils": "1.6.1", - "p-limit": "^5.0.0", - "pathe": "^1.1.1" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner/node_modules/p-limit": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@vitest/runner/node_modules/yocto-queue": { - "version": "1.2.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@vitest/snapshot": { - "version": "1.6.1", - "dev": true, - "license": "MIT", - "dependencies": { - "magic-string": "^0.30.5", - "pathe": "^1.1.1", - "pretty-format": "^29.7.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/spy": { - "version": "1.6.1", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyspy": "^2.2.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils": { - "version": "1.6.1", - "dev": true, - "license": "MIT", - "dependencies": { - "diff-sequences": "^29.6.3", - "estree-walker": "^3.0.3", - "loupe": "^2.3.7", - "pretty-format": "^29.7.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/accepts": { - "version": "1.3.8", - "license": "MIT", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/accepts/node_modules/negotiator": { - "version": "0.6.3", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.15.0", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.4", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ajv": { - "version": "8.17.1", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "3.0.1", - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/any-promise": { - "version": "1.3.0", - "license": "MIT" - }, - "node_modules/anymatch": { - "version": "3.1.3", - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "5.0.2", - "license": "MIT" - }, - "node_modules/argparse": { - "version": "2.0.1", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/aria-hidden": { - "version": "1.2.6", - "license": "MIT", - "dependencies": { - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "license": "MIT" - }, - "node_modules/array-union": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dev": true, - "license": "MIT" - }, - "node_modules/assertion-error": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/autoprefixer": { - "version": "10.4.23", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "browserslist": "^4.28.1", - "caniuse-lite": "^1.0.30001760", - "fraction.js": "^5.3.4", - "picocolors": "^1.1.1", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/babel-jest": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/transform": "^29.7.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.6.3", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-istanbul/node_modules/semver": { - "version": "6.3.1", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "29.6.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-import-attributes": "^7.24.7", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5" - }, - "peerDependencies": { - "@babel/core": "^7.0.0 || ^8.0.0-0" - } - }, - "node_modules/babel-preset-jest": { - "version": "29.6.3", - "dev": true, - "license": "MIT", - "dependencies": { - "babel-plugin-jest-hoist": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/bail": { - "version": "2.0.2", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/base64id": { - "version": "2.0.0", - "license": "MIT", - "engines": { - "node": "^4.5.0 || >= 5.9" - } - }, - "node_modules/baseline-browser-mapping": { - "version": "2.9.14", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.js" - } - }, - "node_modules/basic-auth": { - "version": "2.0.1", - "license": "MIT", - "dependencies": { - "safe-buffer": "5.1.2" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/basic-auth/node_modules/safe-buffer": { - "version": "5.1.2", - "license": "MIT" - }, - "node_modules/bcrypt": { - "version": "6.0.0", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "node-addon-api": "^8.3.0", - "node-gyp-build": "^4.8.4" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/bignumber.js": { - "version": "9.0.0", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/body-parser": { - "version": "1.20.4", - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "~1.2.0", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "on-finished": "~2.4.1", - "qs": "~6.14.0", - "raw-body": "~2.5.3", - "type-is": "~1.6.18", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "license": "MIT" - }, - "node_modules/body-parser/node_modules/raw-body": { - "version": "2.5.3", - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/brace-expansion": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.28.1", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/bson": { - "version": "6.10.4", - "license": "Apache-2.0", - "engines": { - "node": ">=16.20.1" - } - }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "license": "BSD-3-Clause" - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "dev": true, - "license": "MIT" - }, - "node_modules/bytes": { - "version": "3.1.2", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/cac": { - "version": "6.7.14", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001764", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/ccount": { - "version": "2.0.1", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/chai": { - "version": "4.5.0", - "dev": true, - "license": "MIT", - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chai/node_modules/type-detect": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/character-entities": { - "version": "2.0.2", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-entities-html4": { - "version": "2.1.0", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-entities-legacy": { - "version": "3.0.0", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-reference-invalid": { - "version": "2.0.1", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/check-error": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "get-func-name": "^2.0.2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/chokidar": { - "version": "3.6.0", - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/ci-info": { - "version": "3.9.0", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/cjs-module-lexer": { - "version": "1.4.3", - "dev": true, - "license": "MIT" - }, - "node_modules/class-variance-authority": { - "version": "0.7.1", - "license": "Apache-2.0", - "dependencies": { - "clsx": "^2.1.1" - }, - "funding": { - "url": "https://polar.sh/cva" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/clsx": { - "version": "2.1.1", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/cluster-key-slot": { - "version": "1.1.2", - "license": "Apache-2.0", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/co": { - "version": "4.6.0", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.3", - "dev": true, - "license": "MIT" - }, - "node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/comma-separated-tokens": { - "version": "2.0.3", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/commander": { - "version": "4.1.1", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/component-emitter": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", - "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/compressible": { - "version": "2.0.18", - "license": "MIT", - "dependencies": { - "mime-db": ">= 1.43.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/compression": { - "version": "1.8.1", - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "compressible": "~2.0.18", - "debug": "2.6.9", - "negotiator": "~0.6.4", - "on-headers": "~1.1.0", - "safe-buffer": "5.2.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/compression/node_modules/debug": { - "version": "2.6.9", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/compression/node_modules/ms": { - "version": "2.0.0", - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/confbox": { - "version": "0.1.8", - "dev": true, - "license": "MIT" - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/cookie": { - "version": "0.7.2", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.7", - "license": "MIT" - }, - "node_modules/cookiejar": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", - "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", - "dev": true, - "license": "MIT" - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "license": "MIT" - }, - "node_modules/cors": { - "version": "2.8.5", - "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/create-jest": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "prompts": "^2.0.1" - }, - "bin": { - "create-jest": "bin/create-jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/create-require": { - "version": "1.1.1", - "dev": true, - "license": "MIT" - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cssesc": { - "version": "3.0.0", - "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/csstype": { - "version": "3.2.3", - "license": "MIT" - }, - "node_modules/d3-array": { - "version": "3.2.4", - "license": "ISC", - "dependencies": { - "internmap": "1 - 2" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-color": { - "version": "3.1.0", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-delaunay": { - "version": "6.0.4", - "license": "ISC", - "dependencies": { - "delaunator": "5" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-dispatch": { - "version": "3.0.1", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-dsv": { - "version": "3.0.1", - "license": "ISC", - "dependencies": { - "commander": "7", - "iconv-lite": "0.6", - "rw": "1" - }, - "bin": { - "csv2json": "bin/dsv2json.js", - "csv2tsv": "bin/dsv2dsv.js", - "dsv2dsv": "bin/dsv2dsv.js", - "dsv2json": "bin/dsv2json.js", - "json2csv": "bin/json2dsv.js", - "json2dsv": "bin/json2dsv.js", - "json2tsv": "bin/json2dsv.js", - "tsv2csv": "bin/dsv2dsv.js", - "tsv2json": "bin/dsv2json.js" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-dsv/node_modules/commander": { - "version": "7.2.0", - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, - "node_modules/d3-dsv/node_modules/iconv-lite": { - "version": "0.6.3", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/d3-ease": { - "version": "3.0.1", - "license": "BSD-3-Clause", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-force": { - "version": "3.0.0", - "license": "ISC", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-quadtree": "1 - 3", - "d3-timer": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-format": { - "version": "3.1.0", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-geo": { - "version": "3.1.1", - "license": "ISC", - "dependencies": { - "d3-array": "2.5.0 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-geo-projection": { - "version": "4.0.0", - "license": "ISC", - "dependencies": { - "commander": "7", - "d3-array": "1 - 3", - "d3-geo": "1.12.0 - 3" - }, - "bin": { - "geo2svg": "bin/geo2svg.js", - "geograticule": "bin/geograticule.js", - "geoproject": "bin/geoproject.js", - "geoquantize": "bin/geoquantize.js", - "geostitch": "bin/geostitch.js" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-geo-projection/node_modules/commander": { - "version": "7.2.0", - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, - "node_modules/d3-hierarchy": { - "version": "3.1.2", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-interpolate": { - "version": "3.0.1", - "license": "ISC", - "dependencies": { - "d3-color": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-path": { - "version": "3.1.0", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-quadtree": { - "version": "3.0.1", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-scale": { - "version": "4.0.2", - "license": "ISC", - "dependencies": { - "d3-array": "2.10.0 - 3", - "d3-format": "1 - 3", - "d3-interpolate": "1.2.0 - 3", - "d3-time": "2.1.1 - 3", - "d3-time-format": "2 - 4" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-scale-chromatic": { - "version": "3.1.0", - "license": "ISC", - "dependencies": { - "d3-color": "1 - 3", - "d3-interpolate": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-shape": { - "version": "3.2.0", - "license": "ISC", - "dependencies": { - "d3-path": "^3.1.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-time": { - "version": "3.1.0", - "license": "ISC", - "dependencies": { - "d3-array": "2 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-time-format": { - "version": "4.1.0", - "license": "ISC", - "dependencies": { - "d3-time": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-timer": { - "version": "3.0.1", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/date-fns": { - "version": "4.1.0", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/kossnocorp" - } - }, - "node_modules/date-fns-jalali": { - "version": "4.1.0-0", - "resolved": "https://registry.npmjs.org/date-fns-jalali/-/date-fns-jalali-4.1.0-0.tgz", - "integrity": "sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==", - "license": "MIT" - }, - "node_modules/debug": { - "version": "4.3.7", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decimal.js-light": { - "version": "2.5.1", - "license": "MIT" - }, - "node_modules/decode-named-character-reference": { - "version": "1.2.0", - "license": "MIT", - "dependencies": { - "character-entities": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/dedent": { - "version": "1.7.1", - "dev": true, - "license": "MIT", - "peerDependencies": { - "babel-plugin-macros": "^3.1.0" - }, - "peerDependenciesMeta": { - "babel-plugin-macros": { - "optional": true - } - } - }, - "node_modules/deep-eql": { - "version": "4.1.4", - "dev": true, - "license": "MIT", - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/delaunator": { - "version": "5.0.1", - "license": "ISC", - "dependencies": { - "robust-predicates": "^3.0.2" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/denque": { - "version": "2.1.0", - "license": "Apache-2.0", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/dequal": { - "version": "2.0.3", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/detect-node-es": { - "version": "1.1.0", - "license": "MIT" - }, - "node_modules/devlop": { - "version": "1.1.0", - "license": "MIT", - "dependencies": { - "dequal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/dezalgo": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", - "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", - "dev": true, - "license": "ISC", - "dependencies": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, - "node_modules/didyoumean": { - "version": "1.2.2", - "license": "Apache-2.0" - }, - "node_modules/diff": { - "version": "4.0.2", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dlv": { - "version": "1.1.3", - "license": "MIT" - }, - "node_modules/doctrine": { - "version": "3.0.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dotenv": { - "version": "16.6.1", - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/dynamic-dedupe": { - "version": "0.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "xtend": "^4.0.0" - } - }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "license": "MIT" - }, - "node_modules/electron-to-chromium": { - "version": "1.5.267", - "dev": true, - "license": "ISC" - }, - "node_modules/emittery": { - "version": "0.13.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/engine.io": { - "version": "6.6.5", - "license": "MIT", - "dependencies": { - "@types/cors": "^2.8.12", - "@types/node": ">=10.0.0", - "accepts": "~1.3.4", - "base64id": "2.0.0", - "cookie": "~0.7.2", - "cors": "~2.8.5", - "debug": "~4.4.1", - "engine.io-parser": "~5.2.1", - "ws": "~8.18.3" - }, - "engines": { - "node": ">=10.2.0" - } - }, - "node_modules/engine.io-client": { - "version": "6.6.4", - "license": "MIT", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.4.1", - "engine.io-parser": "~5.2.1", - "ws": "~8.18.3", - "xmlhttprequest-ssl": "~2.1.1" - } - }, - "node_modules/engine.io-client/node_modules/debug": { - "version": "4.4.3", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/engine.io-parser": { - "version": "5.2.3", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/engine.io/node_modules/debug": { - "version": "4.4.3", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/error-ex": { - "version": "1.3.4", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-toolkit": { - "version": "1.43.0", - "license": "MIT", - "workspaces": [ - "docs", - "benchmarks" - ] - }, - "node_modules/esbuild": { - "version": "0.27.2", - "devOptional": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.2", - "@esbuild/android-arm": "0.27.2", - "@esbuild/android-arm64": "0.27.2", - "@esbuild/android-x64": "0.27.2", - "@esbuild/darwin-arm64": "0.27.2", - "@esbuild/darwin-x64": "0.27.2", - "@esbuild/freebsd-arm64": "0.27.2", - "@esbuild/freebsd-x64": "0.27.2", - "@esbuild/linux-arm": "0.27.2", - "@esbuild/linux-arm64": "0.27.2", - "@esbuild/linux-ia32": "0.27.2", - "@esbuild/linux-loong64": "0.27.2", - "@esbuild/linux-mips64el": "0.27.2", - "@esbuild/linux-ppc64": "0.27.2", - "@esbuild/linux-riscv64": "0.27.2", - "@esbuild/linux-s390x": "0.27.2", - "@esbuild/linux-x64": "0.27.2", - "@esbuild/netbsd-arm64": "0.27.2", - "@esbuild/netbsd-x64": "0.27.2", - "@esbuild/openbsd-arm64": "0.27.2", - "@esbuild/openbsd-x64": "0.27.2", - "@esbuild/openharmony-arm64": "0.27.2", - "@esbuild/sunos-x64": "0.27.2", - "@esbuild/win32-arm64": "0.27.2", - "@esbuild/win32-ia32": "0.27.2", - "@esbuild/win32-x64": "0.27.2" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "license": "MIT" - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.57.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@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.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "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.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" - } - }, - "node_modules/eslint-plugin-react-refresh": { - "version": "0.4.26", - "dev": true, - "license": "MIT", - "peerDependencies": { - "eslint": ">=8.40" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.12", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/json-schema-traverse": { - "version": "0.4.1", - "dev": true, - "license": "MIT" - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "dev": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.7.0", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-util-is-identifier-name": { - "version": "3.0.0", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/estree-walker": { - "version": "3.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventemitter3": { - "version": "5.0.1", - "license": "MIT" - }, - "node_modules/eventsource": { - "version": "3.0.7", - "license": "MIT", - "dependencies": { - "eventsource-parser": "^3.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/eventsource-parser": { - "version": "3.0.6", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expect": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/expect-utils": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/express": { - "version": "4.22.1", - "license": "MIT", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "~1.20.3", - "content-disposition": "~0.5.4", - "content-type": "~1.0.4", - "cookie": "~0.7.1", - "cookie-signature": "~1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.3.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "~0.1.12", - "proxy-addr": "~2.0.7", - "qs": "~6.14.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "~0.19.0", - "serve-static": "~1.16.2", - "setprototypeof": "1.2.0", - "statuses": "~2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express-rate-limit": { - "version": "7.5.1", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/express-rate-limit" - }, - "peerDependencies": { - "express": ">= 4.11" - } - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "license": "MIT" - }, - "node_modules/extend": { - "version": "3.0.2", - "license": "MIT" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-patch": { - "version": "3.1.1", - "license": "MIT" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-uri": { - "version": "3.1.0", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/fastq": { - "version": "1.20.1", - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.3.2", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "statuses": "~2.0.2", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "license": "MIT" - }, - "node_modules/find-up": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.3.3", - "dev": true, - "license": "ISC" - }, - "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", - "dev": true, - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/formidable": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.4.tgz", - "integrity": "sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@paralleldrive/cuid2": "^2.2.2", - "dezalgo": "^1.0.4", - "once": "^1.4.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "url": "https://ko-fi.com/tunnckoCore/commissions" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fraction.js": { - "version": "5.3.4", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/rawify" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/function-bind": { - "version": "1.1.2", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-east-asian-width": { - "version": "1.4.0", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-func-name": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "license": "MIT", - "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" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-nonce": { - "version": "1.0.1", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-tsconfig": { - "version": "4.13.0", - "devOptional": true, - "license": "MIT", - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.12", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/globals": { - "version": "13.24.0", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "dev": true, - "license": "ISC" - }, - "node_modules/graphemer": { - "version": "1.4.0", - "dev": true, - "license": "MIT" - }, - "node_modules/handlebars": { - "version": "4.7.8", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", - "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hast-util-to-jsx-runtime": { - "version": "2.3.6", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/unist": "^3.0.0", - "comma-separated-tokens": "^2.0.0", - "devlop": "^1.0.0", - "estree-util-is-identifier-name": "^3.0.0", - "hast-util-whitespace": "^3.0.0", - "mdast-util-mdx-expression": "^2.0.0", - "mdast-util-mdx-jsx": "^3.0.0", - "mdast-util-mdxjs-esm": "^2.0.0", - "property-information": "^7.0.0", - "space-separated-tokens": "^2.0.0", - "style-to-js": "^1.0.0", - "unist-util-position": "^5.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-whitespace": { - "version": "3.0.0", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/helmet": { - "version": "7.2.0", - "license": "MIT", - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/hive": { - "resolved": "hive", - "link": true - }, - "node_modules/honeycomb": { - "resolved": "honeycomb", - "link": true - }, - "node_modules/hono": { - "version": "4.11.4", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=16.9.0" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/html-url-attributes": { - "version": "3.0.1", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/http-errors": { - "version": "2.0.1", - "license": "MIT", - "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ignore": { - "version": "5.3.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/immer": { - "version": "10.2.0", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-local": { - "version": "3.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "license": "ISC" - }, - "node_modules/inline-style-parser": { - "version": "0.2.7", - "license": "MIT" - }, - "node_modules/internmap": { - "version": "2.0.3", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/ioredis": { - "version": "5.9.1", - "license": "MIT", - "dependencies": { - "@ioredis/commands": "1.5.0", - "cluster-key-slot": "^1.1.0", - "debug": "^4.3.4", - "denque": "^2.1.0", - "lodash.defaults": "^4.2.0", - "lodash.isarguments": "^3.1.0", - "redis-errors": "^1.2.0", - "redis-parser": "^3.0.0", - "standard-as-callback": "^2.1.0" - }, - "engines": { - "node": ">=12.22.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/ioredis" - } - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-alphabetical": { - "version": "2.0.1", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-alphanumerical": { - "version": "2.0.1", - "license": "MIT", - "dependencies": { - "is-alphabetical": "^2.0.0", - "is-decimal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "dev": true, - "license": "MIT" - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-decimal": { - "version": "2.0.1", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-hexadecimal": { - "version": "2.0.1", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "4.1.0", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-promise": { - "version": "4.0.0", - "license": "MIT" - }, - "node_modules/is-stream": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "license": "ISC" - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "6.0.3", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/core": "^7.23.9", - "@babel/parser": "^7.23.9", - "@istanbuljs/schema": "^0.1.3", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.2.0", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/core": "^29.7.0", - "@jest/types": "^29.6.3", - "import-local": "^3.0.2", - "jest-cli": "^29.7.0" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "execa": "^5.0.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^1.0.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.7.0", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0", - "pretty-format": "^29.7.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-cli": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/core": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "create-jest": "^29.7.0", - "exit": "^0.1.2", - "import-local": "^3.0.2", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-config": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-jest": "^29.7.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-diff": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-docblock": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "jest-util": "^29.7.0", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "29.6.3", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-leak-detector": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.6.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-mock": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "29.6.3", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-regex-util": "^29.6.3", - "jest-snapshot": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/environment": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-leak-detector": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-resolve": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-util": "^29.7.0", - "jest-watcher": "^29.7.0", - "jest-worker": "^29.7.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/globals": "^29.7.0", - "@jest/source-map": "^29.6.3", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "natural-compare": "^1.4.0", - "pretty-format": "^29.7.0", - "semver": "^7.5.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-util": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "leven": "^3.1.0", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watcher": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.7.0", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "jest-util": "^29.7.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/jiti": { - "version": "1.21.7", - "license": "MIT", - "bin": { - "jiti": "bin/jiti.js" - } - }, - "node_modules/jose": { - "version": "6.1.3", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "license": "MIT" - }, - "node_modules/json-schema-typed": { - "version": "8.0.2", - "license": "BSD-2-Clause" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stringify-pretty-compact": { - "version": "4.0.0", - "license": "MIT" - }, - "node_modules/json5": { - "version": "2.2.3", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonwebtoken": { - "version": "9.0.3", - "license": "MIT", - "dependencies": { - "jws": "^4.0.1", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^7.5.4" - }, - "engines": { - "node": ">=12", - "npm": ">=6" - } - }, - "node_modules/jwa": { - "version": "2.0.1", - "license": "MIT", - "dependencies": { - "buffer-equal-constant-time": "^1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "4.0.1", - "license": "MIT", - "dependencies": { - "jwa": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lilconfig": { - "version": "3.1.3", - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "license": "MIT" - }, - "node_modules/local-pkg": { - "version": "0.5.1", - "dev": true, - "license": "MIT", - "dependencies": { - "mlly": "^1.7.3", - "pkg-types": "^1.2.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.defaults": { - "version": "4.2.0", - "license": "MIT" - }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "license": "MIT" - }, - "node_modules/lodash.isarguments": { - "version": "3.1.0", - "license": "MIT" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "license": "MIT" - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "license": "MIT" - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "license": "MIT" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "license": "MIT" - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "license": "MIT" - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.once": { - "version": "4.1.1", - "license": "MIT" - }, - "node_modules/longest-streak": { - "version": "3.1.0", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/loupe": { - "version": "2.3.7", - "dev": true, - "license": "MIT", - "dependencies": { - "get-func-name": "^2.0.1" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/lucide-react": { - "version": "0.562.0", - "license": "ISC", - "peerDependencies": { - "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/magic-string": { - "version": "0.30.21", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/make-dir": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "dev": true, - "license": "ISC" - }, - "node_modules/makeerror": { - "version": "1.0.12", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/mdast-util-from-markdown": { - "version": "2.0.2", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark": "^4.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdx-expression": { - "version": "2.0.1", - "license": "MIT", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdx-jsx": { - "version": "3.2.0", - "license": "MIT", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "ccount": "^2.0.0", - "devlop": "^1.1.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0", - "parse-entities": "^4.0.0", - "stringify-entities": "^4.0.0", - "unist-util-stringify-position": "^4.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdxjs-esm": { - "version": "2.0.1", - "license": "MIT", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-phrasing": { - "version": "4.1.0", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-hast": { - "version": "13.2.1", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "@ungap/structured-clone": "^1.0.0", - "devlop": "^1.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "trim-lines": "^3.0.0", - "unist-util-position": "^5.0.0", - "unist-util-visit": "^5.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-markdown": { - "version": "2.1.2", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "longest-streak": "^3.0.0", - "mdast-util-phrasing": "^4.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "unist-util-visit": "^5.0.0", - "zwitch": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-string": { - "version": "4.0.0", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/media-typer": { - "version": "0.3.0", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/memory-pager": { - "version": "1.5.0", - "license": "MIT" - }, - "node_modules/merge-descriptors": { - "version": "1.0.3", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/merge2": { - "version": "1.4.1", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromark": { - "version": "4.0.2", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-core-commonmark": { - "version": "2.0.3", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-destination": "^2.0.0", - "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-title": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-html-tag-name": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-destination": { - "version": "2.0.1", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-label": { - "version": "2.0.1", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-space": { - "version": "2.0.1", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-title": { - "version": "2.0.1", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-whitespace": { - "version": "2.0.1", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-character": { - "version": "2.1.1", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-chunked": { - "version": "2.0.1", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-classify-character": { - "version": "2.0.1", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-combine-extensions": { - "version": "2.0.1", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-chunked": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.2", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-decode-string": { - "version": "2.0.1", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-encode": { - "version": "2.0.1", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-html-tag-name": { - "version": "2.0.1", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-normalize-identifier": { - "version": "2.0.1", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-resolve-all": { - "version": "2.0.1", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-sanitize-uri": { - "version": "2.0.1", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-subtokenize": { - "version": "2.1.0", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-symbol": { - "version": "2.0.1", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-types": { - "version": "2.0.2", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromatch": { - "version": "4.0.8", - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.54.0", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types/node_modules/mime-db": { - "version": "1.52.0", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/minimatch": { - "version": "9.0.3", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mlly": { - "version": "1.8.0", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.15.0", - "pathe": "^2.0.3", - "pkg-types": "^1.3.1", - "ufo": "^1.6.1" - } - }, - "node_modules/mlly/node_modules/pathe": { - "version": "2.0.3", - "dev": true, - "license": "MIT" - }, - "node_modules/mongodb": { - "version": "6.21.0", - "license": "Apache-2.0", - "dependencies": { - "@mongodb-js/saslprep": "^1.3.0", - "bson": "^6.10.4", - "mongodb-connection-string-url": "^3.0.2" - }, - "engines": { - "node": ">=16.20.1" - }, - "peerDependencies": { - "@aws-sdk/credential-providers": "^3.188.0", - "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", - "gcp-metadata": "^5.2.0", - "kerberos": "^2.0.1", - "mongodb-client-encryption": ">=6.0.0 <7", - "snappy": "^7.3.2", - "socks": "^2.7.1" - }, - "peerDependenciesMeta": { - "@aws-sdk/credential-providers": { - "optional": true - }, - "@mongodb-js/zstd": { - "optional": true - }, - "gcp-metadata": { - "optional": true - }, - "kerberos": { - "optional": true - }, - "mongodb-client-encryption": { - "optional": true - }, - "snappy": { - "optional": true - }, - "socks": { - "optional": true - } - } - }, - "node_modules/mongodb-connection-string-url": { - "version": "3.0.2", - "license": "Apache-2.0", - "dependencies": { - "@types/whatwg-url": "^11.0.2", - "whatwg-url": "^14.1.0 || ^13.0.0" - } - }, - "node_modules/morgan": { - "version": "1.10.1", - "license": "MIT", - "dependencies": { - "basic-auth": "~2.0.1", - "debug": "2.6.9", - "depd": "~2.0.0", - "on-finished": "~2.3.0", - "on-headers": "~1.1.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/morgan/node_modules/debug": { - "version": "2.6.9", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/morgan/node_modules/ms": { - "version": "2.0.0", - "license": "MIT" - }, - "node_modules/morgan/node_modules/on-finished": { - "version": "2.3.0", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "license": "MIT" - }, - "node_modules/mysql": { - "version": "2.18.1", - "license": "MIT", - "dependencies": { - "bignumber.js": "9.0.0", - "readable-stream": "2.3.7", - "safe-buffer": "5.1.2", - "sqlstring": "2.3.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mysql/node_modules/safe-buffer": { - "version": "5.1.2", - "license": "MIT" - }, - "node_modules/mz": { - "version": "2.7.0", - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/nanoid": { - "version": "3.3.11", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "dev": true, - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "0.6.4", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-addon-api": { - "version": "8.5.0", - "license": "MIT", - "engines": { - "node": "^18 || ^20 || >= 21" - } - }, - "node_modules/node-gyp-build": { - "version": "4.8.4", - "license": "MIT", - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, - "node_modules/node-int64": { - "version": "0.4.0", - "dev": true, - "license": "MIT" - }, - "node_modules/node-releases": { - "version": "2.0.27", - "dev": true, - "license": "MIT" - }, - "node_modules/nodemailer": { - "version": "6.10.1", - "license": "MIT-0", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/notepack.io": { - "version": "3.0.1", - "license": "MIT" - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-hash": { - "version": "3.0.0", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/on-headers": { - "version": "1.1.0", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-entities": { - "version": "4.0.2", - "license": "MIT", - "dependencies": { - "@types/unist": "^2.0.0", - "character-entities-legacy": "^3.0.0", - "character-reference-invalid": "^2.0.0", - "decode-named-character-reference": "^1.0.0", - "is-alphanumerical": "^2.0.0", - "is-decimal": "^2.0.0", - "is-hexadecimal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/parse-entities/node_modules/@types/unist": { - "version": "2.0.11", - "license": "MIT" - }, - "node_modules/parse-json": { - "version": "5.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/passport": { - "version": "0.7.0", - "license": "MIT", - "dependencies": { - "passport-strategy": "1.x.x", - "pause": "0.0.1", - "utils-merge": "^1.0.1" - }, - "engines": { - "node": ">= 0.4.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/jaredhanson" - } - }, - "node_modules/passport-jwt": { - "version": "4.0.1", - "license": "MIT", - "dependencies": { - "jsonwebtoken": "^9.0.0", - "passport-strategy": "^1.0.0" - } - }, - "node_modules/passport-strategy": { - "version": "1.0.0", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "license": "MIT" - }, - "node_modules/path-to-regexp": { - "version": "0.1.12", - "license": "MIT" - }, - "node_modules/path-type": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/pathe": { - "version": "1.1.2", - "dev": true, - "license": "MIT" - }, - "node_modules/pathval": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/pause": { - "version": "0.0.1" - }, - "node_modules/pg": { - "version": "8.16.3", - "license": "MIT", - "dependencies": { - "pg-connection-string": "^2.9.1", - "pg-pool": "^3.10.1", - "pg-protocol": "^1.10.3", - "pg-types": "2.2.0", - "pgpass": "1.0.5" - }, - "engines": { - "node": ">= 16.0.0" - }, - "optionalDependencies": { - "pg-cloudflare": "^1.2.7" - }, - "peerDependencies": { - "pg-native": ">=3.0.1" - }, - "peerDependenciesMeta": { - "pg-native": { - "optional": true - } - } - }, - "node_modules/pg-cloudflare": { - "version": "1.2.7", - "license": "MIT", - "optional": true - }, - "node_modules/pg-connection-string": { - "version": "2.9.1", - "license": "MIT" - }, - "node_modules/pg-int8": { - "version": "1.0.1", - "license": "ISC", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/pg-pool": { - "version": "3.10.1", - "license": "MIT", - "peerDependencies": { - "pg": ">=8.0" - } - }, - "node_modules/pg-protocol": { - "version": "1.10.3", - "license": "MIT" - }, - "node_modules/pg-types": { - "version": "2.2.0", - "license": "MIT", - "dependencies": { - "pg-int8": "1.0.1", - "postgres-array": "~2.0.0", - "postgres-bytea": "~1.0.0", - "postgres-date": "~1.0.4", - "postgres-interval": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pgpass": { - "version": "1.0.5", - "license": "MIT", - "dependencies": { - "split2": "^4.1.0" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pirates": { - "version": "4.0.7", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkce-challenge": { - "version": "5.0.1", - "license": "MIT", - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-types": { - "version": "1.3.1", - "dev": true, - "license": "MIT", - "dependencies": { - "confbox": "^0.1.8", - "mlly": "^1.7.4", - "pathe": "^2.0.1" - } - }, - "node_modules/pkg-types/node_modules/pathe": { - "version": "2.0.3", - "dev": true, - "license": "MIT" - }, - "node_modules/postcss": { - "version": "8.5.6", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-import": { - "version": "15.1.0", - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-js": { - "version": "4.1.0", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "camelcase-css": "^2.0.1" - }, - "engines": { - "node": "^12 || ^14 || >= 16" - }, - "peerDependencies": { - "postcss": "^8.4.21" - } - }, - "node_modules/postcss-load-config": { - "version": "6.0.1", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "lilconfig": "^3.1.1" - }, - "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 - } - } - }, - "node_modules/postcss-nested": { - "version": "6.2.0", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "postcss-selector-parser": "^6.1.1" - }, - "engines": { - "node": ">=12.0" - }, - "peerDependencies": { - "postcss": "^8.2.14" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.1.2", - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "license": "MIT" - }, - "node_modules/postgres-array": { - "version": "2.0.0", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/postgres-bytea": { - "version": "1.0.1", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-date": { - "version": "1.0.7", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-interval": { - "version": "1.2.0", - "license": "MIT", - "dependencies": { - "xtend": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/pretty-format": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/pretty-format/node_modules/react-is": { - "version": "18.3.1", - "dev": true, - "license": "MIT" - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "license": "MIT" - }, - "node_modules/prompts": { - "version": "2.4.2", - "dev": true, - "license": "MIT", - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/property-information": { - "version": "7.1.0", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/pure-rand": { - "version": "6.1.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT" - }, - "node_modules/qs": { - "version": "6.14.1", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/range-parser": { - "version": "1.2.1", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "3.0.2", - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.7.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.7.2", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/react": { - "version": "18.3.1", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-day-picker": { - "version": "9.13.0", - "resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-9.13.0.tgz", - "integrity": "sha512-euzj5Hlq+lOHqI53NiuNhCP8HWgsPf/bBAVijR50hNaY1XwjKjShAnIe8jm8RD2W9IJUvihDIZ+KrmqfFzNhFQ==", - "license": "MIT", - "dependencies": { - "@date-fns/tz": "^1.4.1", - "date-fns": "^4.1.0", - "date-fns-jalali": "^4.1.0-0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "individual", - "url": "https://github.com/sponsors/gpbl" - }, - "peerDependencies": { - "react": ">=16.8.0" - } - }, - "node_modules/react-dom": { - "version": "18.3.1", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" - } - }, - "node_modules/react-hook-form": { - "version": "7.71.0", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/react-hook-form" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17 || ^18 || ^19" - } - }, - "node_modules/react-is": { - "version": "19.2.3", - "license": "MIT", - "peer": true - }, - "node_modules/react-markdown": { - "version": "10.1.0", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "hast-util-to-jsx-runtime": "^2.0.0", - "html-url-attributes": "^3.0.0", - "mdast-util-to-hast": "^13.0.0", - "remark-parse": "^11.0.0", - "remark-rehype": "^11.0.0", - "unified": "^11.0.0", - "unist-util-visit": "^5.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - }, - "peerDependencies": { - "@types/react": ">=18", - "react": ">=18" - } - }, - "node_modules/react-redux": { - "version": "9.2.0", - "license": "MIT", - "dependencies": { - "@types/use-sync-external-store": "^0.0.6", - "use-sync-external-store": "^1.4.0" - }, - "peerDependencies": { - "@types/react": "^18.2.25 || ^19", - "react": "^18.0 || ^19", - "redux": "^5.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "redux": { - "optional": true - } - } - }, - "node_modules/react-refresh": { - "version": "0.17.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-remove-scroll": { - "version": "2.7.2", - "license": "MIT", - "dependencies": { - "react-remove-scroll-bar": "^2.3.7", - "react-style-singleton": "^2.2.3", - "tslib": "^2.1.0", - "use-callback-ref": "^1.3.3", - "use-sidecar": "^1.1.3" - }, - "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 - } - } - }, - "node_modules/react-remove-scroll-bar": { - "version": "2.3.8", - "license": "MIT", - "dependencies": { - "react-style-singleton": "^2.2.2", - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/react-router": { - "version": "6.30.3", - "license": "MIT", - "dependencies": { - "@remix-run/router": "1.23.2" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": ">=16.8" - } - }, - "node_modules/react-router-dom": { - "version": "6.30.3", - "license": "MIT", - "dependencies": { - "@remix-run/router": "1.23.2", - "react-router": "6.30.3" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": ">=16.8", - "react-dom": ">=16.8" - } - }, - "node_modules/react-style-singleton": { - "version": "2.2.3", - "license": "MIT", - "dependencies": { - "get-nonce": "^1.0.0", - "tslib": "^2.0.0" - }, - "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 - } - } - }, - "node_modules/react-vega": { - "version": "8.0.0", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "react": "^17 || ^18 || ^19", - "react-dom": "^17 || ^18 || ^19", - "vega-embed": "^7" - } - }, - "node_modules/read-cache": { - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "pify": "^2.3.0" - } - }, - "node_modules/readable-stream": { - "version": "2.3.7", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "license": "MIT" - }, - "node_modules/readdirp": { - "version": "3.6.0", - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/recharts": { - "version": "3.6.0", - "license": "MIT", - "workspaces": [ - "www" - ], - "dependencies": { - "@reduxjs/toolkit": "1.x.x || 2.x.x", - "clsx": "^2.1.1", - "decimal.js-light": "^2.5.1", - "es-toolkit": "^1.39.3", - "eventemitter3": "^5.0.1", - "immer": "^10.1.1", - "react-redux": "8.x.x || 9.x.x", - "reselect": "5.1.1", - "tiny-invariant": "^1.3.3", - "use-sync-external-store": "^1.2.2", - "victory-vendor": "^37.0.2" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/redis-errors": { - "version": "1.2.0", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/redis-parser": { - "version": "3.0.0", - "license": "MIT", - "dependencies": { - "redis-errors": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/redux": { - "version": "5.0.1", - "license": "MIT" - }, - "node_modules/redux-thunk": { - "version": "3.1.0", - "license": "MIT", - "peerDependencies": { - "redux": "^5.0.0" - } - }, - "node_modules/remark-parse": { - "version": "11.0.0", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-from-markdown": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-rehype": { - "version": "11.1.2", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "mdast-util-to-hast": "^13.0.0", - "unified": "^11.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/reselect": { - "version": "5.1.1", - "license": "MIT" - }, - "node_modules/resolve": { - "version": "1.22.11", - "license": "MIT", - "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-cwd/node_modules/resolve-from": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "devOptional": true, - "license": "MIT", - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, - "node_modules/resolve.exports": { - "version": "2.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/robust-predicates": { - "version": "3.0.2", - "license": "Unlicense" - }, - "node_modules/rollup": { - "version": "4.55.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.8" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.55.1", - "@rollup/rollup-android-arm64": "4.55.1", - "@rollup/rollup-darwin-arm64": "4.55.1", - "@rollup/rollup-darwin-x64": "4.55.1", - "@rollup/rollup-freebsd-arm64": "4.55.1", - "@rollup/rollup-freebsd-x64": "4.55.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.55.1", - "@rollup/rollup-linux-arm-musleabihf": "4.55.1", - "@rollup/rollup-linux-arm64-gnu": "4.55.1", - "@rollup/rollup-linux-arm64-musl": "4.55.1", - "@rollup/rollup-linux-loong64-gnu": "4.55.1", - "@rollup/rollup-linux-loong64-musl": "4.55.1", - "@rollup/rollup-linux-ppc64-gnu": "4.55.1", - "@rollup/rollup-linux-ppc64-musl": "4.55.1", - "@rollup/rollup-linux-riscv64-gnu": "4.55.1", - "@rollup/rollup-linux-riscv64-musl": "4.55.1", - "@rollup/rollup-linux-s390x-gnu": "4.55.1", - "@rollup/rollup-linux-x64-gnu": "4.55.1", - "@rollup/rollup-linux-x64-musl": "4.55.1", - "@rollup/rollup-openbsd-x64": "4.55.1", - "@rollup/rollup-openharmony-arm64": "4.55.1", - "@rollup/rollup-win32-arm64-msvc": "4.55.1", - "@rollup/rollup-win32-ia32-msvc": "4.55.1", - "@rollup/rollup-win32-x64-gnu": "4.55.1", - "@rollup/rollup-win32-x64-msvc": "4.55.1", - "fsevents": "~2.3.2" - } - }, - "node_modules/router": { - "version": "2.2.0", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "depd": "^2.0.0", - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/router/node_modules/debug": { - "version": "4.4.3", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/router/node_modules/path-to-regexp": { - "version": "8.3.0", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rw": { - "version": "1.3.3", - "license": "BSD-3-Clause" - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "license": "MIT" - }, - "node_modules/scheduler": { - "version": "0.23.2", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/semver": { - "version": "7.7.3", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "0.19.2", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.1", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "~2.4.1", - "range-parser": "~1.2.1", - "statuses": "~2.0.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "license": "MIT" - }, - "node_modules/serve-static": { - "version": "1.16.3", - "license": "MIT", - "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "~0.19.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "license": "ISC" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.1.0", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/siginfo": { - "version": "2.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "dev": true, - "license": "ISC" - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "dev": true, - "license": "MIT" - }, - "node_modules/slash": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/socket.io": { - "version": "4.8.3", - "license": "MIT", - "dependencies": { - "accepts": "~1.3.4", - "base64id": "~2.0.0", - "cors": "~2.8.5", - "debug": "~4.4.1", - "engine.io": "~6.6.0", - "socket.io-adapter": "~2.5.2", - "socket.io-parser": "~4.2.4" - }, - "engines": { - "node": ">=10.2.0" - } - }, - "node_modules/socket.io-adapter": { - "version": "2.5.6", - "license": "MIT", - "dependencies": { - "debug": "~4.4.1", - "ws": "~8.18.3" - } - }, - "node_modules/socket.io-adapter/node_modules/debug": { - "version": "4.4.3", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/socket.io-client": { - "version": "4.8.3", - "license": "MIT", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.4.1", - "engine.io-client": "~6.6.1", - "socket.io-parser": "~4.2.4" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/socket.io-client/node_modules/debug": { - "version": "4.4.3", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/socket.io-parser": { - "version": "4.2.5", - "license": "MIT", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.4.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/socket.io-parser/node_modules/debug": { - "version": "4.4.3", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/socket.io/node_modules/debug": { - "version": "4.4.3", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.13", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/space-separated-tokens": { - "version": "2.0.2", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/sparse-bitfield": { - "version": "3.0.3", - "license": "MIT", - "dependencies": { - "memory-pager": "^1.0.2" - } - }, - "node_modules/split2": { - "version": "4.2.0", - "license": "ISC", - "engines": { - "node": ">= 10.x" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/sqlstring": { - "version": "2.3.1", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/stack-utils": { - "version": "2.0.6", - "dev": true, - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/stackback": { - "version": "0.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/standard-as-callback": { - "version": "2.1.0", - "license": "MIT" - }, - "node_modules/statuses": { - "version": "2.0.2", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/std-env": { - "version": "3.10.0", - "dev": true, - "license": "MIT" - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "license": "MIT" - }, - "node_modules/string-length": { - "version": "4.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/stringify-entities": { - "version": "4.0.4", - "license": "MIT", - "dependencies": { - "character-entities-html4": "^2.0.0", - "character-entities-legacy": "^3.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-literal": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "js-tokens": "^9.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/strip-literal/node_modules/js-tokens": { - "version": "9.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/style-to-js": { - "version": "1.1.21", - "license": "MIT", - "dependencies": { - "style-to-object": "1.0.14" - } - }, - "node_modules/style-to-object": { - "version": "1.0.14", - "license": "MIT", - "dependencies": { - "inline-style-parser": "0.2.7" - } - }, - "node_modules/sucrase": { - "version": "3.35.1", - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "tinyglobby": "^0.2.11", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/superagent": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-10.3.0.tgz", - "integrity": "sha512-B+4Ik7ROgVKrQsXTV0Jwp2u+PXYLSlqtDAhYnkkD+zn3yg8s/zjA2MeGayPoY/KICrbitwneDHrjSotxKL+0XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "component-emitter": "^1.3.1", - "cookiejar": "^2.1.4", - "debug": "^4.3.7", - "fast-safe-stringify": "^2.1.1", - "form-data": "^4.0.5", - "formidable": "^3.5.4", - "methods": "^1.1.2", - "mime": "2.6.0", - "qs": "^6.14.1" - }, - "engines": { - "node": ">=14.18.0" - } - }, - "node_modules/superagent/node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "dev": true, - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/supertest": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.2.2.tgz", - "integrity": "sha512-oK8WG9diS3DlhdUkcFn4tkNIiIbBx9lI2ClF8K+b2/m8Eyv47LSawxUzZQSNKUrVb2KsqeTDCcjAAVPYaSLVTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "cookie-signature": "^1.2.2", - "methods": "^1.1.2", - "superagent": "^10.3.0" - }, - "engines": { - "node": ">=14.18.0" - } - }, - "node_modules/supertest/node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.6.0" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tailwind-merge": { - "version": "3.4.0", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/dcastil" - } - }, - "node_modules/tailwindcss": { - "version": "3.4.19", - "license": "MIT", - "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.2", - "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.4.47", - "postcss-import": "^15.1.0", - "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", - "postcss-nested": "^6.2.0", - "postcss-selector-parser": "^6.1.2", - "resolve": "^1.22.8", - "sucrase": "^3.35.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tailwindcss-animate": { - "version": "1.0.7", - "license": "MIT", - "peerDependencies": { - "tailwindcss": ">=3.0.0 || insiders" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "dev": true, - "license": "ISC", - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/test-exclude/node_modules/brace-expansion": { - "version": "1.1.12", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/test-exclude/node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "dev": true, - "license": "MIT" - }, - "node_modules/thenify": { - "version": "3.3.1", - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "license": "MIT", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/tiny-invariant": { - "version": "1.3.3", - "license": "MIT" - }, - "node_modules/tinybench": { - "version": "2.9.0", - "dev": true, - "license": "MIT" - }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/tinypool": { - "version": "0.8.4", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tinyspy": { - "version": "2.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tmpl": { - "version": "1.0.5", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/topojson-client": { - "version": "3.1.0", - "license": "ISC", - "dependencies": { - "commander": "2" - }, - "bin": { - "topo2geo": "bin/topo2geo", - "topomerge": "bin/topomerge", - "topoquantize": "bin/topoquantize" - } - }, - "node_modules/topojson-client/node_modules/commander": { - "version": "2.20.3", - "license": "MIT" - }, - "node_modules/tr46": { - "version": "5.1.1", - "license": "MIT", - "dependencies": { - "punycode": "^2.3.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/tree-kill": { - "version": "1.2.2", - "dev": true, - "license": "MIT", - "bin": { - "tree-kill": "cli.js" - } - }, - "node_modules/trim-lines": { - "version": "3.0.1", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/trough": { - "version": "2.2.0", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/ts-api-utils": { - "version": "1.4.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "license": "Apache-2.0" - }, - "node_modules/ts-jest": { - "version": "29.4.6", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.6.tgz", - "integrity": "sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==", - "dev": true, - "license": "MIT", - "dependencies": { - "bs-logger": "^0.2.6", - "fast-json-stable-stringify": "^2.1.0", - "handlebars": "^4.7.8", - "json5": "^2.2.3", - "lodash.memoize": "^4.1.2", - "make-error": "^1.3.6", - "semver": "^7.7.3", - "type-fest": "^4.41.0", - "yargs-parser": "^21.1.1" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/transform": "^29.0.0 || ^30.0.0", - "@jest/types": "^29.0.0 || ^30.0.0", - "babel-jest": "^29.0.0 || ^30.0.0", - "jest": "^29.0.0 || ^30.0.0", - "jest-util": "^29.0.0 || ^30.0.0", - "typescript": ">=4.3 <6" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@jest/transform": { - "optional": true - }, - "@jest/types": { - "optional": true - }, - "babel-jest": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "jest-util": { - "optional": true - } - } - }, - "node_modules/ts-jest/node_modules/type-fest": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", - "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ts-node": { - "version": "10.9.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/ts-node-dev": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "chokidar": "^3.5.1", - "dynamic-dedupe": "^0.3.0", - "minimist": "^1.2.6", - "mkdirp": "^1.0.4", - "resolve": "^1.0.0", - "rimraf": "^2.6.1", - "source-map-support": "^0.5.12", - "tree-kill": "^1.2.2", - "ts-node": "^10.4.0", - "tsconfig": "^7.0.0" - }, - "bin": { - "ts-node-dev": "lib/bin.js", - "tsnd": "lib/bin.js" - }, - "engines": { - "node": ">=0.8.0" - }, - "peerDependencies": { - "node-notifier": "*", - "typescript": "*" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/ts-node-dev/node_modules/rimraf": { - "version": "2.7.1", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/ts-node/node_modules/arg": { - "version": "4.1.3", - "dev": true, - "license": "MIT" - }, - "node_modules/tsconfig": { - "version": "7.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/strip-bom": "^3.0.0", - "@types/strip-json-comments": "0.0.30", - "strip-bom": "^3.0.0", - "strip-json-comments": "^2.0.0" - } - }, - "node_modules/tsconfig/node_modules/strip-bom": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/tsconfig/node_modules/strip-json-comments": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "license": "0BSD" - }, - "node_modules/tsx": { - "version": "4.21.0", - "devOptional": true, - "license": "MIT", - "dependencies": { - "esbuild": "~0.27.0", - "get-tsconfig": "^4.7.5" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "license": "MIT", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/ufo": { - "version": "1.6.2", - "dev": true, - "license": "MIT" - }, - "node_modules/uglify-js": { - "version": "3.19.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", - "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/uid2": { - "version": "1.0.0", - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/undici-types": { - "version": "6.21.0", - "license": "MIT" - }, - "node_modules/unified": { - "version": "11.0.5", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "bail": "^2.0.0", - "devlop": "^1.0.0", - "extend": "^3.0.0", - "is-plain-obj": "^4.0.0", - "trough": "^2.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-is": { - "version": "6.0.1", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-position": { - "version": "5.0.0", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit": { - "version": "5.0.0", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit-parents": { - "version": "6.0.2", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.2.3", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/use-callback-ref": { - "version": "1.3.3", - "license": "MIT", - "dependencies": { - "tslib": "^2.0.0" - }, - "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 - } - } - }, - "node_modules/use-sidecar": { - "version": "1.1.3", - "license": "MIT", - "dependencies": { - "detect-node-es": "^1.1.0", - "tslib": "^2.0.0" - }, - "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 - } - } - }, - "node_modules/use-sync-external-store": { - "version": "1.6.0", - "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "license": "MIT" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/v8-to-istanbul": { - "version": "9.3.0", - "dev": true, - "license": "ISC", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^2.0.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/vega": { - "version": "6.2.0", - "license": "BSD-3-Clause", - "dependencies": { - "vega-crossfilter": "~5.1.0", - "vega-dataflow": "~6.1.0", - "vega-encode": "~5.1.0", - "vega-event-selector": "~4.0.0", - "vega-expression": "~6.1.0", - "vega-force": "~5.1.0", - "vega-format": "~2.1.0", - "vega-functions": "~6.1.0", - "vega-geo": "~5.1.0", - "vega-hierarchy": "~5.1.0", - "vega-label": "~2.1.0", - "vega-loader": "~5.1.0", - "vega-parser": "~7.1.0", - "vega-projection": "~2.1.0", - "vega-regression": "~2.1.0", - "vega-runtime": "~7.1.0", - "vega-scale": "~8.1.0", - "vega-scenegraph": "~5.1.0", - "vega-statistics": "~2.0.0", - "vega-time": "~3.1.0", - "vega-transforms": "~5.1.0", - "vega-typings": "~2.1.0", - "vega-util": "~2.1.0", - "vega-view": "~6.1.0", - "vega-view-transforms": "~5.1.0", - "vega-voronoi": "~5.1.0", - "vega-wordcloud": "~5.1.0" - }, - "funding": { - "url": "https://app.hubspot.com/payments/GyPC972GD9Rt" - } - }, - "node_modules/vega-canvas": { - "version": "2.0.0", - "license": "BSD-3-Clause" - }, - "node_modules/vega-crossfilter": { - "version": "5.1.0", - "license": "BSD-3-Clause", - "dependencies": { - "d3-array": "^3.2.4", - "vega-dataflow": "^6.1.0", - "vega-util": "^2.1.0" - } - }, - "node_modules/vega-dataflow": { - "version": "6.1.0", - "license": "BSD-3-Clause", - "dependencies": { - "vega-format": "^2.1.0", - "vega-loader": "^5.1.0", - "vega-util": "^2.1.0" - } - }, - "node_modules/vega-embed": { - "version": "7.1.0", - "license": "BSD-3-Clause", - "dependencies": { - "fast-json-patch": "^3.1.1", - "json-stringify-pretty-compact": "^4.0.0", - "semver": "^7.7.2", - "tslib": "^2.8.1", - "vega-interpreter": "^2.0.0", - "vega-schema-url-parser": "^3.0.2", - "vega-themes": "3.0.0", - "vega-tooltip": "1.0.0" - }, - "funding": { - "url": "https://app.hubspot.com/payments/GyPC972GD9Rt" - }, - "peerDependencies": { - "vega": "*", - "vega-lite": "*" - } - }, - "node_modules/vega-encode": { - "version": "5.1.0", - "license": "BSD-3-Clause", - "dependencies": { - "d3-array": "^3.2.4", - "d3-interpolate": "^3.0.1", - "vega-dataflow": "^6.1.0", - "vega-scale": "^8.1.0", - "vega-util": "^2.1.0" - } - }, - "node_modules/vega-event-selector": { - "version": "4.0.0", - "license": "BSD-3-Clause" - }, - "node_modules/vega-expression": { - "version": "6.1.0", - "license": "BSD-3-Clause", - "dependencies": { - "@types/estree": "^1.0.8", - "vega-util": "^2.1.0" - } - }, - "node_modules/vega-force": { - "version": "5.1.0", - "license": "BSD-3-Clause", - "dependencies": { - "d3-force": "^3.0.0", - "vega-dataflow": "^6.1.0", - "vega-util": "^2.1.0" - } - }, - "node_modules/vega-format": { - "version": "2.1.0", - "license": "BSD-3-Clause", - "dependencies": { - "d3-array": "^3.2.4", - "d3-format": "^3.1.0", - "d3-time-format": "^4.1.0", - "vega-time": "^3.1.0", - "vega-util": "^2.1.0" - } - }, - "node_modules/vega-functions": { - "version": "6.1.1", - "license": "BSD-3-Clause", - "dependencies": { - "d3-array": "^3.2.4", - "d3-color": "^3.1.0", - "d3-geo": "^3.1.1", - "vega-dataflow": "^6.1.0", - "vega-expression": "^6.1.0", - "vega-scale": "^8.1.0", - "vega-scenegraph": "^5.1.0", - "vega-selections": "^6.1.0", - "vega-statistics": "^2.0.0", - "vega-time": "^3.1.0", - "vega-util": "^2.1.0" - } - }, - "node_modules/vega-geo": { - "version": "5.1.0", - "license": "BSD-3-Clause", - "dependencies": { - "d3-array": "^3.2.4", - "d3-color": "^3.1.0", - "d3-geo": "^3.1.1", - "vega-canvas": "^2.0.0", - "vega-dataflow": "^6.1.0", - "vega-projection": "^2.1.0", - "vega-statistics": "^2.0.0", - "vega-util": "^2.1.0" - } - }, - "node_modules/vega-hierarchy": { - "version": "5.1.0", - "license": "BSD-3-Clause", - "dependencies": { - "d3-hierarchy": "^3.1.2", - "vega-dataflow": "^6.1.0", - "vega-util": "^2.1.0" - } - }, - "node_modules/vega-interpreter": { - "version": "2.2.1", - "license": "BSD-3-Clause", - "dependencies": { - "vega-util": "^2.1.0" - } - }, - "node_modules/vega-label": { - "version": "2.1.0", - "license": "BSD-3-Clause", - "dependencies": { - "vega-canvas": "^2.0.0", - "vega-dataflow": "^6.1.0", - "vega-scenegraph": "^5.1.0", - "vega-util": "^2.1.0" - } - }, - "node_modules/vega-lite": { - "version": "6.4.1", - "license": "BSD-3-Clause", - "dependencies": { - "json-stringify-pretty-compact": "~4.0.0", - "tslib": "~2.8.1", - "vega-event-selector": "~4.0.0", - "vega-expression": "~6.1.0", - "vega-util": "~2.1.0", - "yargs": "~18.0.0" - }, - "bin": { - "vl2pdf": "bin/vl2pdf", - "vl2png": "bin/vl2png", - "vl2svg": "bin/vl2svg", - "vl2vg": "bin/vl2vg" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://app.hubspot.com/payments/GyPC972GD9Rt" - }, - "peerDependencies": { - "vega": "^6.0.0" - } - }, - "node_modules/vega-lite/node_modules/ansi-regex": { - "version": "6.2.2", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/vega-lite/node_modules/ansi-styles": { - "version": "6.2.3", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/vega-lite/node_modules/cliui": { - "version": "9.0.1", - "license": "ISC", - "dependencies": { - "string-width": "^7.2.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/vega-lite/node_modules/emoji-regex": { - "version": "10.6.0", - "license": "MIT" - }, - "node_modules/vega-lite/node_modules/string-width": { - "version": "7.2.0", - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/vega-lite/node_modules/strip-ansi": { - "version": "7.1.2", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/vega-lite/node_modules/wrap-ansi": { - "version": "9.0.2", - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/vega-lite/node_modules/yargs": { - "version": "18.0.0", - "license": "MIT", - "dependencies": { - "cliui": "^9.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "string-width": "^7.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^22.0.0" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=23" - } - }, - "node_modules/vega-lite/node_modules/yargs-parser": { - "version": "22.0.0", - "license": "ISC", - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=23" - } - }, - "node_modules/vega-loader": { - "version": "5.1.0", - "license": "BSD-3-Clause", - "dependencies": { - "d3-dsv": "^3.0.1", - "topojson-client": "^3.1.0", - "vega-format": "^2.1.0", - "vega-util": "^2.1.0" - } - }, - "node_modules/vega-parser": { - "version": "7.1.0", - "license": "BSD-3-Clause", - "dependencies": { - "vega-dataflow": "^6.1.0", - "vega-event-selector": "^4.0.0", - "vega-functions": "^6.1.0", - "vega-scale": "^8.1.0", - "vega-util": "^2.1.0" - } - }, - "node_modules/vega-projection": { - "version": "2.1.0", - "license": "BSD-3-Clause", - "dependencies": { - "d3-geo": "^3.1.1", - "d3-geo-projection": "^4.0.0", - "vega-scale": "^8.1.0" - } - }, - "node_modules/vega-regression": { - "version": "2.1.0", - "license": "BSD-3-Clause", - "dependencies": { - "d3-array": "^3.2.4", - "vega-dataflow": "^6.1.0", - "vega-statistics": "^2.0.0", - "vega-util": "^2.1.0" - } - }, - "node_modules/vega-runtime": { - "version": "7.1.0", - "license": "BSD-3-Clause", - "dependencies": { - "vega-dataflow": "^6.1.0", - "vega-util": "^2.1.0" - } - }, - "node_modules/vega-scale": { - "version": "8.1.0", - "license": "BSD-3-Clause", - "dependencies": { - "d3-array": "^3.2.4", - "d3-interpolate": "^3.0.1", - "d3-scale": "^4.0.2", - "d3-scale-chromatic": "^3.1.0", - "vega-time": "^3.1.0", - "vega-util": "^2.1.0" - } - }, - "node_modules/vega-scenegraph": { - "version": "5.1.0", - "license": "BSD-3-Clause", - "dependencies": { - "d3-path": "^3.1.0", - "d3-shape": "^3.2.0", - "vega-canvas": "^2.0.0", - "vega-loader": "^5.1.0", - "vega-scale": "^8.1.0", - "vega-util": "^2.1.0" - } - }, - "node_modules/vega-schema-url-parser": { - "version": "3.0.2", - "license": "BSD-3-Clause" - }, - "node_modules/vega-selections": { - "version": "6.1.2", - "license": "BSD-3-Clause", - "dependencies": { - "d3-array": "3.2.4", - "vega-expression": "^6.1.0", - "vega-util": "^2.1.0" - } - }, - "node_modules/vega-statistics": { - "version": "2.0.0", - "license": "BSD-3-Clause", - "dependencies": { - "d3-array": "^3.2.4" - } - }, - "node_modules/vega-themes": { - "version": "3.0.0", - "license": "BSD-3-Clause", - "funding": { - "url": "https://app.hubspot.com/payments/GyPC972GD9Rt" - }, - "peerDependencies": { - "vega": "*", - "vega-lite": "*" - } - }, - "node_modules/vega-time": { - "version": "3.1.0", - "license": "BSD-3-Clause", - "dependencies": { - "d3-array": "^3.2.4", - "d3-time": "^3.1.0", - "vega-util": "^2.1.0" - } - }, - "node_modules/vega-tooltip": { - "version": "1.0.0", - "license": "BSD-3-Clause", - "dependencies": { - "vega-util": "^2.0.0" - }, - "funding": { - "url": "https://app.hubspot.com/payments/GyPC972GD9Rt" - } - }, - "node_modules/vega-transforms": { - "version": "5.1.0", - "license": "BSD-3-Clause", - "dependencies": { - "d3-array": "^3.2.4", - "vega-dataflow": "^6.1.0", - "vega-statistics": "^2.0.0", - "vega-time": "^3.1.0", - "vega-util": "^2.1.0" - } - }, - "node_modules/vega-typings": { - "version": "2.1.0", - "license": "BSD-3-Clause", - "dependencies": { - "@types/geojson": "7946.0.16", - "vega-event-selector": "^4.0.0", - "vega-expression": "^6.1.0", - "vega-util": "^2.1.0" - } - }, - "node_modules/vega-util": { - "version": "2.1.0", - "license": "BSD-3-Clause" - }, - "node_modules/vega-view": { - "version": "6.1.0", - "license": "BSD-3-Clause", - "dependencies": { - "d3-array": "^3.2.4", - "d3-timer": "^3.0.1", - "vega-dataflow": "^6.1.0", - "vega-format": "^2.1.0", - "vega-functions": "^6.1.0", - "vega-runtime": "^7.1.0", - "vega-scenegraph": "^5.1.0", - "vega-util": "^2.1.0" - } - }, - "node_modules/vega-view-transforms": { - "version": "5.1.0", - "license": "BSD-3-Clause", - "dependencies": { - "vega-dataflow": "^6.1.0", - "vega-scenegraph": "^5.1.0", - "vega-util": "^2.1.0" - } - }, - "node_modules/vega-voronoi": { - "version": "5.1.0", - "license": "BSD-3-Clause", - "dependencies": { - "d3-delaunay": "^6.0.4", - "vega-dataflow": "^6.1.0", - "vega-util": "^2.1.0" - } - }, - "node_modules/vega-wordcloud": { - "version": "5.1.0", - "license": "BSD-3-Clause", - "dependencies": { - "vega-canvas": "^2.0.0", - "vega-dataflow": "^6.1.0", - "vega-scale": "^8.1.0", - "vega-statistics": "^2.0.0", - "vega-util": "^2.1.0" - } - }, - "node_modules/vfile": { - "version": "6.0.3", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/vfile-message": { - "version": "4.0.3", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/victory-vendor": { - "version": "37.3.6", - "license": "MIT AND ISC", - "dependencies": { - "@types/d3-array": "^3.0.3", - "@types/d3-ease": "^3.0.0", - "@types/d3-interpolate": "^3.0.1", - "@types/d3-scale": "^4.0.2", - "@types/d3-shape": "^3.1.0", - "@types/d3-time": "^3.0.0", - "@types/d3-timer": "^3.0.0", - "d3-array": "^3.1.6", - "d3-ease": "^3.0.1", - "d3-interpolate": "^3.0.1", - "d3-scale": "^4.0.2", - "d3-shape": "^3.1.0", - "d3-time": "^3.0.0", - "d3-timer": "^3.0.1" - } - }, - "node_modules/vite": { - "version": "5.4.21", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "node_modules/vite-node": { - "version": "1.6.1", - "dev": true, - "license": "MIT", - "dependencies": { - "cac": "^6.7.14", - "debug": "^4.3.4", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "vite": "^5.0.0" - }, - "bin": { - "vite-node": "vite-node.mjs" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/esbuild": { - "version": "0.21.5", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" - } - }, - "node_modules/vitest": { - "version": "1.6.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/expect": "1.6.1", - "@vitest/runner": "1.6.1", - "@vitest/snapshot": "1.6.1", - "@vitest/spy": "1.6.1", - "@vitest/utils": "1.6.1", - "acorn-walk": "^8.3.2", - "chai": "^4.3.10", - "debug": "^4.3.4", - "execa": "^8.0.1", - "local-pkg": "^0.5.0", - "magic-string": "^0.30.5", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "std-env": "^3.5.0", - "strip-literal": "^2.0.0", - "tinybench": "^2.5.1", - "tinypool": "^0.8.3", - "vite": "^5.0.0", - "vite-node": "1.6.1", - "why-is-node-running": "^2.2.2" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.6.1", - "@vitest/ui": "1.6.1", - "happy-dom": "*", - "jsdom": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - } - } - }, - "node_modules/vitest/node_modules/execa": { - "version": "8.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/vitest/node_modules/get-stream": { - "version": "8.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/vitest/node_modules/human-signals": { - "version": "5.0.0", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=16.17.0" - } - }, - "node_modules/vitest/node_modules/is-stream": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/vitest/node_modules/mimic-fn": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/vitest/node_modules/npm-run-path": { - "version": "5.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/vitest/node_modules/onetime": { - "version": "6.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/vitest/node_modules/path-key": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/vitest/node_modules/signal-exit": { - "version": "4.1.0", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/vitest/node_modules/strip-final-newline": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/walker": { - "version": "1.0.8", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "makeerror": "1.0.12" - } - }, - "node_modules/webidl-conversions": { - "version": "7.0.0", - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-url": { - "version": "14.2.0", - "license": "MIT", - "dependencies": { - "tr46": "^5.1.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/which": { - "version": "2.0.2", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "license": "ISC" - }, - "node_modules/write-file-atomic": { - "version": "4.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/ws": { - "version": "8.18.3", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xmlhttprequest-ssl": { - "version": "2.1.2", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/xtend": { - "version": "4.0.2", - "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "dev": true, - "license": "ISC" - }, - "node_modules/yaml": { - "version": "2.8.2", - "devOptional": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, - "node_modules/yargs": { - "version": "17.7.2", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zod": { - "version": "4.3.5", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-to-json-schema": { - "version": "3.25.1", - "license": "ISC", - "peerDependencies": { - "zod": "^3.25 || ^4" - } - }, - "node_modules/zustand": { - "version": "5.0.10", - "license": "MIT", - "engines": { - "node": ">=12.20.0" - }, - "peerDependencies": { - "@types/react": ">=18.0.0", - "immer": ">=9.0.6", - "react": ">=18.0.0", - "use-sync-external-store": ">=1.2.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "immer": { - "optional": true - }, - "react": { - "optional": true - }, - "use-sync-external-store": { - "optional": true - } - } - }, - "node_modules/zwitch": { - "version": "2.0.4", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - } - } -} From 1e23057849b7b1f18d4351d1ff77b7c0dbbc4a54 Mon Sep 17 00:00:00 2001 From: Red Rose <146128882+RED-ROSE515@users.noreply.github.com> Date: Wed, 21 Jan 2026 10:59:56 -0800 Subject: [PATCH 10/27] fix: update package lock file --- package-lock.json | 14500 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 14500 insertions(+) create mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..558220b2 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,14500 @@ +{ + "name": "hive", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "hive", + "version": "0.1.0", + "license": "Apache-2.0", + "workspaces": [ + "honeycomb", + "hive" + ], + "devDependencies": { + "@types/node": "^20.10.0", + "tsx": "^4.7.0", + "typescript": "^5.3.0", + "yaml": "^2.3.0" + }, + "engines": { + "node": ">=20.0.0", + "npm": ">=10.0.0" + } + }, + "hive": { + "version": "1.0.0", + "dependencies": { + "@acho-inc/administration": "^1.0.7", + "@modelcontextprotocol/sdk": "^1.25.2", + "@socket.io/redis-adapter": "^8.2.1", + "@socket.io/redis-emitter": "^5.1.0", + "compression": "^1.7.4", + "cors": "^2.8.5", + "dotenv": "^16.3.1", + "express": "^4.18.2", + "helmet": "^7.1.0", + "http-errors": "^2.0.0", + "ioredis": "^5.3.2", + "jsonwebtoken": "^9.0.2", + "mongodb": "^6.3.0", + "morgan": "^1.10.0", + "passport": "^0.7.0", + "passport-jwt": "^4.0.1", + "pg": "^8.11.3", + "socket.io": "^4.6.1", + "zod": "^4.3.5" + }, + "devDependencies": { + "@types/compression": "^1.7.5", + "@types/cors": "^2.8.17", + "@types/express": "^4.17.21", + "@types/jest": "^30.0.0", + "@types/jsonwebtoken": "^9.0.5", + "@types/morgan": "^1.9.9", + "@types/node": "^20.10.0", + "@types/passport": "^1.0.16", + "@types/passport-jwt": "^4.0.1", + "@types/pg": "^8.10.9", + "@types/supertest": "^6.0.3", + "@typescript-eslint/eslint-plugin": "^6.14.0", + "@typescript-eslint/parser": "^6.14.0", + "eslint": "^8.56.0", + "jest": "^29.7.0", + "supertest": "^7.2.2", + "ts-jest": "^29.4.6", + "ts-node": "^10.9.2", + "ts-node-dev": "^2.0.0", + "typescript": "^5.3.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "honeycomb": { + "version": "0.1.0", + "dependencies": { + "@hookform/resolvers": "^5.2.2", + "@radix-ui/react-avatar": "^1.1.11", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-dropdown-menu": "^2.1.16", + "@radix-ui/react-label": "^2.1.8", + "@radix-ui/react-popover": "^1.1.15", + "@radix-ui/react-progress": "^1.1.8", + "@radix-ui/react-scroll-area": "^1.2.10", + "@radix-ui/react-select": "^2.2.6", + "@radix-ui/react-separator": "^1.1.8", + "@radix-ui/react-slot": "^1.2.4", + "@radix-ui/react-switch": "^1.2.6", + "@radix-ui/react-tabs": "^1.1.13", + "@radix-ui/react-tooltip": "^1.2.8", + "@tanstack/react-query": "^5.90.16", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "date-fns": "^4.1.0", + "lucide-react": "^0.562.0", + "react": "^18.2.0", + "react-day-picker": "^9.13.0", + "react-dom": "^18.2.0", + "react-hook-form": "^7.71.0", + "react-markdown": "^10.1.0", + "react-router-dom": "^6.21.0", + "react-vega": "^8.0.0", + "recharts": "^3.6.0", + "socket.io-client": "^4.8.3", + "tailwind-merge": "^3.4.0", + "tailwindcss-animate": "^1.0.7", + "vega": "^6.2.0", + "vega-embed": "^7.1.0", + "vega-lite": "^6.4.1", + "zod": "^4.3.5", + "zustand": "^5.0.10" + }, + "devDependencies": { + "@testing-library/jest-dom": "^6.4.2", + "@testing-library/react": "^14.2.1", + "@testing-library/user-event": "^14.5.2", + "@types/react": "^18.2.43", + "@types/react-dom": "^18.2.17", + "@typescript-eslint/eslint-plugin": "^6.14.0", + "@typescript-eslint/parser": "^6.14.0", + "@vitejs/plugin-react": "^4.2.1", + "autoprefixer": "^10.4.23", + "eslint": "^8.55.0", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.5", + "jsdom": "^24.0.0", + "postcss": "^8.5.6", + "tailwindcss": "^3.4.19", + "typescript": "^5.3.0", + "vite": "^5.0.8", + "vitest": "^1.1.0" + } + }, + "node_modules/@acho-inc/administration": { + "version": "1.0.7", + "license": "UNLICENSED", + "dependencies": { + "bcrypt": "^6.0.0", + "ioredis": "^5.3.2", + "jsonwebtoken": "^9.0.2", + "mongodb": "^6.3.0", + "mysql": "^2.18.1", + "nodemailer": "^6.9.8", + "passport": "^0.7.0", + "passport-jwt": "^4.0.1", + "pg": "^8.11.3" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "express": "^4.18.0" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.4.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@asamuzakjp/css-color": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.3", + "@csstools/css-color-parser": "^3.0.9", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "lru-cache": "^10.4.3" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { + "version": "10.4.3", + "dev": true, + "license": "ISC" + }, + "node_modules/@babel/code-frame": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/generator": "^7.28.6", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.6" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/generator": "^7.28.6", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.6", + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "5.1.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.1.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.1.0", + "@csstools/css-calc": "^2.1.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@date-fns/tz": { + "version": "1.4.1", + "license": "MIT" + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.2", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.12", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.3", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.4", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.6", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.4" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "license": "MIT" + }, + "node_modules/@hono/node-server": { + "version": "1.19.9", + "license": "MIT", + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, + "node_modules/@hookform/resolvers": { + "version": "5.2.2", + "license": "MIT", + "dependencies": { + "@standard-schema/utils": "^0.3.0" + }, + "peerDependencies": { + "react-hook-form": "^7.55.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.12", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@ioredis/commands": { + "version": "1.5.0", + "license": "MIT" + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.2", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/core/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/pretty-format": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/node_modules/react-is": { + "version": "18.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@jest/diff-sequences": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", + "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/pattern": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", + "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-regex-util": "30.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/pattern/node_modules/jest-regex-util": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", + "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.25.3", + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.0.1", + "express-rate-limit": "^7.5.0", + "jose": "^6.1.1", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/accepts": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/body-parser": { + "version": "2.2.2", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.1", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/content-disposition": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/cookie-signature": { + "version": "1.2.2", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/debug": { + "version": "4.4.3", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/express": { + "version": "5.2.1", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/finalhandler": { + "version": "2.1.1", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/fresh": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/iconv-lite": { + "version": "0.7.2", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/media-typer": { + "version": "1.1.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/merge-descriptors": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/mime-types": { + "version": "3.0.2", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/negotiator": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/send": { + "version": "1.2.1", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/serve-static": { + "version": "2.2.1", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/type-is": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.4.5", + "license": "MIT", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@paralleldrive/cuid2": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz", + "integrity": "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.1.5" + } + }, + "node_modules/@radix-ui/number": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "license": "MIT" + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-arrow/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-arrow/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar": { + "version": "1.1.11", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.3", + "@radix-ui/react-primitive": "2.1.4", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.3", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.15", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.11", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.16", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.3", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label": { + "version": "2.1.8", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu": { + "version": "2.1.16", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover": { + "version": "1.1.15", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.8", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.5", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-progress": { + "version": "1.1.8", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.3", + "@radix-ui/react-primitive": "2.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.11", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area": { + "version": "1.2.10", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select": { + "version": "2.2.6", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-separator": { + "version": "1.1.8", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.2.4", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch": { + "version": "1.2.6", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.13", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip": { + "version": "1.2.8", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-is-hydrated": { + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/@reduxjs/toolkit": { + "version": "2.11.2", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@standard-schema/utils": "^0.3.0", + "immer": "^11.0.0", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" + }, + "peerDependencies": { + "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 + } + } + }, + "node_modules/@reduxjs/toolkit/node_modules/immer": { + "version": "11.1.3", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/@remix-run/router": { + "version": "1.23.2", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.55.2", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.55.2", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "license": "MIT" + }, + "node_modules/@socket.io/redis-adapter": { + "version": "8.3.0", + "license": "MIT", + "dependencies": { + "debug": "~4.3.1", + "notepack.io": "~3.0.1", + "uid2": "1.0.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "socket.io-adapter": "^2.5.4" + } + }, + "node_modules/@socket.io/redis-emitter": { + "version": "5.1.0", + "license": "MIT", + "dependencies": { + "debug": "~4.3.1", + "notepack.io": "~3.0.1", + "socket.io-parser": "~4.2.1" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "license": "MIT" + }, + "node_modules/@standard-schema/utils": { + "version": "0.3.0", + "license": "MIT" + }, + "node_modules/@tanstack/query-core": { + "version": "5.90.19", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.90.19", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.90.19" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, + "node_modules/@testing-library/dom": { + "version": "10.4.1", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.9.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "picocolors": "^1.1.1", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/react": { + "version": "14.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "@testing-library/dom": "^9.0.0", + "@types/react-dom": "^18.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@testing-library/react/node_modules/@testing-library/dom": { + "version": "9.3.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.1.3", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@testing-library/react/node_modules/aria-query": { + "version": "5.1.3", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/@testing-library/user-event": { + "version": "14.6.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.12", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/compression": { + "version": "1.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cookiejar": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz", + "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.8", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "license": "MIT" + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.25", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "^1" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "license": "MIT" + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "30.0.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-30.0.0.tgz", + "integrity": "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^30.0.0", + "pretty-format": "^30.0.0" + } + }, + "node_modules/@types/jest/node_modules/@jest/expect-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", + "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/@jest/types": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", + "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/pattern": "30.0.1", + "@jest/schemas": "30.0.5", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/@sinclair/typebox": { + "version": "0.34.47", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.47.tgz", + "integrity": "sha512-ZGIBQ+XDvO5JQku9wmwtabcVTHJsgSWAHYtVuM9pBNNR5E88v6Jcj/llpmsjivig5X8A8HHOb4/mbEKPS5EvAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jest/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@types/jest/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@types/jest/node_modules/expect": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", + "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "30.2.0", + "@jest/get-type": "30.1.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-diff": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", + "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/diff-sequences": "30.0.1", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-matcher-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", + "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "jest-diff": "30.2.0", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-message-util": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", + "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.2.0", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "micromatch": "^4.0.8", + "pretty-format": "30.2.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-mock": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz", + "integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-util": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@types/jest/node_modules/pretty-format": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.10", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*", + "@types/node": "*" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/methods": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", + "integrity": "sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/morgan": { + "version": "1.9.10", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.30", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/passport": { + "version": "1.0.17", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/passport-jwt": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/jsonwebtoken": "*", + "@types/passport-strategy": "*" + } + }, + "node_modules/@types/passport-strategy": { + "version": "0.2.38", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*", + "@types/passport": "*" + } + }, + "node_modules/@types/pg": { + "version": "8.16.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "license": "MIT" + }, + "node_modules/@types/qs": { + "version": "6.14.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.27", + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "devOptional": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@types/semver": { + "version": "7.7.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.10", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "<1" + } + }, + "node_modules/@types/serve-static/node_modules/@types/send": { + "version": "0.17.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/strip-bom": { + "version": "3.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/strip-json-comments": { + "version": "0.0.30", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/superagent": { + "version": "8.1.9", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-8.1.9.tgz", + "integrity": "sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/cookiejar": "^2.1.5", + "@types/methods": "^1.1.4", + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/supertest": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-6.0.3.tgz", + "integrity": "sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/methods": "^1.1.4", + "@types/superagent": "^8.1.0" + } + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "license": "MIT" + }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.6", + "license": "MIT" + }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "license": "MIT" + }, + "node_modules/@types/whatwg-url": { + "version": "11.0.5", + "license": "MIT", + "dependencies": { + "@types/webidl-conversions": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.21.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.21.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.21.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.21.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.21.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.21.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.21.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.21.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "license": "ISC" + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/@vitest/expect": { + "version": "1.6.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "1.6.1", + "@vitest/utils": "1.6.1", + "chai": "^4.3.10" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "1.6.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "1.6.1", + "p-limit": "^5.0.0", + "pathe": "^1.1.1" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner/node_modules/p-limit": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vitest/runner/node_modules/yocto-queue": { + "version": "1.2.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vitest/snapshot": { + "version": "1.6.1", + "dev": true, + "license": "MIT", + "dependencies": { + "magic-string": "^0.30.5", + "pathe": "^1.1.1", + "pretty-format": "^29.7.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@vitest/snapshot/node_modules/pretty-format": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@vitest/snapshot/node_modules/react-is": { + "version": "18.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitest/spy": { + "version": "1.6.1", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^2.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "1.6.1", + "dev": true, + "license": "MIT", + "dependencies": { + "diff-sequences": "^29.6.3", + "estree-walker": "^3.0.3", + "loupe": "^2.3.7", + "pretty-format": "^29.7.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@vitest/utils/node_modules/pretty-format": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@vitest/utils/node_modules/react-is": { + "version": "18.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/accepts": { + "version": "1.3.8", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "8.17.1", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/aria-query": { + "version": "5.3.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/array-union": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/autoprefixer": { + "version": "10.4.23", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.1", + "caniuse-lite": "^1.0.30001760", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/base64id": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.16", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/basic-auth": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/basic-auth/node_modules/safe-buffer": { + "version": "5.1.2", + "license": "MIT" + }, + "node_modules/bcrypt": { + "version": "6.0.0", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.3.0", + "node-gyp-build": "^4.8.4" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/bignumber.js": { + "version": "9.0.0", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "1.20.4", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/body-parser/node_modules/raw-body": { + "version": "2.5.3", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/bson": { + "version": "6.10.4", + "license": "Apache-2.0", + "engines": { + "node": ">=16.20.1" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "license": "BSD-3-Clause" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.1.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001765", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chai": { + "version": "4.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chai/node_modules/type-detect": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "dev": true, + "license": "MIT" + }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cluster-key-slot": { + "version": "1.1.2", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/co": { + "version": "4.6.0", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "4.1.1", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.1", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/confbox": { + "version": "0.1.8", + "dev": true, + "license": "MIT" + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.7", + "license": "MIT" + }, + "node_modules/cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "dev": true, + "license": "MIT" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.5", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/create-jest": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "dev": true, + "license": "MIT" + }, + "node_modules/cssesc": { + "version": "3.0.0", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssstyle": { + "version": "4.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^3.2.0", + "rrweb-cssom": "^0.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cssstyle/node_modules/rrweb-cssom": { + "version": "0.8.0", + "dev": true, + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "license": "MIT" + }, + "node_modules/d3-array": { + "version": "3.2.4", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "license": "ISC", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "license": "ISC", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv/node_modules/commander": { + "version": "7.2.0", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/d3-dsv/node_modules/iconv-lite": { + "version": "0.6.3", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "license": "ISC", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo-projection": { + "version": "4.0.0", + "license": "ISC", + "dependencies": { + "commander": "7", + "d3-array": "1 - 3", + "d3-geo": "1.12.0 - 3" + }, + "bin": { + "geo2svg": "bin/geo2svg.js", + "geograticule": "bin/geograticule.js", + "geoproject": "bin/geoproject.js", + "geoquantize": "bin/geoquantize.js", + "geostitch": "bin/geostitch.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo-projection/node_modules/commander": { + "version": "7.2.0", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/data-urls": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/date-fns": { + "version": "4.1.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/date-fns-jalali": { + "version": "4.1.0-0", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.3.7", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "dev": true, + "license": "MIT" + }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "license": "MIT" + }, + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dedent": { + "version": "1.7.1", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-eql": { + "version": "4.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-equal": { + "version": "2.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.5", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.2", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-equal/node_modules/isarray": { + "version": "2.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/deep-is": { + "version": "0.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delaunator": { + "version": "5.0.1", + "license": "ISC", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/denque": { + "version": "2.1.0", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "license": "MIT" + }, + "node_modules/devlop": { + "version": "1.1.0", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "license": "Apache-2.0" + }, + "node_modules/diff": { + "version": "4.0.4", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "license": "MIT" + }, + "node_modules/doctrine": { + "version": "3.0.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "dev": true, + "license": "MIT" + }, + "node_modules/dotenv": { + "version": "16.6.1", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/dynamic-dedupe": { + "version": "0.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.267", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/engine.io": { + "version": "6.6.5", + "license": "MIT", + "dependencies": { + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.7.2", + "cors": "~2.8.5", + "debug": "~4.4.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.18.3" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-client": { + "version": "6.6.4", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.18.3", + "xmlhttprequest-ssl": "~2.1.1" + } + }, + "node_modules/engine.io-client/node_modules/debug": { + "version": "4.4.3", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io-client/node_modules/ws": { + "version": "8.18.3", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/debug": { + "version": "4.4.3", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io/node_modules/ws": { + "version": "8.18.3", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/entities": { + "version": "6.0.1", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-get-iterator": { + "version": "1.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-get-iterator/node_modules/isarray": { + "version": "2.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-toolkit": { + "version": "1.44.0", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, + "node_modules/esbuild": { + "version": "0.27.2", + "devOptional": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@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.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "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.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.26", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.12", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "license": "MIT" + }, + "node_modules/eventsource": { + "version": "3.0.7", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.6", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/express": { + "version": "4.22.1", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.14.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "7.5.1", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/extend": { + "version": "3.0.2", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-patch": { + "version": "3.1.1", + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.20.1", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.2", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/find-up": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "dev": true, + "license": "ISC" + }, + "node_modules/for-each": { + "version": "0.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/formidable": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.4.tgz", + "integrity": "sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@paralleldrive/cuid2": "^2.2.2", + "dezalgo": "^1.0.4", + "once": "^1.4.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.4.0", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.0", + "devOptional": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.12", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "dev": true, + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.6", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/helmet": { + "version": "7.2.0", + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/hive": { + "resolved": "hive", + "link": true + }, + "node_modules/honeycomb": { + "resolved": "honeycomb", + "link": true + }, + "node_modules/hono": { + "version": "4.11.4", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/html-url-attributes": { + "version": "3.0.1", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/http-errors": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immer": { + "version": "10.2.0", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "license": "ISC" + }, + "node_modules/inline-style-parser": { + "version": "0.2.7", + "license": "MIT" + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/ioredis": { + "version": "5.9.2", + "license": "MIT", + "dependencies": { + "@ioredis/commands": "1.5.0", + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.4", + "denque": "^2.1.0", + "lodash.defaults": "^4.2.0", + "lodash.isarguments": "^3.1.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" + }, + "engines": { + "node": ">=12.22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ioredis" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-arguments": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/is-promise": { + "version": "4.0.0", + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/pretty-format": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/react-is": { + "version": "18.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/pretty-format": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-config/node_modules/react-is": { + "version": "18.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/pretty-format": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/node_modules/react-is": { + "version": "18.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/pretty-format": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each/node_modules/react-is": { + "version": "18.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-leak-detector/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-leak-detector/node_modules/pretty-format": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-leak-detector/node_modules/react-is": { + "version": "18.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/pretty-format": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/react-is": { + "version": "18.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/pretty-format": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/node_modules/react-is": { + "version": "18.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/pretty-format": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/react-is": { + "version": "18.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-util": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-validate/node_modules/pretty-format": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/react-is": { + "version": "18.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jiti": { + "version": "1.21.7", + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/jose": { + "version": "6.1.3", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "24.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "cssstyle": "^4.0.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.12", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.7.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.4", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^2.11.2" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "license": "BSD-2-Clause" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stringify-pretty-compact": { + "version": "4.0.0", + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.3", + "license": "MIT", + "dependencies": { + "jws": "^4.0.1", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "license": "MIT" + }, + "node_modules/local-pkg": { + "version": "0.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "mlly": "^1.7.3", + "pkg-types": "^1.2.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "license": "MIT" + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "license": "MIT" + }, + "node_modules/lodash.isarguments": { + "version": "3.1.0", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "license": "MIT" + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/loupe": { + "version": "2.3.7", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "0.562.0", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/lz-string": { + "version": "1.5.0", + "dev": true, + "license": "MIT", + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "dev": true, + "license": "ISC" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.2", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memory-pager": { + "version": "1.5.0", + "license": "MIT" + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromark": { + "version": "4.0.2", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types/node_modules/mime-db": { + "version": "1.52.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "9.0.3", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mlly": { + "version": "1.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.15.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.1" + } + }, + "node_modules/mlly/node_modules/pathe": { + "version": "2.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/mongodb": { + "version": "6.21.0", + "license": "Apache-2.0", + "dependencies": { + "@mongodb-js/saslprep": "^1.3.0", + "bson": "^6.10.4", + "mongodb-connection-string-url": "^3.0.2" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.3.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "3.0.2", + "license": "Apache-2.0", + "dependencies": { + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^14.1.0 || ^13.0.0" + } + }, + "node_modules/morgan": { + "version": "1.10.1", + "license": "MIT", + "dependencies": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.1.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/morgan/node_modules/debug": { + "version": "2.6.9", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/morgan/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/morgan/node_modules/on-finished": { + "version": "2.3.0", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "license": "MIT" + }, + "node_modules/mysql": { + "version": "2.18.1", + "license": "MIT", + "dependencies": { + "bignumber.js": "9.0.0", + "readable-stream": "2.3.7", + "safe-buffer": "5.1.2", + "sqlstring": "2.3.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mysql/node_modules/safe-buffer": { + "version": "5.1.2", + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.4", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-addon-api": { + "version": "8.5.0", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.27", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemailer": { + "version": "6.10.1", + "license": "MIT-0", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/notepack.io": { + "version": "3.0.1", + "license": "MIT" + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nwsapi": { + "version": "2.2.23", + "dev": true, + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.6", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.1.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-entities": { + "version": "4.0.2", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "license": "MIT" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "7.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/passport": { + "version": "0.7.0", + "license": "MIT", + "dependencies": { + "passport-strategy": "1.x.x", + "pause": "0.0.1", + "utils-merge": "^1.0.1" + }, + "engines": { + "node": ">= 0.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" + } + }, + "node_modules/passport-jwt": { + "version": "4.0.1", + "license": "MIT", + "dependencies": { + "jsonwebtoken": "^9.0.0", + "passport-strategy": "^1.0.0" + } + }, + "node_modules/passport-strategy": { + "version": "1.0.0", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "1.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/pause": { + "version": "0.0.1" + }, + "node_modules/pg": { + "version": "8.17.2", + "license": "MIT", + "dependencies": { + "pg-connection-string": "^2.10.1", + "pg-pool": "^3.11.0", + "pg-protocol": "^1.11.0", + "pg-types": "2.2.0", + "pgpass": "1.0.5" + }, + "engines": { + "node": ">= 16.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.3.0" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.3.0", + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.10.1", + "license": "MIT" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.11.0", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.11.0", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-types": { + "version": "1.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/pkg-types/node_modules/pathe": { + "version": "2.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.1.0", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "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 + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "license": "MIT" + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pretty-format/node_modules/react-is": { + "version": "17.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "license": "MIT" + }, + "node_modules/prompts": { + "version": "2.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/property-information": { + "version": "7.1.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/psl": { + "version": "1.15.0", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.14.1", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/range-parser": { + "version": "1.2.1", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.7.2", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/react": { + "version": "18.3.1", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-day-picker": { + "version": "9.13.0", + "license": "MIT", + "dependencies": { + "@date-fns/tz": "^1.4.1", + "date-fns": "^4.1.0", + "date-fns-jalali": "^4.1.0-0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/gpbl" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-hook-form": { + "version": "7.71.1", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18 || ^19" + } + }, + "node_modules/react-is": { + "version": "19.2.3", + "license": "MIT", + "peer": true + }, + "node_modules/react-markdown": { + "version": "10.1.0", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "html-url-attributes": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=18", + "react": ">=18" + } + }, + "node_modules/react-redux": { + "version": "9.2.0", + "license": "MIT", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25 || ^19", + "react": "^18.0 || ^19", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-remove-scroll": { + "version": "2.7.2", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "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 + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-router": { + "version": "6.30.3", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.30.3", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.2", + "react-router": "6.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "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 + } + } + }, + "node_modules/react-vega": { + "version": "8.0.0", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "react": "^17 || ^18 || ^19", + "react-dom": "^17 || ^18 || ^19", + "vega-embed": "^7" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/recharts": { + "version": "3.6.0", + "license": "MIT", + "workspaces": [ + "www" + ], + "dependencies": { + "@reduxjs/toolkit": "1.x.x || 2.x.x", + "clsx": "^2.1.1", + "decimal.js-light": "^2.5.1", + "es-toolkit": "^1.39.3", + "eventemitter3": "^5.0.1", + "immer": "^10.1.1", + "react-redux": "8.x.x || 9.x.x", + "reselect": "5.1.1", + "tiny-invariant": "^1.3.3", + "use-sync-external-store": "^1.2.2", + "victory-vendor": "^37.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/redis-errors": { + "version": "1.2.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/redis-parser": { + "version": "3.0.0", + "license": "MIT", + "dependencies": { + "redis-errors": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/redux": { + "version": "5.0.1", + "license": "MIT" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "license": "MIT", + "peerDependencies": { + "redux": "^5.0.0" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.2", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/reselect": { + "version": "5.1.1", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.11", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "devOptional": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "license": "Unlicense" + }, + "node_modules/rollup": { + "version": "4.55.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.55.2", + "@rollup/rollup-android-arm64": "4.55.2", + "@rollup/rollup-darwin-arm64": "4.55.2", + "@rollup/rollup-darwin-x64": "4.55.2", + "@rollup/rollup-freebsd-arm64": "4.55.2", + "@rollup/rollup-freebsd-x64": "4.55.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.55.2", + "@rollup/rollup-linux-arm-musleabihf": "4.55.2", + "@rollup/rollup-linux-arm64-gnu": "4.55.2", + "@rollup/rollup-linux-arm64-musl": "4.55.2", + "@rollup/rollup-linux-loong64-gnu": "4.55.2", + "@rollup/rollup-linux-loong64-musl": "4.55.2", + "@rollup/rollup-linux-ppc64-gnu": "4.55.2", + "@rollup/rollup-linux-ppc64-musl": "4.55.2", + "@rollup/rollup-linux-riscv64-gnu": "4.55.2", + "@rollup/rollup-linux-riscv64-musl": "4.55.2", + "@rollup/rollup-linux-s390x-gnu": "4.55.2", + "@rollup/rollup-linux-x64-gnu": "4.55.2", + "@rollup/rollup-linux-x64-musl": "4.55.2", + "@rollup/rollup-openbsd-x64": "4.55.2", + "@rollup/rollup-openharmony-arm64": "4.55.2", + "@rollup/rollup-win32-arm64-msvc": "4.55.2", + "@rollup/rollup-win32-ia32-msvc": "4.55.2", + "@rollup/rollup-win32-x64-gnu": "4.55.2", + "@rollup/rollup-win32-x64-msvc": "4.55.2", + "fsevents": "~2.3.2" + } + }, + "node_modules/router": { + "version": "2.2.0", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/router/node_modules/debug": { + "version": "4.4.3", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/router/node_modules/path-to-regexp": { + "version": "8.3.0", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/rrweb-cssom": { + "version": "0.7.1", + "dev": true, + "license": "MIT" + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rw": { + "version": "1.3.3", + "license": "BSD-3-Clause" + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "license": "MIT" + }, + "node_modules/saxes": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "7.7.3", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.19.2", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/serve-static": { + "version": "1.16.3", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "dev": true, + "license": "ISC" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/socket.io": { + "version": "4.8.3", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.4.1", + "engine.io": "~6.6.0", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.6", + "license": "MIT", + "dependencies": { + "debug": "~4.4.1", + "ws": "~8.18.3" + } + }, + "node_modules/socket.io-adapter/node_modules/debug": { + "version": "4.4.3", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-adapter/node_modules/ws": { + "version": "8.18.3", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/socket.io-client": { + "version": "4.8.3", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1", + "engine.io-client": "~6.6.1", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-client/node_modules/debug": { + "version": "4.4.3", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.5", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "4.4.3", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io/node_modules/debug": { + "version": "4.4.3", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "license": "MIT", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/sqlstring": { + "version": "2.3.1", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/standard-as-callback": { + "version": "2.1.0", + "license": "MIT" + }, + "node_modules/statuses": { + "version": "2.0.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/std-env": { + "version": "3.10.0", + "dev": true, + "license": "MIT" + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "license": "MIT" + }, + "node_modules/string-length": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-literal": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/strip-literal/node_modules/js-tokens": { + "version": "9.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/style-to-js": { + "version": "1.1.21", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.14" + } + }, + "node_modules/style-to-object": { + "version": "1.0.14", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.7" + } + }, + "node_modules/sucrase": { + "version": "3.35.1", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/superagent": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-10.3.0.tgz", + "integrity": "sha512-B+4Ik7ROgVKrQsXTV0Jwp2u+PXYLSlqtDAhYnkkD+zn3yg8s/zjA2MeGayPoY/KICrbitwneDHrjSotxKL+0XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "component-emitter": "^1.3.1", + "cookiejar": "^2.1.4", + "debug": "^4.3.7", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.5", + "formidable": "^3.5.4", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.14.1" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/superagent/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/supertest": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.2.2.tgz", + "integrity": "sha512-oK8WG9diS3DlhdUkcFn4tkNIiIbBx9lI2ClF8K+b2/m8Eyv47LSawxUzZQSNKUrVb2KsqeTDCcjAAVPYaSLVTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cookie-signature": "^1.2.2", + "methods": "^1.1.2", + "superagent": "^10.3.0" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/supertest/node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "dev": true, + "license": "MIT" + }, + "node_modules/tailwind-merge": { + "version": "3.4.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.19", + "license": "MIT", + "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.2", + "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.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss-animate": { + "version": "1.0.7", + "license": "MIT", + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.12", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/thenify": { + "version": "3.3.1", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "license": "MIT" + }, + "node_modules/tinybench": { + "version": "2.9.0", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tinypool": { + "version": "0.8.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/topojson-client": { + "version": "3.1.0", + "license": "ISC", + "dependencies": { + "commander": "2" + }, + "bin": { + "topo2geo": "bin/topo2geo", + "topomerge": "bin/topomerge", + "topoquantize": "bin/topoquantize" + } + }, + "node_modules/topojson-client/node_modules/commander": { + "version": "2.20.3", + "license": "MIT" + }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "5.1.1", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/ts-api-utils": { + "version": "1.4.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "license": "Apache-2.0" + }, + "node_modules/ts-jest": { + "version": "29.4.6", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.6.tgz", + "integrity": "sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "^0.2.6", + "fast-json-stable-stringify": "^2.1.0", + "handlebars": "^4.7.8", + "json5": "^2.2.3", + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.7.3", + "type-fest": "^4.41.0", + "yargs-parser": "^21.1.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0 || ^30.0.0", + "@jest/types": "^29.0.0 || ^30.0.0", + "babel-jest": "^29.0.0 || ^30.0.0", + "jest": "^29.0.0 || ^30.0.0", + "jest-util": "^29.0.0 || ^30.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jest-util": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node-dev": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.1", + "dynamic-dedupe": "^0.3.0", + "minimist": "^1.2.6", + "mkdirp": "^1.0.4", + "resolve": "^1.0.0", + "rimraf": "^2.6.1", + "source-map-support": "^0.5.12", + "tree-kill": "^1.2.2", + "ts-node": "^10.4.0", + "tsconfig": "^7.0.0" + }, + "bin": { + "ts-node-dev": "lib/bin.js", + "tsnd": "lib/bin.js" + }, + "engines": { + "node": ">=0.8.0" + }, + "peerDependencies": { + "node-notifier": "*", + "typescript": "*" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/ts-node-dev/node_modules/rimraf": { + "version": "2.7.1", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/ts-node/node_modules/arg": { + "version": "4.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/tsconfig": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/strip-bom": "^3.0.0", + "@types/strip-json-comments": "0.0.30", + "strip-bom": "^3.0.0", + "strip-json-comments": "^2.0.0" + } + }, + "node_modules/tsconfig/node_modules/strip-bom": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/tsconfig/node_modules/strip-json-comments": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "license": "0BSD" + }, + "node_modules/tsx": { + "version": "4.21.0", + "devOptional": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ufo": { + "version": "1.6.3", + "dev": true, + "license": "MIT" + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/uid2": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "license": "MIT" + }, + "node_modules/unified": { + "version": "11.0.5", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universalify": { + "version": "0.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "dev": true, + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "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 + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "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 + } + } + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vega": { + "version": "6.2.0", + "license": "BSD-3-Clause", + "dependencies": { + "vega-crossfilter": "~5.1.0", + "vega-dataflow": "~6.1.0", + "vega-encode": "~5.1.0", + "vega-event-selector": "~4.0.0", + "vega-expression": "~6.1.0", + "vega-force": "~5.1.0", + "vega-format": "~2.1.0", + "vega-functions": "~6.1.0", + "vega-geo": "~5.1.0", + "vega-hierarchy": "~5.1.0", + "vega-label": "~2.1.0", + "vega-loader": "~5.1.0", + "vega-parser": "~7.1.0", + "vega-projection": "~2.1.0", + "vega-regression": "~2.1.0", + "vega-runtime": "~7.1.0", + "vega-scale": "~8.1.0", + "vega-scenegraph": "~5.1.0", + "vega-statistics": "~2.0.0", + "vega-time": "~3.1.0", + "vega-transforms": "~5.1.0", + "vega-typings": "~2.1.0", + "vega-util": "~2.1.0", + "vega-view": "~6.1.0", + "vega-view-transforms": "~5.1.0", + "vega-voronoi": "~5.1.0", + "vega-wordcloud": "~5.1.0" + }, + "funding": { + "url": "https://app.hubspot.com/payments/GyPC972GD9Rt" + } + }, + "node_modules/vega-canvas": { + "version": "2.0.0", + "license": "BSD-3-Clause" + }, + "node_modules/vega-crossfilter": { + "version": "5.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "^3.2.4", + "vega-dataflow": "^6.1.0", + "vega-util": "^2.1.0" + } + }, + "node_modules/vega-dataflow": { + "version": "6.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "vega-format": "^2.1.0", + "vega-loader": "^5.1.0", + "vega-util": "^2.1.0" + } + }, + "node_modules/vega-embed": { + "version": "7.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "fast-json-patch": "^3.1.1", + "json-stringify-pretty-compact": "^4.0.0", + "semver": "^7.7.2", + "tslib": "^2.8.1", + "vega-interpreter": "^2.0.0", + "vega-schema-url-parser": "^3.0.2", + "vega-themes": "3.0.0", + "vega-tooltip": "1.0.0" + }, + "funding": { + "url": "https://app.hubspot.com/payments/GyPC972GD9Rt" + }, + "peerDependencies": { + "vega": "*", + "vega-lite": "*" + } + }, + "node_modules/vega-encode": { + "version": "5.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "^3.2.4", + "d3-interpolate": "^3.0.1", + "vega-dataflow": "^6.1.0", + "vega-scale": "^8.1.0", + "vega-util": "^2.1.0" + } + }, + "node_modules/vega-event-selector": { + "version": "4.0.0", + "license": "BSD-3-Clause" + }, + "node_modules/vega-expression": { + "version": "6.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "@types/estree": "^1.0.8", + "vega-util": "^2.1.0" + } + }, + "node_modules/vega-force": { + "version": "5.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "d3-force": "^3.0.0", + "vega-dataflow": "^6.1.0", + "vega-util": "^2.1.0" + } + }, + "node_modules/vega-format": { + "version": "2.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "^3.2.4", + "d3-format": "^3.1.0", + "d3-time-format": "^4.1.0", + "vega-time": "^3.1.0", + "vega-util": "^2.1.0" + } + }, + "node_modules/vega-functions": { + "version": "6.1.1", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "^3.2.4", + "d3-color": "^3.1.0", + "d3-geo": "^3.1.1", + "vega-dataflow": "^6.1.0", + "vega-expression": "^6.1.0", + "vega-scale": "^8.1.0", + "vega-scenegraph": "^5.1.0", + "vega-selections": "^6.1.0", + "vega-statistics": "^2.0.0", + "vega-time": "^3.1.0", + "vega-util": "^2.1.0" + } + }, + "node_modules/vega-geo": { + "version": "5.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "^3.2.4", + "d3-color": "^3.1.0", + "d3-geo": "^3.1.1", + "vega-canvas": "^2.0.0", + "vega-dataflow": "^6.1.0", + "vega-projection": "^2.1.0", + "vega-statistics": "^2.0.0", + "vega-util": "^2.1.0" + } + }, + "node_modules/vega-hierarchy": { + "version": "5.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "d3-hierarchy": "^3.1.2", + "vega-dataflow": "^6.1.0", + "vega-util": "^2.1.0" + } + }, + "node_modules/vega-interpreter": { + "version": "2.2.1", + "license": "BSD-3-Clause", + "dependencies": { + "vega-util": "^2.1.0" + } + }, + "node_modules/vega-label": { + "version": "2.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "vega-canvas": "^2.0.0", + "vega-dataflow": "^6.1.0", + "vega-scenegraph": "^5.1.0", + "vega-util": "^2.1.0" + } + }, + "node_modules/vega-lite": { + "version": "6.4.2", + "license": "BSD-3-Clause", + "dependencies": { + "json-stringify-pretty-compact": "~4.0.0", + "tslib": "~2.8.1", + "vega-event-selector": "~4.0.0", + "vega-expression": "~6.1.0", + "vega-util": "~2.1.0", + "yargs": "~18.0.0" + }, + "bin": { + "vl2pdf": "bin/vl2pdf", + "vl2png": "bin/vl2png", + "vl2svg": "bin/vl2svg", + "vl2vg": "bin/vl2vg" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://app.hubspot.com/payments/GyPC972GD9Rt" + }, + "peerDependencies": { + "vega": "^6.0.0" + } + }, + "node_modules/vega-lite/node_modules/ansi-regex": { + "version": "6.2.2", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/vega-lite/node_modules/ansi-styles": { + "version": "6.2.3", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/vega-lite/node_modules/cliui": { + "version": "9.0.1", + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/vega-lite/node_modules/emoji-regex": { + "version": "10.6.0", + "license": "MIT" + }, + "node_modules/vega-lite/node_modules/string-width": { + "version": "7.2.0", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vega-lite/node_modules/strip-ansi": { + "version": "7.1.2", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/vega-lite/node_modules/wrap-ansi": { + "version": "9.0.2", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/vega-lite/node_modules/yargs": { + "version": "18.0.0", + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^7.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/vega-lite/node_modules/yargs-parser": { + "version": "22.0.0", + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/vega-loader": { + "version": "5.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "d3-dsv": "^3.0.1", + "topojson-client": "^3.1.0", + "vega-format": "^2.1.0", + "vega-util": "^2.1.0" + } + }, + "node_modules/vega-parser": { + "version": "7.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "vega-dataflow": "^6.1.0", + "vega-event-selector": "^4.0.0", + "vega-functions": "^6.1.0", + "vega-scale": "^8.1.0", + "vega-util": "^2.1.0" + } + }, + "node_modules/vega-projection": { + "version": "2.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "d3-geo": "^3.1.1", + "d3-geo-projection": "^4.0.0", + "vega-scale": "^8.1.0" + } + }, + "node_modules/vega-regression": { + "version": "2.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "^3.2.4", + "vega-dataflow": "^6.1.0", + "vega-statistics": "^2.0.0", + "vega-util": "^2.1.0" + } + }, + "node_modules/vega-runtime": { + "version": "7.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "vega-dataflow": "^6.1.0", + "vega-util": "^2.1.0" + } + }, + "node_modules/vega-scale": { + "version": "8.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "^3.2.4", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-scale-chromatic": "^3.1.0", + "vega-time": "^3.1.0", + "vega-util": "^2.1.0" + } + }, + "node_modules/vega-scenegraph": { + "version": "5.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "d3-path": "^3.1.0", + "d3-shape": "^3.2.0", + "vega-canvas": "^2.0.0", + "vega-loader": "^5.1.0", + "vega-scale": "^8.1.0", + "vega-util": "^2.1.0" + } + }, + "node_modules/vega-schema-url-parser": { + "version": "3.0.2", + "license": "BSD-3-Clause" + }, + "node_modules/vega-selections": { + "version": "6.1.2", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "3.2.4", + "vega-expression": "^6.1.0", + "vega-util": "^2.1.0" + } + }, + "node_modules/vega-statistics": { + "version": "2.0.0", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "^3.2.4" + } + }, + "node_modules/vega-themes": { + "version": "3.0.0", + "license": "BSD-3-Clause", + "funding": { + "url": "https://app.hubspot.com/payments/GyPC972GD9Rt" + }, + "peerDependencies": { + "vega": "*", + "vega-lite": "*" + } + }, + "node_modules/vega-time": { + "version": "3.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "^3.2.4", + "d3-time": "^3.1.0", + "vega-util": "^2.1.0" + } + }, + "node_modules/vega-tooltip": { + "version": "1.0.0", + "license": "BSD-3-Clause", + "dependencies": { + "vega-util": "^2.0.0" + }, + "funding": { + "url": "https://app.hubspot.com/payments/GyPC972GD9Rt" + } + }, + "node_modules/vega-transforms": { + "version": "5.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "^3.2.4", + "vega-dataflow": "^6.1.0", + "vega-statistics": "^2.0.0", + "vega-time": "^3.1.0", + "vega-util": "^2.1.0" + } + }, + "node_modules/vega-typings": { + "version": "2.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "@types/geojson": "7946.0.16", + "vega-event-selector": "^4.0.0", + "vega-expression": "^6.1.0", + "vega-util": "^2.1.0" + } + }, + "node_modules/vega-util": { + "version": "2.1.0", + "license": "BSD-3-Clause" + }, + "node_modules/vega-view": { + "version": "6.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "^3.2.4", + "d3-timer": "^3.0.1", + "vega-dataflow": "^6.1.0", + "vega-format": "^2.1.0", + "vega-functions": "^6.1.0", + "vega-runtime": "^7.1.0", + "vega-scenegraph": "^5.1.0", + "vega-util": "^2.1.0" + } + }, + "node_modules/vega-view-transforms": { + "version": "5.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "vega-dataflow": "^6.1.0", + "vega-scenegraph": "^5.1.0", + "vega-util": "^2.1.0" + } + }, + "node_modules/vega-voronoi": { + "version": "5.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "d3-delaunay": "^6.0.4", + "vega-dataflow": "^6.1.0", + "vega-util": "^2.1.0" + } + }, + "node_modules/vega-wordcloud": { + "version": "5.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "vega-canvas": "^2.0.0", + "vega-dataflow": "^6.1.0", + "vega-scale": "^8.1.0", + "vega-statistics": "^2.0.0", + "vega-util": "^2.1.0" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/victory-vendor": { + "version": "37.3.6", + "license": "MIT AND ISC", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, + "node_modules/vite": { + "version": "5.4.21", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "1.6.1", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.4", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "vite": "^5.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.21.5", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/vitest": { + "version": "1.6.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "1.6.1", + "@vitest/runner": "1.6.1", + "@vitest/snapshot": "1.6.1", + "@vitest/spy": "1.6.1", + "@vitest/utils": "1.6.1", + "acorn-walk": "^8.3.2", + "chai": "^4.3.10", + "debug": "^4.3.4", + "execa": "^8.0.1", + "local-pkg": "^0.5.0", + "magic-string": "^0.30.5", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "std-env": "^3.5.0", + "strip-literal": "^2.0.0", + "tinybench": "^2.5.1", + "tinypool": "^0.8.3", + "vite": "^5.0.0", + "vite-node": "1.6.1", + "why-is-node-running": "^2.2.2" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "1.6.1", + "@vitest/ui": "1.6.1", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/execa": { + "version": "8.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/vitest/node_modules/get-stream": { + "version": "8.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vitest/node_modules/human-signals": { + "version": "5.0.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/vitest/node_modules/is-stream": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vitest/node_modules/mimic-fn": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vitest/node_modules/npm-run-path": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vitest/node_modules/onetime": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vitest/node_modules/path-key": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vitest/node_modules/signal-exit": { + "version": "4.1.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/vitest/node_modules/strip-final-newline": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "14.2.0", + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/which": { + "version": "2.0.2", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.20", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/ws": { + "version": "8.19.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.1.2", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "dev": true, + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.8.2", + "devOptional": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.3.5", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.1", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25 || ^4" + } + }, + "node_modules/zustand": { + "version": "5.0.10", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} From 6d516efe934991d3b44720b25c8d4f7abe3a4344 Mon Sep 17 00:00:00 2001 From: Vincent Jiang Date: Wed, 21 Jan 2026 13:47:21 -0800 Subject: [PATCH 11/27] new changes --- docs/quizzes/README.md | 8 ++ docs/quizzes/job-post.md | 157 ++++++++++++++++++++++++++ docs/quizzes/job-software-engineer.md | 143 +++++++++++++++++++++++ 3 files changed, 308 insertions(+) create mode 100644 docs/quizzes/job-post.md create mode 100644 docs/quizzes/job-software-engineer.md diff --git a/docs/quizzes/README.md b/docs/quizzes/README.md index 030b4387..78542bae 100644 --- a/docs/quizzes/README.md +++ b/docs/quizzes/README.md @@ -2,6 +2,14 @@ Welcome to the Aden Engineering Challenges! These quizzes are designed for students and applicants who want to join the Aden team or contribute to our open-source projects. +--- + +## 💼 We're Hiring! + +**[Software Development Engineer](./job-post.md)** - Full-stack TypeScript, React, Node.js, AI agents + +--- + ## How It Works 1. **Choose your track** based on your interests and skill level diff --git a/docs/quizzes/job-post.md b/docs/quizzes/job-post.md new file mode 100644 index 00000000..d7a42028 --- /dev/null +++ b/docs/quizzes/job-post.md @@ -0,0 +1,157 @@ +# 🚀 Software Development Engineer + +**Location:** San Francisco, CA (Hybrid) or Remote +**Type:** Full-time +**Team:** Engineering + +--- + +## About Aden + +We're building the future of AI agents. Aden is an open-source framework for creating self-improving, production-ready AI agents with built-in cost controls, human-in-the-loop capabilities, and comprehensive observability. + +Our mission: Make AI agents reliable enough for real-world production use. + +--- + +## The Role + +We're looking for a Software Development Engineer to help build and scale our AI agent platform. You'll work across the full stack, from our React dashboard to our Node.js backend, contributing to core infrastructure that powers autonomous AI systems. + +This is an opportunity to work on cutting-edge AI infrastructure alongside a small, experienced team passionate about shipping great software. + +--- + +## What You'll Do + +- Build and maintain features across our full-stack TypeScript codebase +- Design and implement APIs for agent management, monitoring, and control +- Work with real-time systems (WebSockets, event streaming) +- Optimize database performance (TimescaleDB, MongoDB, Redis) +- Contribute to our Model Context Protocol (MCP) server and tooling +- Collaborate on architecture decisions for scalability and reliability +- Write clean, tested, well-documented code +- Participate in code reviews and help maintain code quality + +--- + +## Tech Stack + +**Frontend (Honeycomb Dashboard)** +- React 18 + TypeScript +- Vite +- Tailwind CSS + Radix UI +- Zustand (state management) +- TanStack Query +- Recharts + Vega (data visualization) +- Socket.io (real-time updates) + +**Backend (Hive)** +- Node.js + Express + TypeScript +- Socket.io (WebSocket) +- Model Context Protocol (MCP) +- Zod (validation) +- Passport + JWT (authentication) + +**Data Layer** +- TimescaleDB (time-series metrics) +- MongoDB (policies, configuration) +- Redis (caching, pub/sub) + +**Infrastructure** +- Docker + Docker Compose +- Kubernetes + Kustomize +- GitHub Actions (CI/CD) +- Nginx + +--- + +## What We're Looking For + +**Required:** +- 2+ years of professional software development experience +- Strong proficiency in TypeScript and Node.js +- Experience with React and modern frontend development +- Familiarity with SQL and NoSQL databases +- Understanding of RESTful APIs and WebSocket communication +- Comfortable with Git and collaborative development workflows +- Strong problem-solving skills and attention to detail + +**Nice to Have:** +- Experience with AI/LLM applications or agent frameworks +- Knowledge of time-series databases (TimescaleDB, InfluxDB) +- Kubernetes and container orchestration experience +- Experience with real-time systems at scale +- Contributions to open-source projects +- Familiarity with Model Context Protocol (MCP) + +--- + +## What We Offer + +- Competitive salary + equity +- Health, dental, and vision insurance +- Flexible work arrangements (hybrid/remote) +- Learning & development budget +- Home office setup stipend +- Opportunity to work on open-source AI infrastructure +- Small team, big impact + +--- + +## How to Apply + +**Show us what you can do by contributing to our open-source project:** + +1. **Solve an existing issue** + - Browse our [GitHub Issues](https://github.com/adenhq/hive/issues) + - Look for issues labeled `good first issue` or `help wanted` + - Comment on the issue to claim it + - Submit a Pull Request with your solution + +2. **Create new issues** + - Found a bug? Report it with clear reproduction steps + - Have an idea? Open a feature request with your proposal + - Spotted documentation gaps? Suggest improvements + - Quality issues that show you understand the codebase stand out + +3. **Submit Pull Requests** + - Fix bugs, add features, or improve documentation + - Follow our contribution guidelines + - Write clear PR descriptions explaining your changes + - Respond to code review feedback + +4. **Submit your application:** + - Email: `careers@adenhq.com` + - Subject: `[SDE] Your Name` + - Include: + - Resume/CV + - GitHub profile + - Links to your Issues and/or PRs on our repo + - Brief intro about yourself + +5. **What happens next:** + - We review your contributions (1-2 weeks) + - Technical interview (60 min) + - Team interview (45 min) + - Offer 🎉 + +--- + +## Why Join Us? + +- **Impact:** Your code will power AI agents used by developers worldwide +- **Open Source:** Everything we build is open source +- **Learning:** Work with cutting-edge AI and distributed systems +- **Culture:** Small team, low ego, high trust, ship fast +- **Growth:** Early-stage company with room to grow + +--- + +*Aden is an equal opportunity employer. We celebrate diversity and are committed to creating an inclusive environment for all employees.* + +--- + +**Questions?** Email us at `careers@adenhq.com` or open an issue on [GitHub](https://github.com/adenhq/hive). + +Made with 🔥 Passion in San Francisco diff --git a/docs/quizzes/job-software-engineer.md b/docs/quizzes/job-software-engineer.md new file mode 100644 index 00000000..8a0fdd5b --- /dev/null +++ b/docs/quizzes/job-software-engineer.md @@ -0,0 +1,143 @@ +# 🚀 Software Development Engineer + +**Location:** San Francisco, CA (Hybrid) or Remote +**Type:** Full-time +**Team:** Engineering + +--- + +## About Aden + +We're building the future of AI agents. Aden is an open-source framework for creating self-improving, production-ready AI agents with built-in cost controls, human-in-the-loop capabilities, and comprehensive observability. + +Our mission: Make AI agents reliable enough for real-world production use. + +--- + +## The Role + +We're looking for a Software Development Engineer to help build and scale our AI agent platform. You'll work across the full stack, from our React dashboard to our Node.js backend, contributing to core infrastructure that powers autonomous AI systems. + +This is an opportunity to work on cutting-edge AI infrastructure alongside a small, experienced team passionate about shipping great software. + +--- + +## What You'll Do + +- Build and maintain features across our full-stack TypeScript codebase +- Design and implement APIs for agent management, monitoring, and control +- Work with real-time systems (WebSockets, event streaming) +- Optimize database performance (TimescaleDB, MongoDB, Redis) +- Contribute to our Model Context Protocol (MCP) server and tooling +- Collaborate on architecture decisions for scalability and reliability +- Write clean, tested, well-documented code +- Participate in code reviews and help maintain code quality + +--- + +## Tech Stack + +**Frontend (Honeycomb Dashboard)** +- React 18 + TypeScript +- Vite +- Tailwind CSS + Radix UI +- Zustand (state management) +- TanStack Query +- Recharts + Vega (data visualization) +- Socket.io (real-time updates) + +**Backend (Hive)** +- Node.js + Express + TypeScript +- Socket.io (WebSocket) +- Model Context Protocol (MCP) +- Zod (validation) +- Passport + JWT (authentication) + +**Data Layer** +- TimescaleDB (time-series metrics) +- MongoDB (policies, configuration) +- Redis (caching, pub/sub) + +**Infrastructure** +- Docker + Docker Compose +- Kubernetes + Kustomize +- GitHub Actions (CI/CD) +- Nginx + +--- + +## What We're Looking For + +**Required:** +- 2+ years of professional software development experience +- Strong proficiency in TypeScript and Node.js +- Experience with React and modern frontend development +- Familiarity with SQL and NoSQL databases +- Understanding of RESTful APIs and WebSocket communication +- Comfortable with Git and collaborative development workflows +- Strong problem-solving skills and attention to detail + +**Nice to Have:** +- Experience with AI/LLM applications or agent frameworks +- Knowledge of time-series databases (TimescaleDB, InfluxDB) +- Kubernetes and container orchestration experience +- Experience with real-time systems at scale +- Contributions to open-source projects +- Familiarity with Model Context Protocol (MCP) + +--- + +## What We Offer + +- Competitive salary + equity +- Health, dental, and vision insurance +- Flexible work arrangements (hybrid/remote) +- Learning & development budget +- Home office setup stipend +- Opportunity to work on open-source AI infrastructure +- Small team, big impact + +--- + +## How to Apply + +1. **Complete a challenge** from our [quiz collection](./README.md): + - [Getting Started](./01-getting-started.md) (required, 30 min) + - Plus ONE of: + - [Architecture Deep Dive](./02-architecture-deep-dive.md) (backend focus) + - [Frontend Challenge](./04-frontend-challenge.md) (frontend focus) + +2. **Submit your application:** + - Email: `contact@adenhq.com` + - Subject: `[SDE] Your Name` + - Include: + - Resume/CV + - GitHub profile + - Link to your completed challenge (GitHub Gist) + - Brief intro about yourself + +3. **What happens next:** + - We review your submission (1-2 weeks) + - Technical interview (60 min) + - Team interview (45 min) + - Offer 🎉 + +--- + +## Why Join Us? + +- **Impact:** Your code will power AI agents used by developers worldwide +- **Open Source:** Everything we build is open source +- **Learning:** Work with cutting-edge AI and distributed systems +- **Culture:** Small team, low ego, high trust, ship fast +- **Growth:** Early-stage company with room to grow + +--- + +*Aden is an equal opportunity employer. We celebrate diversity and are committed to creating an inclusive environment for all employees.* + +--- + +**Questions?** Email us at `careers@adenhq.com` or open an issue on [GitHub](https://github.com/adenhq/hive). + +Made with 🔥 Passion in San Francisco From cd2e64bcc886e4ca792e744534299c90879f337e Mon Sep 17 00:00:00 2001 From: Vincent Jiang Date: Wed, 21 Jan 2026 14:19:11 -0800 Subject: [PATCH 12/27] changes to readme, job posts, styling --- README.md | 15 ++ ...chitecture Diagram (github readme) (2).jpg | Bin 0 -> 258643 bytes docs/assets/aden-architecture-diagram.jpg | Bin 0 -> 258643 bytes docs/quizzes/{job-post.md => 00 job-post.md} | 0 docs/quizzes/job-software-engineer.md | 143 ------------------ 5 files changed, 15 insertions(+), 143 deletions(-) create mode 100644 docs/articles/Architecture Diagram (github readme) (2).jpg create mode 100644 docs/assets/aden-architecture-diagram.jpg rename docs/quizzes/{job-post.md => 00 job-post.md} (100%) delete mode 100644 docs/quizzes/job-software-engineer.md diff --git a/README.md b/README.md index 538a3f88..36721b25 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,21 @@ Build reliable, self-improving AI agents without hardcoding workflows. Define yo Visit [adenhq.com](https://adenhq.com) for complete documentation, examples, and guides. +## What is Aden + +

+ Aden Architecture +

+ +Aden is a platform for building, deploying, operating, and adapting AI agents: + +- **Build** - A Coding Agent generates specialized Worker Agents (Sales, Marketing, Ops) from natural language goals +- **Deploy** - Headless deployment with CI/CD integration and full API lifecycle management +- **Operate** - Real-time monitoring, observability, and runtime guardrails keep agents reliable +- **Adapt** - Continuous evaluation, supervision, and adaptation ensure agents improve over time +- **Infra** - Shared memory, LLM integrations, tools, and skills power every agent + + ## Quick Links - **[Documentation](https://docs.adenhq.com/)** - Complete guides and API reference diff --git a/docs/articles/Architecture Diagram (github readme) (2).jpg b/docs/articles/Architecture Diagram (github readme) (2).jpg new file mode 100644 index 0000000000000000000000000000000000000000..f6955c9e3db7cc0ed5da9a79057eadd1cc81f8a8 GIT binary patch literal 258643 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 cZCh- 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ⅆ4s9LByUazs_tSPq2N6uu-=U0+M;G>2 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 literal 0 HcmV?d00001 diff --git a/docs/assets/aden-architecture-diagram.jpg b/docs/assets/aden-architecture-diagram.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f6955c9e3db7cc0ed5da9a79057eadd1cc81f8a8 GIT binary patch literal 258643 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 cZCh- z4mZROADV&5O-$E-x}s+3^Y`fPGUfC-3{x`M%T)D4Ca8hyKt0-@BqmOnh7z}qVK3Pc zO9_1RqBqED#9&stQVdK!^^n^&N?f-lh|HYR@EQe!*`ydrDu%LB(V0|t)-KssS|Wwy zCJ!nb%?4uxb=eO*dZScL4W#y5lmlW%k-(iPND3f`Y{S<0vWx^sCfcia<7n5SpR4lA#C~zyP_LWpDwdA-Gl!2xU9NYG2bYP4>3H3uDJPAd9#^=Qxvc;yWGeGO@5^P?Qeuyf=;1W- z*T-p2*$bF2Wi2L9=ggBqO&NYR=D$};EdBwT(yk2-yyCGFxAg6>JaP_eshwVa%R8xS zaU{wP@XVvIp)V}HCg%r?ei5PQxG2m3k5p;9y(f_6a9Hj_cUmrO6Nz5ruA9Tq8(WPW zC=7_?>$N_)AK%O;KNjJK4(UTq>wGXCH|a8!h5`k)Q5m(R%=ZjP)cAr&CJ~f;>XYvh zn=9{l75UpEip6wAm}eweOKC5go8}V~aY}_GQJM{^itG>Gst~*^3KrsH%FTZwM;J$z zZQ%zjW@Lk$_Y`_>$E}n(ft`N|j4a_9mo8#wq6K@4_AP&dUKhYSVsY@}rP&Q^8>?SqGEZTCFulw2j zHO%t6jjY2R002jstt9>Y9_veet;3ygsk=)(m3j;Gao=%=U#1dfc`o`ATxX$9zWc($ zKNU^2euMaxL&4T=xTx;rfZ)#0uFhvd?t5fcLg!S_n&|gL#Yb-yR9!uqUL_Zdlj+cK zzj?^xz1Jj8m!vr;GOR0+p#vHf9pZSddyjL=_|%A0TfE7nnyeZ~XndeNivY-^65Q&} zpV|Dhp;;sID{#@bk%gwC>m_zhz<{o%B#9=&Oi)?`l*Tt3z8Xaw5Likky{_Pot{`&2 zKSL+s8-M+`cR}|GjpI3LbLr7NgZj(+2y>-x3{ zV%bw&VnjN)$-@{{e}h=_X#*}8=nH*=P0LWaU8BM)Grsxhh|H=&e zHMx(h4z_I6h(k7ef8OK61I#HX7hGxn*@j7wu=AQFqKf@BP}(&$S+fW4t^!Ke=?qS9 z@8yHD&STYaCRg$=g_FswS&(HQu~0G2^F@tI_MU6?{zZ!osA=V09b9FCidnDZTNuDK z5yYPApR7Rx$E)M`H_YBS2Q?F)wvmv(;JrN)V_r4Y!%p84OhX4drmdZ%GsNcT|Q5PdwpFAK(fTzllx_ z_<*QkEvE$xCI+G&n0$!V`IJxh?{5E-~l5?Ttr+6 zXPF?#^z52FNvzpj+br-@#&~gB!s@EwSeXR*m+#CBJORaTD%~HwI4F70mQQ+^mz!4v zV&D&*j?PF0_bW5}DkP3DmffDV11i0Xs8o+$ox_yIAY~w_72Tq00Hr*tnBAwYSWNr& z=MhhNI06i?#gIknvJMwy7%N}W)XSAX=vzFgU{14pZi!dkG4jgTCejDEp80o=%noFh z9&GBJurdzyVX}Y{i3fH#k&fZiz%2&&#<-W&*S;fR(tt1sMZopBxnHG5rH<=|Lr$E6 zS;xv`K-NG3kA9Ta)ymU6!PWQB=2#0JDcTX=N7F00X>+4lXWIPb(#Td8qg=F|4!arc zF-AQ6;D-&g*R#oUmexkPQwBC@G9VCQ>^_$^g(Jk4$Xi_gpv2oPKBRA5BJmm=>gkG3e8S5eVX(*-q>jmD z7v7{_3@CJr_kQBb#&56VNTTPWjARy(N=Bv)swCE%`a}(It&*l~_Ma~))4c}p1`%TR zkqqGP=4UzST>NNV^~TV?nG=;`Zm5-?d-uKKJms<;TNds1_XHnH zMM<+k0|6(D!8&I_m}WWv+`-6xYdj%(CcQJ&o!J;~&%V5n)j9eJzUUSZo-2dwBMo3T z{PXgl(~C0g147g zoD=Z%N-BZKVF?zp{QwBg0w0fVAV_=JybC%D{Eq>EGRT~bhM~QCxZfa=p9MeOIS~Y) z%&1VMcu@b&k#5jf-j?|>cy z;#?Cwj}pf0{1KVJbDf1JGDd$Ue12==WZDM;)#lzHF04B=!Q@FbKO5F#H=dfPtQ$#{(CauM)3k zy@ED508EO&F`xiJ=vDaN<4l`+mbDzUM10(@-z1}tH){oAZy&y@r4h!0pMvZO z4*`n*Yg|B#?qva%X8R%hFTEROA+2xqUUtYjT?PgPfAkfe1c^V15>(pU?`vhikM}p~ zUU=&J8=%n!Ze~u?31xO7DnEnI_W{gt#T!r{-kxaVst(*aOdmMGI3C%`0d4KloV8XO&rX^jFxbWB{-A4$13@_1@m%QH7%la*2&6IhN) z9q)P9^LLgx?PVLYxZ7(NV=V5)N-wO%26?N zRZ1wFQmV%ioNSP)q~tuG*30SkS-@=6j3P~i5~W=-Aa4fQ7)$&`q$}9UdVVp66Y$wOGITxots92~Y68fs@>mWze)0 zt?{0Y*IhafEDO{5RkEY1%Wfs)a8UR*W)#uOkPAA1q?$BElWTlz?OMIvMoI6(#^=Io zrO}GbJIY7M8(|SLLoT8yaplW;7COdJ^q^hm1aNH1!G|E<;wfW?^?2K#rR7jSDek`ZZ)Q_Z77E zwSH!+D@T%#Vr`LoswP8TCiFe%q2*`BS{U{auoU&kSV8=%oPRQ$SDOJCa{jh4LDEg@l;%sm zQSP6|+m}1kQ>-7!+kI?~>JMG#e_*A{q2=F~iRKzo&xL~)G-1iUGZxr|}aMiWfby~_ zHuUI60F>5tjm4U16q`$rOZDcX=SA7%58ITP9OJ96_!OB*n1W&wCzI_Ui}V-cw?KZm zXByx<#T?^dV;wCuQRD?xiS8*TY!>Ne{OzKA-K(ZwR_ET+C1taKQVi7%mFe5GEUXNb zS%}w%9dN?0?^M@UlB3^R!O894K+`smJI(Nt?!Yph%qOJZV6Tq?41=C{ej^|Na^P{) z#aedSUG8HfH;Km~&4DZH;pOw40Xl%IkG-b%nkHA0=DKdk!Rle@lj6{fFu-7BoQ4aw z?%PC4ZHuW==bDIW*mJR`-ifc!RrO#@*HjcJz2C723mdKeS*J1xn+~uv#nftNJ`!7Z zwv>OO@fqkjmQ{9t{VwIc-ywOXSofD^cboOz;mPy5Of4o*bwR+9dTjH83AH!dA3kq9+JX&~y z$6g(L7#Us+H~yu@OIo^7b4-0GVH}&oQ#S8x(RH2l$W3frUZi*~SnclPiioTbpe(xA zqd}Su`Rc2jAw^;dG?nMv%jKhm}+cx##;NL@Pi<; z41Liy>r^`#LN&-&(dCl;o&#I2)kO9Tf&&3^=7}3OAi*fuyl8 z>Ypx5cK}Z(KbboqDY)XMP(-iw@Y|xvl_b}-tSBgz#5q_Gd3s8bX^`lxz5EjV4YxMk z%(-Y5ciJ0YYM*c|A&e0JC>I_Z8U``|F_C5{Uqm7q==tN?jHXfv5ApB478cpF^7+pj z4U=!Re-rHmZ&&VttK9*FS*4RS(Z;YX6*SwOb)KfdVP z=%d_Gw@07v*c)k{n$dJ&PHxMso&!s5vjd@|=sTNhUK{qc*l5)VOxP9Zwv<7;pJ!1< zw7O}bPA{VKTvssD7Z{_urN$6mcfwEzW7|MO7o7=xF?}u1 z#CSs^^5w(g?U^h$zGrbMpV0F0*5f2_U4x95`Owv3xTuXAY<`a#SnuVogc5A1%&JjM z-|E*t#muqtv2ydo2J~J&q8$%7U_gHMA#fVxOavW2WPFJJq{IR53kT}Br)bX8&HKPb zr^9Uk-u?U8xqHqb@p;Q!Gv`qla82PkJR9wwkJ$HM3c2|S7uF(F;uV6^SkH0RSt4Vv zL1LKz`nrzb0=6* z$i3ZC``Ztzq1yvdr^8@9pxxiFc}&=FP*Qo6eLg3R)I7?fIe`MQMMcOxRB&--1F9ma};LT28e)dticaRY@j6J zHY#C5@c;P3A4oQR0q+-c!rK@%0!LDpwAxv2IVZFQ!0?BRZE=Yc*8PL z88X1U8^KL|2KYRq&&EZr0q~5kG(5%1nai_5)Vg$iTq*ViE>-l8uL`3rKq-_YIn(bb zK)e!;F@|w4#I{B@!ldYzGnmy-;|eyPxizx-Y9vWG_Cv!9xk&4rGIckh*&KFW(x1Ha zBN8DY9q)MJ&&Ck}S|}N!MYvNuB*665_Q%V|FL^FVe;YgNN!xsVzGOyq3jh+Galz*# zF!nm3OBo4=1!T(fAC*kOp3ALUCDk1~^H-TD?FIzmv^DI`I1cb>q75~+)O^1}&6OjJ@Q zC+i^IhD5qf5{2;T&PrE z5kW`a?4P@mlh|>~eiCuBF&R&xeI?Aw7EZf75$wCqB_{oY;i>mCfX|YRf{)%FRo#q5 zTs5u&*iWNLv>Ze=69LA?C!re|K80K{=&`El3rh1zLV^6-rC?rFxiH6_%6DAem7ww zYnst(d#v<p1 z{Ro{YuXZybAW84VIamdMIz=M36%rSjKS<%vXRLiWGLj_*cF*D5>W15oS22`Mm>^@* z9DCLm(xau}-R?K(*Lkx+Bi$ErQjd6ohdFM%7V|@9knb%G;aJd=CrR##6c%4$F$RHo z7c!M|IaIXg()pe#U$yE^Z1&x`Pt)KTgnYMmQBt$&O6xeu6QroJTc=X>rZMT)%t9-e zTnghPy4Km!`xIgj`U=}3(96P&>4H$Sm#@Jx&z=Ys$~xLC#hk_E05!+f50P6+Yynwk zjAmz4{n(x@1Q&`kIospIFF1|XUKPJ2qmWP(j&EbVF-Jpkx8?1!Fa4gImA~W~^tuA% zJiPS1*;mCz-~H=1sX5Y$Y(A_*AzFLe?%Yg==nw7KHS9077R9W^WqaQGCb7Z#8D?); z1D2hhhP0d6X2NMAhzRtk~=b=9$pz@2a{CoqgRJU zUV5=l9Hd+6h)Qr;+|aZ+JrGT?dh{0cHqwsDl0HpjTX(52w=Q%e4%4%XCMM7;T& zNxDWFGu8LA!4Vlnf!Dow2`)Xl@{#21Q4z`vACkT8>x)E9{nCY`R+04>Y1wRYvKD!A zRLTcf8;cN`mv$VV?me&DX%H~LS?r!WJHwb=B89t%UEN`?v6xoebAQ~nQofo264gfP z;M8UYD|^nTi2eV?OR+e#v?OHuepIE3lJ15F6jxGM@zi z(qrHCE0!CuX_6b@1ydlnll~KPj`zUj0=qE-95BWD;b*(^OX{bcK+0%n9@b&sAdBn z_MRsar12yF^B67yOa%>CPcIomfx$QZHF! z=UF`edDhD=Sr4FPA>;&HnPuPiQpUWDCY*8pfE6$UF;qkec*iRMbddcomFJv42D8~WE;@)m(chdHDMK~izNY) z>w>$Kg#H%ajlZSo!!w70z*he}x%9sV_StXL4Q&Z1jrl)HQz!7w?3_~lGegix);gdE zDh(mx&w6QsDGvq>5qSG|PN{+G{+h#o&58S8b2197Fz~sPYMZl8#_gaSi2K`$QptWINEHBy$kb~}z9DlD|peXatDB=Ga7G2PCcCXGAnjLa@Hisd~Z z1Y_R1{g_1y1SYvL`0;i*lN29SEbnj@XjN)T)frjQys+R}u`n@6s+ z47HI;;e(yIWnx}OyjzOh$~Yl%0&GkGkJQ^RoyqtvZ|H7qjqoYhBFv2_ISXT)Y?ax~ zk^E73KhwuZP0zElF{>|Lt8c9N*1{vh^ao7aTHgI^W7m{&WD5braEb7RZ)}WOpWZMZ zL3mR*B*FM_g$iPeZXm-_WS5r2Cy941)~9O@#~DHnrKqUn-VgIG8PN~dc5g(#__0?+ zcGFiO19_~A87Xh=E}Q{A$5G$9*lF}40Y@;BDvMc2Pe1YYLGk?c2L-Xf$Eg4aUT2z* zmOAL8&&|Hf)?tjxk}?@iJMh77f{(R<}S5Cd=8Wh%Z_%-H)$|Cu{2qm7yjEem;7 zim4IxIZw4ni09g@ZaLhT83;-A*Y@$AzY-!+N2girA{X@8-QdPUu6CpLSN1W7OxpsN zu{^Pb-#0QMO9V@}Q^sD#8FgOK!u34+Hf6b6VAj;|d`TyDe8xiUiWWWTWpTRXxd!3a zO5EdU-;y8K9$x)6GkYQSE=c9_20jBR-qkz@oBkX~kaJtDIdzxr-yA6@S)aSzunVec z9==8;zPU?N^IAn-MYn)?C;ViJFCXvvVDiq~hJHn0wi@r((j0P-#_}nxb;+ORDAz;P z&t<0pWg3pdFDWb0HIhHMF$E+Ju2trwD=1Osxfo~`O;69{H*HfhCh1qK%6U9*zE@&V zHj)3X=Q^`_;)HalG;LOysSWjpaPfOVpS8jDm}<))8lxcld71K#PV9vW|D|Zx$6`WR zg5Sd3x?B-2Yva7$9VogM;a_9r(bQ{4TLqhO+iOT>B&jJQN__jrxvtNUNbfyb7O@u| zlKE(T8@*aaE{ld0xvYqqE%x!*xo=`^O8Yq_FHg5_GsGajetDJmHV#C_l>s>6Wb1Y8 zJiE!Y`DRW+M|)Dk(&bqFm_7iZU? z{7B{+4_7_O28*n{7UN(m_l&B#dwtH`Tu<33NxtLRA4tZ^8|}V4 zv%8G%pQ#{TQXXO_TmS-vXHzLQ->qO7FS}z$pQ7f};#3cAE=-v^`AWWAX7rT${=xHC zX#1cm0pNCNsUB-~uuYFLP+{nUwDYn$?UKXWLN_vLpe6Q!Hl60XNxwmo_>UPY@gIKr z3%5KMc0oyeXNfys7jQlnO~g=EA&&`v(H|mRwz7TpZ7F>V_7@N@4CM8 z8cqfD#}&QbRQ=Yj~SvZc7*$vbcfmC|+! zRa;W420}O5gp$ixb3*d_XT+A@prgl+6lgErjN|@=r0~YjEq~wLcnFz`g5YnQ`n((yI;MX1Gg*i{$ToPhOFa~VdmKCXAR*PtB zjd3B!vPYJ6I6qjlPgwdqVJI5<|#$RLTg_9|FK4kQ=$3GBF+E$!xGornP2 zA25;*!K(TngkMtesEo2%s=R-1@E}Y!{yp*6MBWl zMiCML-Jv9BO7K2R3BVBqeDp|L!@$T>@KNw@P$JwM@cr_DPag#rxMJ!H^g3qwqYLCd z(e%(aBnRh8)Z+PYp#M`hyo*wFkTe+uyXY!4tO<~!23B2d8PxaZ0jc0eT-oXS)JN0% zEp*>SSbUO&;BXKC!M-gI#~=L(DFJat0pi^wC5&@CfLCTX>Vn{Q7|$Y33=oU061S2U zg=!;;_MitLzI*E5Y}iyoeQ_~Mi+VMH`TN(OQ5Hk37mfEFJMtBF8B2MP^4u+&Vf zKFYoLCD6xtl6uC4}ElXc&g@cV%H{)9G%ZXQ`cFD!7ix~lIv-60GF++aWGtn3iQ>m{iSo^OSG?gO zW>feQ_xR`99fPjDC*E`r4x&1Am(!XPcdr|=n;g)wqLJmBSGO&=8^B-ihM)%&nQzIX)PiCyE=|G9cZHH6h>yW_> zC6nxEvk{;rbo|?5Z_zCSan`hndnc+rP-bQ_ zLom6Y;`MB>0r@;EdNRJc_k2Bib7W};@+H19U+GW)bkq<(Su!O2ZqYmsx>@lX6fnjW z)o0u1%@^)qz(Ed)RiLyJ@x8)t+V%nTG47xtN1{y!VsTG9OAE$k)|;Ag7!DaA3zntU4X7r-ZU1l)rTGPhHf@biSWPe(;RIhhNIF zb-kj;fntd%F$ucWEwveUwg`_BBnU6|$6t3@>VM;0r&|AvRk32b7ZRzc>&0?Z<%Qm$ zTW4ftrlu9|;QjTniRN`H4`W*Nhwq=R*A^Vl1W82T!=eeq)YY2(hrax&PIr9aalt|( zzhYNLkIj{{Q3tGc5u+{kVmDrryR*57dVT@A892?(nCEF!WE))kyrWDTntN*8Iv&ce zF9>bq^8>oL+`M(B*{c=145PC6_I}(%T>Vp|q4Kq!%&XJ~yWae~Spmm8K;sluAwD^y zxRi_5DNaZ^LliG)@Sa%UYoKF|g3pG5KF@{Wu<9$Xd3Z&~O|qPoQa-8WX^RZyY5(j! zp9Z~{&C;@|z9wf92^2mwXfRY($! z%$SVO(8q{u|MKLvIS!920hObKitC#pB?$SRA8;X>MXLpX;!1AZ-r`-6zGG?6`}ZRU zyaV)vfinS-WbVO}>W-?>n_?HI8!CzieG@X&KOjp4u5fzin|C zNE!JYcR_TrP|Egwt!YCpZF%rfp<7yTTG;c}`qi7#;!XfjqWU!O%Tetueysje4R=0r zVoWB!1!PbYHQc#5Gsc9VjZl6^lhvDHCT)YYB>DY*%ccX%$)?;F`0Cf*P2>Ss*=(>= zjf@dr9u~n!@0Fo5>%tsNd z^!)s2Eic)=;>kVt8#LAvPI(}ZAJ8X4O;l5v;?{=tWVjAl9@{HLs$2P*JQK&cZFcgU zY}Gqr#@~#yLASic*NnE=PDe>A0>zb+^j#_tf!$2(KsOSJIFopbLz?GGj4Y9LLJeN* zwiPFKeT#XVr_^D&=I?vmr^Iq;)vO;f@$<($K!F$zz9z$*c2^e{_P=1ik_mQ_5i5$1MWA2q4iRkn6DO6+N zE7BCSv~2yD`cT?u=pK}rU?%?!2w?z*3S_r|@NmN(2$Dfh4_9-I>?Oy}W7B}JSNeI! zpZ1Ql_z`TI+`mt5R51Vd$z8@lhX0(~{-^V*4c>|<&}#`f143$3g?ac1>^SFzUNA8o z7~xPI$z;hJab2KX5mWIAvcCfL{L`lsLS%#^dtLu^$)EV!BDT~A_{d@)=Rpey4zn}AK{=YPHfC02^ z7W~gubI-JRi9P*5f6;-kg+E$?5QID!R?Fhg@jwJ0uz5Ou;%xptnnEEB_~7HQ6|j>lWg-8uYQoc%pMQT?+U!v7Zb7kEiJTI!u-98i}FocsZD zBgArk^EUAtpwaNRNBQy@8U}X)Ik`rOJ#BDc%Kn;$Te!OJus1fx3qZp2PlH+0wZEsg z-BX@YPyGL=Gb;6a7HJsBw zqGobZg!mOT4Ocz|6Hel1*@2Ftst{(v!?;@L@e*M8X(@>Zlpg;hY+FDc`#8{5w-RWE zxeuvV%soQ^LS9bm4*UCbAcgv0N7g}n<8XT*>H5#wQCG(ImVPe(-dh@)e5RyHs`L5! zXg01%cGFY;Q#pExF*34jv1TG$cS-ioB5lZv*px@PX-?;s+mZ!BK8u_y;^{!I+B5Yt$vObg zN~O7&#b~`2-}G5+o(!_|YOmlF;_1ria%w&~Qo`~nRzp6&JkGClv!8fl%soUCDXOs$5SW`g8FjQWP|$oa?G~2__YTpO{JQ}aeyD7+{O_VP0;t>vj|-&^6ni+ALSnu zzJ}TGl$~hCH<{)e)5Z9dS6om2sa(CeY~tKLPKzIZjv%xCu@Ha4;|aW{d_d}28cnNo zSm&@r<*zr!s8@~I+XC5g?iuWMC4aU$R@@jE^fVPsv8Qz7$wgtHMr)r{f22r+TCCom zxQVHLs!8X>_RimU({=h#TYv_FSK+P`Xqg(Qdp5}jHih;P!%`Ox(YXNy7Q>H|*rX2H z>0=wx?COVf2yIKdg#(pqSZaq`%mlZcz z%Y#qFzNpz_G_+b`cS_2{9rkWKG;hZeYgkPg*P#q|$%I5MT1j^>o9WZq{P~yw3-g}E&pSYIhCuM8EspV7%YjFEG%T{-^8s&c z^`RE%9GAxUsO{YP(H(`?PjqAEENabfF0Fuv%|yObP{symX*R|kPvOS&yWCyYj--g3 zIvone0sO6x+5RpId{>lC&2BHbCYBr9x%lQDU@U{+DhZxvJK@v6UgqH{R!I-1&&kXk*g1(P~^4{u*v3e`7J z4zs7csu&K%3P5`2n8&vWs)erNGvNjOVkh1^#`UQOU)Ar8n~Ubn%{%))Kh|w@7NVz3 zAn7}}xvT2z(keUUyWvsc!pJ*$7V%Ug)mvT9E2H3f*FBMd3^(u3Tsy%BGuw<}o>hw4 zU8_VvcKF&T5ZAgJmxBl1U5>J$^Dqn%@&AZ=%c!>2E?hgf6mMv8DGtTmY1z033B|2w zvEmd6?w%qIT3m`1cPLIvacFUO*8qY2t^J;J#`l*nlChE{&z#RauPbfGM}~Wz*E8uT zEAIHlm|Uuc181~_Q{bhPg-_9x6trs3Ai=3*<&LEO3;vz*Un|gW!{-zD8-CJ0VYze% zCnn3z&QftVaftPNVq}%)_yevIkQBi3F{kLB0m2ujYN*tX(Up@=#(SrXfz71KEJ{6M z79WX-X&rCsH#CgR4WYX2m;KC{|AM^Z;x}bIiQkx|eIQrabg+7E5bJYVVZ*`lB1sRa zH53lqTWXqt+SH)+G<=~*QYR4ZKt$tfvkRxM#uEVHltIW2Q{N*V#9Otnk1`p z%*x`Waqjr>HnIqi94vgdgiCVBKd8AF=^Jz+tkqetRhK?FXoF)P_vvghz9Md{Kqyjb0(@mTPNv#<-=TV z*~jb;#~uQd0pI2ILnQoXeXTFE>)pBMe>lFDqr%b+!dPn4;%NoUI9n-{<;5>2LYFz^eXz*Uo|$39ij%cijy%m2Dy zPx@nV`G*kqxQ1pR$yFlOE|}9+m!Z*)81)_1aM=+D-&nXg@^MYcaO@|q!0decw6v}? zRQc*dP-G#iOTkLBT2+37PP085>73z?NB7lZ_VX+M6pkLTa`3O@sF>O$HRq}sXYNKH zrwX=eeXXf{qDL+a4M;FED3|+?9jA&|=8BC4d|9kAnFjdrbjL0qTK_OGmUNeK+I@PUOMjC*HGC)ZY$9+Qc=`U)HNn5% z$S0(v*$!O|Udsc7hoqpyfe#9*2MUR)lg-v#7^uq80OL&!^MTvYK-CWwkALP*YNnED zP|7xNwqpCm-#61kQc6yPA4^v%`@b?#95`w^pk3GWbyNRER=$lAC@||68KGp7f;yR# z?jx#Bl02J5M0p7+CqHj=$|@mGzb*U&9Aa^g`Gy(AbPK)WWQZBt%j0J@Etd_(>DP;| zVzZv8n1Fq{eDYJ^h%7#d;1rW@%AQS9X+45!V5bKVSl>Sm;=o4d|6Ye;{N1Y|$-9Z4 z?&YG3@FuQQEon_63Gkl1mb4Ai0=O3E-3dK9ZlYZh$nTU-<6n)2YZ~rSzh|#)#Y3ZP zbKF0%ES*YSd|~!Tw>{91?^Hfies-@}?p}D1Y;Mf|&eD0*=};EScUAM;JB_AxwA{0h z?CmcB!hla5`U$coU6VWmb9r9OWQlwBa)Cb;0+#bpfpgBA%GX@~v?x$4WfH(7_BS5C zHk`?RDli2W6SfK!7z?%1>^)aCl)wf_)D&zF3s~#H3^JamsQ=$F8-Z?2h*kNdxdyw} zzc%FEqnQD##@RyPKUDwkw_?PDQ|^RdN$)Jtc<+bbCXp;40c6$(C8&`;{qs#YDFnrD zu4{aO4~YDK9{}la8oa-f;XEgwD<&XDS04x!$4nXpepIr%lrR9CNBkfSY&QS@ZLklK z@&ql?f@A*Oede(*=&+_;on1b#wTV8*BQJF0n&=5~*YLrkv|d2i zn4jt!m-|@iZ9zy$umQ@k5xtijMu@gCgW=CxVG&J^_{P%VS2I=2F6iplTwg$!ZxMp#3@DohDGE=jJ+R*<211!po__FQnqjZpLtl9g!nIT(1zwhc(gP z%ShbG3m=(@BF9RR^}Wpt%tji&$d>MW)3zXmA7USI9vU}iK-0qjPr|}7z2-j@uMgUA zKAuj9c3-iSzOe&{MN9QN^-3`PN`_F6qW{zhtr|!YE=L5a>p6tT+xY~jdmBtIb;DR$ z17NER^WOsmkrIfs&s6iVOs=ogr8}e4Yixn>ju_P8^6Q30T8U+g?+uYF%oKVF=plDH z7BVb>&mhwPz%6374QOQ$U~~T2C~z1iZt?f+7T7m0jw}hDfY$W>HG*wxJhxK|v3@)XZdFdj6>{+j2gB zXtu<(KO{^JUt&T@2+-X15Q7I9wc%Rh!kRl8zephHVqYCHBQ`rVUz^zNnEx&gk!m^f z&u!#jiuWwSGOv}r&A6=j`t%H``#{`BTw%g{Z&oCa?*C2xBxwkK^{T_?hY= z99h~R#Vh?9(TQ{VIK(D0ZeW^O0Q>uNZzu^dR>SjDW@RQOwyVU@h%7kPkC>|0;wrKa>!BH z0?tY$Pp@{}u^yN@rn7w_*ndDOnu1Q!L)E!ti0!)4Y&i<7i(dM-c*uMXegu?CaHxAM z;5LhxRko0JG=}!FJ6Z{jK~ub&)|H=Gcxa)2c^3KR5E3k?xyAst2LB5hMA)|wy!yhp zP=rXnsetpRYZSxY|y)wbwmINdIGg@T0 zgr-~BBs1((abjtQq(__eaI#4+cGbKqvD zHq{FeAF8yY7X~R`T-e-c>?Km2_NWV;&W3ul_vhlP$~AFUaCjN%h4S9?&_{T5<8<)9 z$SGFaBsBd;{-g_YX#R4rWB-8KL|=caUm!_`xME{3VYuBiJVDZ;K z;)PQBai6#Spil@;l}-}PKM_tW^iT-8pYNAyeL=e zBc~YhE0HhU&HbxrTE*sV35p=JM%VO-=h)j%)Wg4gNW>HWk&dn$ zai6ZliL61X`pXJW{tGfM(@SVH769bapYwHtH#*zD(3yT~dnfx-^cy#4#q3kmivo3-&w7LV79O6uoOeRTFW3(Y9^ zbr@1X%KVdkT$}@OjuT*bSjmT!q<9SZ#&s%Bgag7DgF4DhgzQS7Ak zSkvai^)>fP78i zBvoaPopNs#CqVeIe1mOvSAEd|$&u2h>K`P}b{IR2+}?P*v)I=(<(Apf)_aP=hv_1# z{IMe}9e|`*57V(By>0lCDc_Sg?g++wHv2vPT|0E9bWT{UN^!ql`d6gl&A8=+Q)v^1sik9O~A$m@a zGv7?(^PCF9E3gSJ5B;+SFQHn6I)R|`GAntZfh53G3LpZNz(u-#`8fD)B><*W4ukzY z(_CeLK=Xp*JnaE>_+H<6K3?z`4@Yu~4dnr+PP~pAh{Ij37#yrlcd9dd zb&2Y9SPa}~nnPfs&lm$QK{Sw^iiqX!wF zh-3-o*_gBRQuNm~PE4-IBU!`w!S5A6sTex^U8a{0usa*SNe`iGcBOOqAeMoV9-a$h z8lPzNrE}VsjiN%C@tnO~G~0N0Jh5QPnGKAT z+ob{1Lx{WIG&K^MC8ow3C0AEZjdxiF(1v;4$#2_q+(->jRNNTmaXQQ16%`tniZdRI-w=hqCS=T zG=W)?+8`A80+{UVc!3DOe#f6K{v-dIt+x7Nb?ve5AHv`D;Ez6rYdkm`hA_^J{v9zB z!R;zZ+3pKYzRyikqp>H#qVv|(b)M{1_SRQkE^_t+$aQKdeXgvH3E?07 zH21uJsuUtr^tk^a67IOm`KA!uS?*yR?ZOY>Ig7>^$STzrR~_e8LJCGUXl=O#C{rm} z3>cTlu+gNufX!1fUn5t1$GX2uCPQu)Z&?X~gVAg$b{`jp4#8>f6}tWBo0E@@Jy<}> zKc;&(+Qxi(M2+Y|g&kZi(}>1X^ujKoukZ>YU!}j2y2_dBnKn*jjgQy$cvBTaW0dvE z)r6?Cth&C3>K~)Xmic*KV?uG6Nx|mj%`}_~w!MTUT4v%O zU-|R={S!_R^$1Y;R=0(NR4Wd-M-`(HsC;`^+Mya3<5l$$pqR~-8oJ8Iio?Q|)XNk$ zc-cE(q?;l~G(gc?w38kT_AD+*Y$ypPxm2_l2A|g9(Q5E+(y0RltOSR?A1$^5APbxQRUyj`SmmX=OvD<+p^xfHfU*1_NQ0-~f ze(^EJBe>*s<(BzCZ{-bylzO-pV0KkPDwT)+g}i)kXus3I0y115vFtHcK2iXXhNt1@mu>8Osf_${c*wspqQ1>=tYn-vt*MXs3;(Uvi8-Kj`c?bOhtqkz& zOfZ6O9&r;N~HSY)R(g zd%`*xLxMCER0gwYwvN)jIhhi_M{=)s*V)$})|aq$%9x1LM1Q`3y`V?#RdWH|?ikr7 zDgDPBjGcK6Y#Cx~-P`f?;O>wb>vNGR=d~KlpVDm=&+HAJ0m-Dr!5KQ_e{${g6{U2= zRK?dow;CXq95`)#A0i+B1`H1!YJTxC-f&drby~PWP{LdM>nC?A>kVwan0pX z{)D#K9uIvU?Mgf)&1)$Lc07q6z=<;Z>{YV60x-CY)B)t+2s17Kp?%h>7*HG3$kJi_ zYUE(n3>WoRt@+JJW$W%jFoAde6cu~zvp3*Q2SN}lN8%R<$JPvFSYLV%U2L1bQSIi3 zq%K1=InSm{8c+YzT0Zt;L*9DvgPk^$TidAnpu-tEsM|x0nSFAL z9cQW_S`CJK0S z*%s z7M>M#{E52Mp8E#v=W@hghzEk0T#naK9kLs%3Q`Xl@La(>i$nJHyDtdT)Y4#OT@KyU`Yvm#Xe%C32Z-NeS5Kr-$jR7q&H~YZa>XT%sVN2GP~Zi z6T7o4=hTD6NHg7crxc4VFCWF{#XPaaE?b=qW;HT|K#$R7Ks|TXbbVoW{?N?8LfZ0& zqV`D-f7>YptR3I(voAUDs(PP4TZ2rJH!~!eg0PHb5R+d{Ovx z>=hkS%A#BL3@ay>La|kj@ow)$%>NtCpX{p)%LTo?ii+-fuEk?Byr*UX|MzI$NeB z;d~F4mSc*iV|S(dbKree-MzlYd-BS(zzc3^c{+4G)Tlj+^6-GUmj)*Orsk5C&__J; z+;TDdA{7+uC44!<_ou=mHk=01Iqfi1(|41x=D7W$QL<>(D_ZzbWZ@Drbyem;1N-at zbiF8Lu^wcyo9M<_lIB2|H@K|95dTWWZiieaq$Ql~Qd~B{L!vq9*rmpLrmBJ6`Iz@MIkdeT`Jl1;5qPdh^PNTb>`St*jcpg za=yB%c@HY}DTg=ADs*1+T%>i!xX*`nsa8q4hs6>DhmB?}{gIPU%e1!ZEU55(m2a5V zOpTntf)r_*MUM?}8_tJ7ylQj#^YAv|m9K51l9hyS{+2eRw1|((C&?#f&nCzZzQB-g zo$}PcrRc3CMLv%J8H>unQ{g?t)?|4Se$vTr@t@ddRdoG2_Kru|7bH! zkJ{ieeQ~plK1SH@C^g?R^3y*%S1|k1B(LB4n?mK{Nae!2A*R0Y+-Vj&jB@5%$}1XD z$O5ukHAAJLcCJIz)!+HK4W#f+i4IAhCv|UN7aO4b#EO^+OqVn^Rz|h^lI&V+cCSf# zSJh^!Hq-?yr6+ZIAJ5ktbwBvolcl;Z?J$`OsKc)--wo(d#;Q}*&)9ZuGCC*;1w%sQ zhzgPciCR8pL9Fy1hHf9?=!tsXV&>IPwq*og&^=w@eUckjEwXOCOgQir{mXp@wI*Rv zYMj-$`bX&3n|o+hwGAA-Qx?)ghr9P@qDHUsuUpkPYD-q$h+qAx#|JSX~;XOx8Y5(s#%bQJ)E4{;4UILffD~ z8Lzdlw7gQ8)M#92mdqru`4`lID;rajhq7GXJsXeZ^_(L9T-AjwJ3zS&>v;$>7w;2` zner02Uj-Y%LbF&6?TpkF(vFn=decr=Pht2G< zlYYy*a8{@0-qX#_+bx)%Owf>QpIi%R|BESO5FAT^mOdKmTQMkkcJ7S!mtk`2Lpp ztz0h{q(qU(*VU=PBhArt-09t{Umkj|iHQ5Vu9ZBWZo3N)JSTFIGb#uhvM8SfD~O+XgNp&=9hER z*cF&4$PM8HOP=}9xNjq9?!+~a+p2IQQO26l_@KgIcd_l0PUu7*6~)hHmR*Yle9CJyKJzZ?ar)Qa23 z93uHqne(9pPk^*ESa>+#{o4D;2eL6LYPEjX%}q+#Qx4RnIa{7?`m^V1f<;Z<83>^5 zKYb#>A!FYnxKmtX0SsHM3nLu}Z+s5gcuz{7E(el2??4_0Rc1~brbMoU$jD2zEVkj~ zBM+3lp8@I(dGpy~ztcK^runD&wM?(S%(xr%$=c%_P$E7z>$285q_E$xcVd5-yflT5 z1&IiT)z@?7Rq@U3#tA6`H-u=H548c=cgg%GQKj3{XWy8n3epT`L(2(s^JjA+mD@i9 zUWp;bcm%?3p~FiU%zw(<{Kf#M!`Fx!h8H0DG?OYd48-<7WYv9C)Q7#onL%8bDh=MB zlzQKi9f;3gpmLfC*BZG*XWW7Z!^F+O}w z3@wyH?j}5qB@2cq4?wFQ7rDuwcQWwP3-(zr_1fK#{{0$d7FaH z4U^-K!tgt8l{46rw3qdwr};=Z%-%}&drFxI?CugS*G;s@tmw$zf!!}erjZKy` zGk9I1sC~$-1dqhV8+}p&*c(H^5{XSrX+VC71T9a_@bV6S`-Ev`8yQu`nmEOMX|Bn{ zpG|rx;&;TKJ+E7ah-t_d*S$nsrc(B{LzsAZ$;O6w9N*ZCxT{F$fvsD|~CyS9+L zI+886i_XN?zvtk^t<}LSF4=pL?>1|6rA%U|1A1H}(-T>xWL(lQ@%K9c%*CzKamw)( z^1Zer?>dw~OX8GwOOu*{VX;T*0e{##dR%}JL0kr#?*TTronpmvxgKPS&0PHj8jqT$ zznY}%D*p^yH`HJ`xu(@#94)hXZ`jPqPPv=w`;8dim-VuLdzUQEiP^ct)+AjfR`SV9 ztG})Dcr`|tgX+Md#Nib_O)wK?aLd(ze`4lwaRA4=W0`l5fo%g?d7A7e%sFJXqA1}T zRb5SeDm4uz*!YgB4t&uXk+lx}>-Eg3N>EQNrfN4~J5-Lmmg0FRG0vYSudnB!Z|LGm zpRWKhrajh>d#Q|?LIyN;_5fRJTQed*Iv9sTwW* zzQKmO+xo^xgqydLY$-}KPycMTtJ0|q8{tWizC%N#Dek z6sSqJ>hWgF-%Z>-t6u!46|RZYCI7`8V_EB?cx6FNU*#KKe~;pY?uf1b?Cjv&R?iU=dqDaGka^^qhEiv9?SJE3{e&)U^fE|KSrGUkB0>xUiV(&KJVxY|#-_(XY&T0t7jRsFUbA@v579 z+6>@@`|~1gniXDHm-4FXA^IP@hiGxit7$Z?ql}O?c!S|V*s1kZHo@df z-AXo&8Eq)bBWa{!9-u)`RlyDiWPx-L^zgY~Hpi7)*U$0l9dDBiiPdP?3(br};;WkH zIONB9B(SX<-Z}bxGgd`Tu}_b4<{Pm51Js+9j4F}O|1HS;_D%ERs%6)SkbVy9$luFa z29J+B5=F4(CpDxn^o%HhuC)5``{^^w(wYS}+lP*i`ALe^TG_ExE?mY^%p=ggNQvG}Q=$?ag0n zVg;h5$Y!?|UqTz9_QO&h8jM4Z7Dn8;S9Zc$9uHG5;VZ$fRS&|d^kV}4e)PvcSf8@( zj2XqC5Av^8@i7BeH>+5_KO|)ggIYn-8B?3FWg{C~frnixkR6?4{&oK2lDkHD+Q*Vo z%N-8$(aKGlTX67qEKCTO4aOUPkYEU~ne-AHp+YO6jZv>X{E)Z+g+J4Xc*gHB;hB$T zC08CcS42^Cd#Wb)Y)I8aSAiSEF+l6UPHT@|RKDG%q?*f05SqhmITKq&`Nz#3eHj}; z6@M;Agq2>CCU1`_|BfU$0H!Lb|U+Og6Rs9KLk8AO&8-Gti2%T0|r6ELa=qCw4l&}ae>A_xX zu`SFTCjTcu8id(EpUno<-+-J`#Y_#@K9;o{i~~rS?!}XJ|0Jl<4{IMaTA0KhvoNY2 zxz=EJWgs!$-@q_eO}?*J3**VM=>NC#A-jl@IVYHmdEfA&ZqwWLgZmZv)p)OyYkdIw zWTy?;aNs4Af#<<=*(x&}=wst4Z5T)%uvgr^bi(b~e&m8Ejl0#dYB67t|8~4@Y|5~7 zFF$yWTeS{38M-5ey?GbJc%GhDsLs9Rz$+~78$0;NH7#i(aPq`yB#6nOn?zVF;;Fv4 z!yiI;zPQkIPTU?cB7+K%qY;h19_di2S#g{$H)w&S;XOo)>7%gThp1(TjGJ8*9zuFV zE_D@Ui~!hiC4WeL6)QGQhHRnEw#MG_@wz+TkGA2(6N@=o%`bT+2+L|0_imUcn zJBQFZeV)QUz4PbgU*Y~hM|t)bhS?#yZM5tg>v>o5>&0LCAH=^`V?eMT4c{kt$&!;q zV|A9Jp!Baest213ty-EV@~e|VulH-_m>nr)B!Di;k-jJEy#D#hM6Z6x=e8HpzT;vABvqg&15cVeInzf^=q_s8u;>0N{N_@3oLW5ZGFEDRH8QV)+ z+|G)P5GpL3QlKNbwd_x&#k%D!?87!QnJa++6#|eLszk$Lg`Z)ulS_g2Zgc_wf*rlF zNh&X+#y`E{ANA+t(!}JR54vdiIw@)ka4@LDDmm5!0AkBAuKQI)35s+I3ZOrGbR!l~XG@nSJmlZc7sqbBXRQU*j z(Dv1kQ+62Ok`OH3O^q>D4GhNCBnIV9CG5QCktVk^RPe~PtBT5pFVV7|6IkCSbFV7U zwjjp^Yofw)z<}Orbbt<($--jM3w7VtoTl>L-X2P}ivbV5MKuqJH<((lzw_z+L-|@u z4$FTvs!=Qm?65)TcwwCNFb543SPtW^xb>D@8M2&DD!UXk(RUPTb!+mX8=dclwYN{S zD2SeZ(2xyp;EhP<^Nqas^WxTFdFJ{epy9QDvbYpMHhh1;DL{Uj>D)EqC_t@fbb5&3 z(+x&%Ok1}1d#1dvS2aAyyiJyKXtbKq@Q_xMInN&w#nV$6;_^pOb<$dMTvy-673vuq z?5XpZM&3zgY3SbS_@Nor2O&6FE!sksNth%2O3txd>OT4;t zNQP2|W^Qpr_l7#V1LvWu90_~Hl}Ua$QG)6kRAwY-v*6;HY!O{XJsm<*_kyU~=NmVR27hA4wTzw!Zbyho`G{|l z@2q<$8-(u)j~3L_*wqVtrkdEba~^BZ+sidVLn*;cm!m=h1V8zCIXhLGEt?qGjMf=@ z<6xGZpl!xqSNQXWb9=>HQ}>noNwC0EZkp8vL#9Djn>gn*29*L|ZI@@O+5)}z=kr@B zhbP=k6KmFK#q7zPg6LlCca6^?ZA1pNHoTME)nXM21W&=%{R(Gyd60(}|Tu5toCHb!#tyQaA z#D@);#6RiRZ=4eNe$t%y5IpnZS+uk1S9H?0qqC3wpYHGHU<;qALlah|?`87l4{Pt} zO4GIIwwEMgKMYt46o(dtw(4O2PnezJFiuee?IOzJN|q<#nDS4#V%8nG%+vgirEb1 zU+jt426~>n5G@e2^5Aw3NRXq@>)sA8RQ=W`zAa`-2S)sruC8kY1^R#U>#-j~fD#?X zq^uxqHoW;H=vzQ2uNNlYgugKmH^yeZLYh#xC-IQycrh`PI(jjBF?@6(`NG!vKSrPs z)vX%^yT#f0SE9VQgZJVdlBu?czK;Oh8%v@cPZAdP#45oS7n$RRY@Deh9a*<|!njNA zKI6P1j(?(lnwThsm^8Oj}^Pi!6x}fm+5VbbZcZF8pa2divacjz@7^@bMi@hXE zCY-~zF;%Bb#~lQGs5j#ivB;yF>{_wWcWEqhQ%@apdCZ=WfJryIpZ(fmRWP!>R3NS< ziZJ;r^G~Lt>|j)yYd`5bX6XEMB~`L+Set)gPNhBg%b}XGzrG2!3WM^`ptluo=yODj z^S2N@HY@AU#&|^wzTXr-mY5&^7=}Z2BCO&K~_@$6-Y6!wYQfg{9)>W9WKZ|L|Lmpi+YNdzwje$k9 zV%Wo&KDYG>uoZ1Yn&=@%v^cmGzqA8gSg*v{y+^jHVJH+Zpjh^ZKc&*5EkV zox$7+Z8HpEqU8~WVnD?qQ}Tcwj`=zv>uOII2DG!^B}I67(}yrV1qph2c3YF|YQR=03^$F^|{4jw%+q5H&Ls zSrN9Y9*7m__gl@S9qRWmRIHXLy(8TKx)AiU{COil1X(OeEu*swOBcj2O@SIgH=gK*BTs!0EI57 zCzLj;ekUeZ0F+D$rtv4*_Gn5%NBE`%$>+*gMZ2^dctyNJQ^8C*H>I5l_<0=;c!ILE zO$BRI2&sZl0*0t5fO`$A=WQKmHKth|KX4&dI{oUihM;df{N<;%aI zxWZ7oMY}R9Jda7^|Fta(sV+ViW#~n^l4HP3$OTG;{U;BZ)%<`o2&aW8HEkeVd{1Ef4_5f@QexYTT3WDtu6#(?{PXWxUYHoa|&!9&OY>B|_PEDL3$0^WF8 zhHcvgy#6%kA7m<%Ki9B+ZK8g*`u<_^>QfCIMUk~*GKc|Z&Lnq++T-JBHWJ{Wl+G&A z+f}5g*KZS!ui9OY0`+fL5&;it|-^XR!q&>qDkelRp0PM)XltPu6^Z?_wHZC^~*)YN8UC6f#l4loR~39 zGyokXD%yIZ1I|#9OQtU`eJN=oDd`_S=$YX)OnPFrPrbet>S&MumZ9tRl8u3V>#BE? zt;#or%>k56I;JBYX|(m!msjTt`*0_!`t$r0>BF^9xw4S^CI4W~A3DIT>C{Tjh}hU* zAEX;s=a)Vt2!Fr5rlE(`{*X~n~4CT2%@W_Y-={Uv}xVf zc})q9!s0d=T$7SDx&7t)wn=W?5?-r)S(O^Ewpl~D3}Ttu)Biqdt`62cJy)agSInpT z2VzI>SBDbbrY-x{T?d^#uzV~@_33OxU88W0g*6Ap48y*yrVNXc0mGT-!uz>s=Pz=~ zkgzAxWyOC~-ZrRy7r~rt^2M34iTAha$h@k6lDWbG&qO z)frL5I_*2*95q7+t4NKTo8KXZEwa4gceU;l#6g@x17ED*O4C1-;}v=zz7d}xF2rUk zK$?b$8e*Q+%J221JNU^RTUBKYp1L8~vk2uICx-&y&hmC-hxPR6mfDBlwuZ4T#~Emd zL}?s?D~`JIN!;}x5L`7l!G0Yvzq}H#4VF+%Nyia1Ez^ugTyZ`lW?Q@<*6{AO@oK!sy7$@&>%E>9@+_&TyWh ztteYvIkZnrrlW^9YIu7C zHQ^=2pPC*pw||`|DiVS>2)$%5CUy1Z2gc^G5<(vfyj|Oe0RCuRzVNhJhdm@s%lx^v^p!-95Kc=VC3-gDAj`ZdL>y4M^va!6vB5WhJf6?>S#>N&M9zlt#y)&GEz}-(#<@@E-h!L4)Vrt% zcIf1A$fs4( zRY7P6vRhD$>1Uyv7JO4))Dypw}*qAi)oj_#-`_$D8d3H({qh#ifip#gX%vBe$-ksu+w zVBZbQmZZR(GEqSe8a@bm(m*t-GBT%$x3$LcF~=sBYs@l>`j-xIfJ?wrOG)rO7?ckJ zVFdp#>rfEOjuCyn+b7L5*feOM-#9Z7ba4DKuaJ0y{NgrNimBRO0_Cr84UdbGwB#7o zfcNT}e=rb@3E(gBtyFWORi*7aRpLB57q!*>Gv(719B{l|6ZT;=LxwT4+V9~tTORT` zEW+O`ufPET^c`eIDM(;mezLkIr_o-IuIruce-G1B9d)kiW}ZiUhIwl#(pUMt=sd?U zpZ}X~Th%>CYPb030BhTVoBXemXZiL}lfX>O-n@ z>tJ?_?V1ESaM+I(uIGOgnd-aaf7jLg0?u>hFh)-`P ziQN39?+*e(?-=L8^n=}Gfdx;CeP=2U?H@GU!)Ax?l-5dRfi?4@@3#P~HT}0re;XD* z)a}^-;NLiY)L1}Y*@56eTiV#;^hxf9V#;`{II422&ZrHg^lG z`X_%9A!u&v5y`JT4gd`4eP<$ml(Uhm+xk70p*!i}i#F>{eG7DG0a-wHukvw#!d^%h z=tC9LWcyDl`GZ1tr2E_sIGl@Cvb1z`y?*=aTW7M|Pm$Uu3Mx6m2=Z@=xMD%?6@R@c z*D`Vba5^P{ zFxFwPJ$mQVCK2%X?LmuGS!zF~mB9aATcC)hZQKdyHg&Bf?H`Qk*DL9a$m!XOE&vjI z0w{Qy{$%ET`~^r8%Y?KO8R|Mk@Af|(LSSqHsY}HRccq^4_0bnON>wC|ALri z&NlcVx;H{EfvOVs?&p^@=bo9TKu3+K!<&Er}lSlJK!Lpd`-Q97dGC2EGz317mm@y`I}@&C*7KQI#bnoG(sFtxK=_jdSArQIX`w3={%lW{b9X?;t8Dc1d#6g1vUbVbG@SSj<^UVv z_fZBflX&{Lz!$ZOzf!V~2UG$}#*0wq@0_c*8e%U5#q8GvPR5Da<)jVmq`!0hawE1h z4tjYmlnb7*>4=?@{G2Mwqx|QX*@ljYNWvfb#rU=7#`c@0JChIB-OgsQD-q?Z9uoyV zYKL{}`yISQh2HPf20k7$dB7X2DNpzHQIyP+zA)(7ACZYe9TUMKQ3iq5yN~=6kJEQy zhTc!o6V9wJC49o2^V>~6rxXv%A7HPZRm(g*1uALh-mixs90(HSdPbxx@x{H2>OQm4 z=@)AJZLd*0shV(ca76Etef|*|=c@eI*~t~zp1R{N8hwY9&9{3BdI`W1 zQyZkL3)D7b2_4$TBF0*q>c8713(_QmX$UaJF)cPaDzYg<(+IqC3#F*kUVo-}kN3A+ z<#@`t3h){4UQqt_*YjYoVQVRm7REddY4EAh`xPs$ZcQw{E)V$pbj%(hc&oslmirb-ZbgD=mGzp*l9NxV_yba~?*f@&nmFw8V*g=e zi~dL0eQs!dr2#nqK;tii>dEj)7qva9k#j35BYn&mMDySY*VC7FK*NyUy zcN-ivn%j+9%ZrMz2(-f_-5CIQP}z;_+!+3LTyU0{{`M7TR#gtU(o)jhbL6M_L^`J| z=044a6>C!`?pN(fPsG=)`m~+>tbWBC@J?R;dqL8k=_n(MeN7q&$b#0*ANmzVan5$5 z6;m`>3V+cSeJ9}iE=uc{O`!LD_UMBmj!|ItcVjKu85f9Q_Wu#S(fRy3*JZ47Wf+Z-z~_KlqtWT_)rTJws}OY6oK`xg}Q2^w}+4@)sOvTwc#5#=Hyhdr|HPW=N*eL## z5)AqmT+Tf^&l$d{ME)MM~Go-5tVilWLM*ZwKSUac=% zPpI0FJV*TUN*%rDCh+A3mth>{8J)F6(VVp?;Rbk226fMSCzK5#jIP9a6J(qF95 zHo{hxHa=y0$J3|5Ui|mA5A)%7QwF=y*R3dpjb~#9K~#Qt`m#NR5#~K0EG&c5~nGK`k^W@d^@8Qd$f&Q zj?nZ>;>tNAnZmNgad(IJLK8jhMK*8W#)mvA*zL5r5+OJB&VHxCO8?^if)wG*(ov>KPi3Y^js?Hd+d=E{hHc1sdD`fir@)auS=c2-8o z#W9HEADuWa(!@Oe9Q0^Ma&~|JShsWTE30=gd-7gc-V+CIh$t>vFx^eQz}aMs@HZX% z>Fn^{%H4#hnKuvi8xJF|>f`#MX3_GEw8>Ajs6K5?dh&&)n;7C^l?J;MNS`xH zf2f$HpUIUTr2h%M-B`sm7fsn#MaCMDnK$}vq~IW>3#!pE1Ymy8iqZ!!z{Ju;=e*xi z1d?X-Dw6$KU)Z3hXU%0Go#be>bkxD;%Aje7j~>eQ=%N~%v;zv%-#w)zb$0^XB&G_` zD45?Pf?tk1YDt&(LZz|1=}3@1fty^Caaod;hA;3iKd>&RDvwiO*Y;a+Snju_}Hy!5w!u94AW?qnZ0$@%9_JvSew+ za}7!U+Jy4lYlbm}=ecQoY%LXN3hYH-TLjvYu1Z1jG)QQ$ckQ;+HuLBu90@_MgwurK z6tlNj`Q!VuWp33Dm)<%2wZ~{j%5O}6MRvZfrgu&+j;3defFr3d|GUzm&gVb-6isCo z`_m`4kI%8@aL%4zG_PsOuE|ezywPUFbnDq7UFga?ORRF1)2X>j~B0h#rjl#5>LXDu4JOAPch*kkjG4zf96nNF-Oo;8vS3T+w!1a-75t>WG10Syt+DzL#=VSGds;_ zcsR@u<1QIM|Lz~FGX;;;W(O6<8p+3Eg2N|O6nflVMWIcD7w{H1K*N6q-Q#B>O<;t= zFa1~&`PH^LPVCVLx@Q0SR-E~Atq(NCck`521>I~Bccl2>TmkiUrSEgOIQ{v#PuYR7 z{el0tKBu3c+6-_4JS0E#H?lf4zMxW9OxyC-V}ee1XCB}tvGhg*gBgFLI(f~%cblhj zttUKW-!5ohtIwzh`~?k8>IUXAF3pfBZFkd3gqgp!Q75*X(EU!Vnm_~M)7HD_~&Fhkf=(A&T)3cmd?3vyv%7znZg2%c#>m!b6SihtA+wod&*uEzQ9wGcx%9V2UF9rl%=+9~d$zRYIe zT^2o+YeQkQk6RgD%JrO(RnxBDVU^{uIES_U1<^^tZahwMr>TSYjWDrLG5!U;Xvswz zjuJ$1rhB5!yji{2qx-|OfP$J?F%1S&E4|p z)aJw&o{M+3=j;h|-Zzi4jZy$a;UZTW=-Ai?L{PjUec`CAa6kyY*4*-udy|vgBYuxp9TMESl$_?&q^ii{Fa|V|$%V)jiyrD@^Z@MC$&-iopwM(OG{cYBqW?f7^AVxTHz#P%990+%Z5i$;Cem?XR5e%H<4+3S0)V$?> z%QxMjkadZ$HhZTan(#v5S78q-A1Co}Nad0(>XiXxqDMvyuV*p-M{;&YT2Gtb0;GIg zPZSVd<5T+s`)R7$f+xjr2nylbzJquCT?4!2Ff)eQ-!Dua)_I{ZWR@DF zF_;Fq+(d>VHi|Z9l1i8FzbVSd+RO;>7b>p9*_N{vo-Ef;N(6h!tO{+JI6Sp4HYxGi za3qkY_sV~3-=5hch@g6 zY;I~Z|6A;H+0wfs6oMbwsq|P7HJ0y6?x5}pV3MMYo&%8FH2zK!n@CWD)OHK0qRi>M zwZHGO1XapmPS4V>b|9_z7t|f<^X6usha0PCuFuQoAIio*%7V#GoHXefJ=zxArV zRyS$>VbdiEEz^b(0RS$~Sj`4lPLrgJHC3-GTbF55Ga zf=VU`pyJW&hL=k$z|-VH5KJcA5(&*dItOUygMffnr&&r~s7n2M6pgCJsT1J5Ws}?1Bs^rdc_lNafHJDN3Yc9z7)EY$N87?EmtIi`_!KJ;^TH;e}&zh z0pg(!7Qja=qPd0;+!O`|`LA6&B5r&la@efKF%8t&{jViev>zC;2qdC}c3YC)uR_PmB!uA2G53lX-85l|0Rd2WXvJU=Cro?Qry38(zqE1sYCb zR@=-~V_?%j%o5xr6LeUI$>%t@wPW#IXrgV!l(|VmcEGQ^xyBiTGzvjikhCW9vND8Hh9I1sq(J1?W)kFNe|Iz1BpH{y-fixj{z=@ zUxA$UZp?0DlUhrQWI7cE-^=ls_Q$pBe$(C@dqrpI_zSQ{`vO(1v=9b*``4-OT}XYP zo7C2yV);)OC(W_w>$VnPL~fG_jkx*+~o!GByd$gRKc@g{rdsV;qAR%J!HE7 z>~^nHQ#YO7zJ`UR=}#uk@P|#8Cf+bxdL_XHB8YaGdyuBvMBx31Q;`tDgBbhOgRH_w zot%|5M{*<_O&lw|9I-Xt{o>c@7RqNW``{i79ki0hkK0x}70bYJYOd?D{I;%pQFWV_ z%2CD8#JOXUJGggHs-4fzKwUG?g=Y2^cbwD$x7W8iEXMUR{g)(1T z0XO83Beksss94_>23n5L4X{@yw7PTYaOMfTwqXEd?4S-O?>>(%YqW2<@ILW3TFK*B zNr_EF&KrIX2%q>yV8X$9QyWzgxlX%>cNbgl%eM?6At;}Xj_lhqQBvp3w;|J~4Kd^X z8eSK*kh?-%W#p;0w`n2mVO2-|Tvq{MWplAIrtVeN1I3m)J|0{;iodNjoWFFerrEC- zw{xjqLLZq;&NSEXFxYv730&jM92-(o2o#3vP}2Gt*)otEI9nThO-gBe+ zT`?yM-P~x~Ne+z}P6z}0<}kV`(R{Cw-Hu6#$FK+g1i6w|-7M|xBIJk>db<_rmqBy6 z9J>wKPs8pAO;=y;`1QROP^7*8>Fb}?RkN`;E!&kA60+yY1I4p10$01{0qFgU3$w0` zTRzUVP|@)A2RwjSslVYcbTK4E+3Yv}ey7FQ+wd3=I$q_QhSlsjKqmPox_kt;P5_@=UwTS`2YFI&9gw8_#0SqQwt8&e%PoF)uz zYb_S$IqVu<$QZ2DVJ>5o7#P$gB;36}t5&JlwH>gl4SyQats+lBZ)Z#-9r4Hr0G@&D zQFj56hvWLfk>`eql(fO}o(v8$b3|;L^-)@P*wj?tEU^_G6q5Fjunq~puW4I6B)z9N z1h#5r`M6}F{5pN6putsrSU*%+qvt#ttgs&%066gP!#js{#GNZgv5F0>65vA-jL(HY z#TihF(%g+wUA_dUjk24v$qQ5tAV9U})=5S9@?Ho{2!f&tX2Z1l$jf^d4`u>FBi~yp z99tEk6@3`!E$i(nJDKKSvHeS^aAh^A~JtLH0WM7nzfC-$ zZoHmmV!76cpA8QXlBBd{sC$`L_K@et{U6QS)b%9^V$WjgBi-x5 z*Jd+3BK8`=ORpz3bavJ{^D;^~R?d{i0DzL|py~K+hT6FgG7YvfP1L;u@lB;155z*j zL9yC1!6tWP9!#~C z_(~n+Q76|%eo*E$A^p8Pd}{BkG<+c@)1)%?SEV!R+rfJ3gXs5BBifJjBo0*A$m@)s zX|pcuOsy0dPg}UYbKGy}!M#uCkPv1D?DG%og^dJr%5REMKDKF76E)X8{gPtl*_Phl zK3A0kmvK0BNcA#HZq?>iZcTJec69nV4S7n<;Q?FxbEGXmz5y_g3{km0Puo|%nT@Nj zg`E6`U4bU4od_$>@Z$I=I9~G%Nrx+g9wfduON;nzlLQk$Bv5(;`+eGU%ouGJ^?qdh z{WjV|sl=mNYV4W8l_ob$H*r;f9I~gR2sjaex|1RHX8%mlM?oj(PrctLg%wCj$DFk4 zs^kSt5?Na@x{mO9z&guQqzQCv=$|ND` zriOvzCh#>{e3>a~-+?McDt(D{sXq~HM6X`s2=(EMK331h4D2P^gZzFJpJH3#CQq{m zqP^@GzgIg>v`!|D36J{6SDnAXe=MUP`Mm9M!4Xyyd+YbmmMQIA;$^?+t$;7CBStk+6hSp9ggzSxF~(ydqXgV+3~Z|88U+KJ*4Q`7GKFab6BPy%33M& zs=9Xa`dR)b*MR1gh4RfT#tDSxXhp1@a~g;;P`+YrgTp)ak@XJNShZ#naYwj_w#;(+ zZkB+`YB&Coa>~ZG&}ZDWWwhsk0yoFNPNCd!>C5=8hXVT2dP-=|qv`lREYmfJ85y=`d;83#k}Tvq|6|-&N*t zWN!JuQ>T*&HS=Dnj*=E*b-QcR%}O;NZYi=%6V&{GgVs^2U^~h18B`ka@t$qX2c{X- zO;;MZ(+Y>w=GVs5m9h?wpSWlDcK6M#PodDbaaq1TzLI5`Br|#cxum){Ez*wHG^`OO z30Fe1%_Kn3kK6>{O$2IRh8&R5)@;H1?Iji6jCV}+OSt}l+ZZA0TpY#*2ml}yM_u+8 z1OsfkoC%+#7p(2viFRN1;;p?Ny_XZ5!ZeE_dmlCcLK3%-n^HYnzS8;S^O08Kza2{| zKUY?`Drs$!H&nD>a3WahG!cD5n+@uh z!(V$8PhURwIsM|Wex60t<-P6r*{Ti}2{f8xkcBS$W{bjSJSWPKRMAoDj;S$IE0kma zuv5{rqH-zr)}}PsnenK_!j!1q`V(iUKA6s8fqHapL|NDzUd7t$=#8b@32cV|RMR3+ z8|*-d);ijHH@Kizg5K!G^GAiPX)Uv zee*8Qgta#F3{{`Cj8%69k6$zO5R|?y%Sy%@3p!evry(?to=?`{p99B=rw>3bVgtO% zPQ`Yq^04mVc2!~XnX{&occTWOl1pn-=k?=o7QayXbGs>}t=bi)SNkJPN1U$dDqt+C z6EqS7n4H$(2jLwpQ_TX*h(nuEqYe$e&;+$tKQBs2*B)yZVVSSCPn(^a+N&8ypt zrL?(91ue_jJ;i;A^X$XeAMMI7o9aI7j;_bvw0e%b4&ma+UBNOeAMvU$!;HLLjB0?* z4+Q-n>c>je%*2%4W#pT!qA5nFpOg#w(>?t$Dx6IBOw$0{#`fWqiyVt455pRtdbFA1 zwtgU5mLNa767$jG+rDp;VFwv_iJA$I7L(z>AUB_@4Si)>+>4g|(iI6Kya<-oURn6I zmmTuew&UruP?sO^XHNkYPIak#jMFVV1U>&$RN10-^C^%RWq)vysA~6cN!mj*%W>A21lyQ~j_^3DCV?EoB>pZQ*zxw_2meco^ z-jZ)4RU8FR@*ifD_SpeC5LQ^JZu~tYRnCaPpK&Slf+f<2a}RP~1T(&BUJ=r@z=fpu zF5NerLqwgw+eU^-ZJi$ium>e8AM4vs_^pe&MSQK%MZNX{zxGu_v8(=#f66N zhEg-5z!|TA^U+;lG;WU_6Gzh}5RezNufGFutt-^<@Tvj$d83lT*x$*lM#PPOLHq*} zyC5R{)c2oB*aRrA@2gPBJl)lk(HO~k4)c8xsk+VC8ITY(|Te?1qKgm^1 z4_oG7zjEqT16zrXa~=;b8xR?RJ5B3c`>IbEUcz%D^&|^MjESlZ^mySQW&<~^iMR|8 ztsoYB>?f^_TQiyLFXP=V%Z$%M2tGw?Dh!P)TbjH|ofdQQZvbaM`7-j{fD|ShKa$nb z9QQg({V)m-+(&Rl>dJGUaFb&? z_nmVS$AZPLDLKS-kKHl;V7s!yk zRh`_40AbM|3G$8E7>0JZm%8NF=r1dueD@$bjJ~YcY*lL)?qr!sg-leIms0O5-XD-_ zc$+j%yj z#)|#qB!RzFa$IuXwy(^1MsFZylRtkXfnvH!)FM%XfwAO?nqz#GbIR-rp?rXB>=AV)e7Wp( zN1YwiBWAedT=nAXAfD_8k{n0`O0onQcyXu0q-xm?~aAiL}`=3~GffOURZ3;^dy70?c#_3u!y zw_76=Q>H^)Fe`B63`opO9xVk(oic3y3>7d*9~P=20W@YzamXUIC3JW)^9hE?<6W?S zQAk|@9Jc{E5OFwCDEsIlT-cBq*(a3zPN`Q;Y7<6(QsbBIPdydHP*1CSrx2rTf+vT3 zK+EpJ9wa{Wq{k)(2*wa1^9YU6>$`gufof{v`;WHepX3F5qb>W(Ze;9A*)f-ipF1;SsuG>)cv_MH< z3fy$BQy4C$LaM&Rz?rQJprfxPrut2O^)|I{^f=f%YCo$`9wrIUwCx3dalze+#nCkR zFc;FZpA6%K04~}0$d05l>Z#h~Gvf;z>V%Yi6@`+( zC4s2|`i4Rxb?^M9dj-UC^6#WntLTedq#Vp zQzs7X>=Z937 zv+Q?2lmjlwz*DqHmiMkevxU_~-{`la`Qtr!f!ADBg?F+MRy}7X3?+SbS=o`nEpRo? z7JjsEp4*^k^0YVRVG+vQxR+sbw1~pZAo!crHRpZ9_6oR9j^VbD>h%nx5WOz=6C)zO zQS(Q{RFJ7L39U-Eg&>AU)o&h-Hjnb|B+J?d{_#dXDXCH;e1wn8hJ2J*Hhw) z=4^zjIp+T?`J!Qk8otLZ5!UR7{Q=yg!A;edYF)q8q4REkeEr>atnXFRECcC?>y1#d zn*4!fs%Nwe(V_JoXPCWglWnEu#3SMcUU@ydLo?U$BS&lM%=^73)!5GP9EZR6;7NP^e=%RHG)zdL^Lm zsB%a0{g8lt{WWU%6ec~&Xo&cx!e=ubtH%O z(GjcV*W)pG*>4Lqz>I7azV&0$mIH(S_wxH+LyxHFvd-V;c*pv(Q#o^b*gVOh!s;d z$4iYJ8Ug*L_A}ZjR}bf6Pq+YC9$9xEXmm7NbxwvmbF3xH+@6MXkpIr#7Da-sWd%d+5!h0QHbAkhIVha%;TkBAY;jKLe= z{C|O8GRP8VV*(atywGO5f+qQ>9^5sQFSOtN z9^p1QiP@)i*-10XgK=efU&MF+S%1J%gI061~^5+G;K^Ncg~>n z&2O4(oNjVIzbV76r|^$n#h5rYU8I~p4QA2Efc(xs)dCPtsTO<+W5k+102Ix4(mp>; zTu}r$d=XhwrqKqqoRkn@@>ruHTxD}bxd-kQ4A6t91)8g?!wcb{5$~-huUKC3ILyUX zUgt|glLR;>yL@l5Cu)A1vZKwDa54Uw+>*i|Ab|)3|IkAgm#VtToROycDp2rVe~XmY zzoILNzo6@UQTHTxcZBX+LO->&ott4HIa00tp&YIZ$7k(I#E|Pa24Qq1Rp&4Nimln` z$f#n78c;>*ol1agr>N&*2h}cGKI7jwYAcS25u^a6aLD8Ehjj=`7~<&pVI_E!K+=9_ zY<*+Qv^x@^%J&hk=ToXx&yD_I@Za=$Fn33KPfT6!S0V8GXg;hG3~)Xlgc@0n)Nj87 zkdPNAQ61e5aMsbwQPxlY*xY=qBil@3=zIGJ$L0 z$28Y)E2ebxYK&pe6a$9qifq}3F`tai*sG(j;7JWDGrFVemY zZ8ytL6eTU(EzZB+9;(Jh=I@ZXS8?&?oBe6!?j@v8z#7$DQ_J2w9RJOV$}PnTldNP; zAnQV5?mdsb-j+aZ_eZE-Q5AEi<;sJBTQ1x*hf0ZO=Gcry6reWb?ES%C+xFHfDmlRv;1V>V`6!ccT{Dy{*$X!CDqf? z6Q04(!l-BOUIohCs*0j*SmByvpmtCRQ1gOZL$2ln4$-6>^4PqBl6kNBmMH8)EzbvV zUvfNQ87(6P_*vxyrU12ej7A>9W94TW@(M|FMYPk#LaLp1F$f!a3!|Ivb}Un`YG=)| zDNZS5A$cvRVdF?mLyWueFx7?m_b=(FJsMAUbF)S2j)25NIc5Jxr0<{bT$i)@lUQ?3 z2s;sw)5ak9hKq(9iC!i18#yLBevXnOitYOgiU~wAAE}LVjv?)(zEe_iINvP!qg|9F zhAa03SnO+xrl)jXEYAjc`Uxh;i2VhXy=O;3u`-3SXS>!cj-FDeRWnyP^JOc=gs$<9g3ic+`;Z0l)Sy!NmaO>v_Ox@{Rv^A}`q1<#(j`7x1MSlM!esz>Pn z!hD3pS^AP+UEeteihVjJ-2gV2+c+eKEclIcKPSfi)N<8&wFBe! zPm3SZ)(M(m=R>AR@~Jq9*vW-POWM|DTS2)f?!s*K6Br+EcO5PacO=gp*jZ$p*imU5 zg|*8__xaglAMXo;sNa);UAW@BfmGn@ecZ+5U(j60c@qGiq(i(c*ivT6epuzr+mr>l ztH#dwtWZ?zSaylJX(t^=mM$WNC3FD6sbROGtB)2adFuh`I;TaGiUP-7Bj;5Z`-39F z)QIyn$ZN-U(a&m^rXjfuKXKGdMcBQtxZtPO>Kh#MfE<;I;|xN_D_?I#055^DVS$d7 z=hfHvuoj0sH@`-Omjn5|R<5a9&JJJTILI7bn9{hPOo@6tNlV6GRLls(kuCT)MBCOP zX^cctyXXJx69D7&?Of4Y35;I>l3FSl*Y?=(M4X@D*MEXbKynnO^Dnq$*2Tdx;~=K7 zyesUPNedO60%!*`Owghzg9C=me`(G3sa-Ji zXIfDkW8O#7bb2P~`oK@$y}6)#)s);V+UvGt@N-GrDlraAPA+#^emsTK~EMo|jWKIpAJoxNzjB$ang zU;ngrw5UO|OTH0CEV3*0A#3{Xy(>N6?v5+w9m@lTtC|F-2V*aJW2BfK)CAr2&3GMg zp1J2NjGo!bT-Y|(P48Y1*7rCW@Cy$Qklu1B?7rPZ)ge<^Z1$P4y&!zDLRC4XqH*Ox zr*RU;t*}^$!q1MQF7ab&9+BVup$a&k0@$>pg!ku*-*%(N_I3?%Jt)O)ig#TFXM7yG zX61O;r|jkE{-AeNT12y3Nen&SRTy$SU!8Qo?IEWP9ml@+=BT(A1x&v|Oh01^vi0XL z_M;}RleeFJ{6OZIl5cq2hvccSv@DzG7p-yZPI89P*cX-~rT3n^$>oj(aLj)}Vr7A@ zN@9jkcJ*Z)y0v#%dCh;;_(-x8j6BYUmS*|j zQlDlfSJaB1a9x8W77z;G7Fv}^X>4JGiU*%re^4vcD10eeBZNB=pNOQ+`Ebyy9&iYF4T`Oy;Z`ussP<69~b{m0?A_ zQ=vIF1ru16e)*ZZw-J(7V>sIP9K~n){(pkiUg}LxpGXjfcXdvKww|%`3{i)mt>AyC zJDi5a2;7P#_!a|4Zk6Ul$!+xl`jx6Nr)R3lLrVNIT;wtE#n%?lDv^>hV*X@A#xd)7 z^R?2Cmn8tpWsZi!b0CaEZvYaYdcc@NLL8zKqI#Tjja&C-dqk29sgL3)kF)ey$!+4| z8yTE;aku&){e?bmG(Y8&2C1iraCe4X=2S8*$ zptmfMKN${29*9v7m|3205DwL1G*(prynvM9fpA#b;0Ie7kblIG&l%;S7dQuEd;zvh zjzMTH2w<%ia;{&>Dw}-E8b(70<8hOGd=r&!`KK@TbteCyCs$3*Z38wGV&EzTj3_q8 zOl+SegU?mycZOSu;T%{no<4Ms>W*|BJ!q^a%Ok0S$mgfX|Q!P@<#j4V?v~?q_7! z$E{S;tnG>I=^XYH>5Nv=9{nbNp`$`1X_p2%0ivy76c<%HeYIx}#Vr^ecFgD}!G;D9>SV9Z z8gr)-aUcQ5=I-oUWrqjwd558{1%9AVC7 zb8Rjk?Ya*wr{HmUx8pP3sR9e_rt?a~;h?B2<2uCV&!+q;K^ z2a5-2oyw87SG;qoFW?M~&uwp2NIV_??dr|*=j+!Whr|AtRhlmx#u4L8m^8@G2Nr+s zrzH$etNTnTzXs}kpB)02e{0s-q;2p19pbfulnuVAw*&8*?_$-H^Byk3e?(~wsTX-< z=dkT`H>zS3q66F-5M__$VpvZg3ogDHY?cAamZONThogiWk|oTHo_UQ?OwP@tNH@Nu z%JcGi&L~p0@Ff9F!2i)$>*2Oed|@dc#&FzgZqEM9%ZpgRUNW^1+^L)WE{Eh*;iJPL zGJ%G;5&uGqy45bZS)H|_Gc{3xt3sH?F(jm!J-&lo^jTl%{L8{11t9o@Bqlts!;{tL zG9z8hMq8*G6#%w+CSv_EhW?dZna9}bPpuHO){FHK6lC znSe4R?9UZ38^v`ox8jVxkY7KGviq0(!Db;eMGWYb`2Z-bckPbJTo>_zRXwDg`Jg46 zZ(Gk+-K%iPF`uW^Ux%F8$#2kX`!A^P#S?%aMpJ(B2SRG}-a%}TaH9qyC2dP_h=#n6 zl{5D2;~++;w~=M}ToHn!U9yeG?|c`hdZI-^7m)>*jxu`IMUnI(V+f2mJ?n~j%o#VV;Q)FF&v8~9 z>aJ19>AZWB-PN9c;)FhDh-C zw+-a*-4FxE{=TA<`-rdTrILM($xQ!*?1`xE$*w1)1)Kd!9F!!Yt4uN=H3!>+o){DY0E>#) zc6Rz^tlI1c?b&G+8OsGdptQ^#2w^Vvc$kluQHXj9DsW4p^91a_-_FOdX)8hW>Lm29 zplYh~DW?om3y$)z_Dij|E!5h{X{(Xn_D#D?MV>_Bkv(M<-nHFYqjm=y@4@YM-rvV) z=&Z8QFHZ@U8=MGGn!>RML7H{I}r|DI9^VAp}y0LgY z#bKQ&GnC`aNAfQpQRgMyo>S`7R99sy{n~G|QkiqZU%+?d9a&N!ZGxMoX2Af6atbI& zdOoNmzcxrgr9vE!~*rMw&7iC<2>rod`6l3 zY)+2HGL5gx-n~xxc^Re{sLfS)V7 zSa|Ulq=E+O=3%SCPmyBlc}Yz|ggdY>06%vfi1Hvb0Q{aI;P0c`k;f!J9;X?23^UTA zAF>G~OqX=Q&7XHuJ3ywkyG;d1Um(B7xNAS{q^!&wCY0KXibjVmk% zZuq3Joe%^gkhJv30f4Qv2x|#zARm3B?0-%Qvh3;YLI_OGKI=fPXiOZ@T#zDhw0}W& z*TRq39aWUdMp~BN;yeg}b^mFB7e@b^@9lr{#oJ#@{O^rm{YtRye`STej0k4BrU2DG zf#IyI|MzUhjPNc8V^4pF`g+W9Bk?92&;HNdXqBTUb{yftEiR{$seknQ?@crY7)AfT zCrA%yeZRgmHX=;?(4Dc6>A8l{l8^mh5fJSV@_=pBrElMW6NjA@DZhtjNPyJ42CGWq62 z0eO;iNH&|@*u;dqsfh=qJ#KC#HOn06ex3dH&8n5RChipB{AhR6|06o8AF?bW6()vY zkWAjWfHZD}w?LCil}$gL3P2J~YoTKO(PtVKo|s>Cdd{1@+;0rWVoZYC$ciX#5sRo! zE;J8FIcEG6 zqRPCLkyq}Iqv}%zDnR<+!QEAWrX3_d;uc3mGIod7$8Dt{=Neypf3m|-NRa8n4=cA~ zn)Fm1GMJ!4Pd2ikhAQOB3GYz5Y9P_!G&lM=Hx)Lob{9$-dR+5@K>qwo$H>U2m}}&r zczyCwsV(473~wr#Nz6t)kM$_d=mqXi8pzpj>jhakEOdb__9x-So#f|g9^Neund#9V z{}Wj2YNYA5z-RGe)fT?!_~_2wHO7mHP(Vt~c$*(4;|16E{6_QZ(*J_OCx^LmFB5jh zQ%N9>HSY3_J7`IO;+jZD_|AfoV9aBl$VdBYcu^wea1TB^8$axjp^(ltj z0(66vBunti^8sn7s(!tH$K4%cHO3f43rpVPh^))`m^> zV#hNt-vpSK9%q)w7JUbyVK^Wj#NoSt8HbcXvllq5^t&Q0+jVFLoE;q<|BN0A(ynV(lozyvh@*s74#mN_(&g=1>Bz|M=wHSk%>k=T^6O*@;{Xl19t3i&sE zdGR`V{Zg$U^wA~02!4TSegX0wPk*-4$ICmi?R|aQCJudwrjhtnW>Z>v>?o@x1g~3~ z+=f#`2o6|Yc&HzEg()(BgIUaWJ8u{Hk9RZ(HW6OQ8Xk9gFLpv%R58)|EDz-RwkGT_ zy3cj)ZMRQRldtSps!ink`N!5;TUy!{WeO=nBupId|KNNp#$nMh=E*m51-UIZ{(Vim z2fljCgpqM=(4pSDcujBT7@aG|p0UCvs9gre&r&@dST3sQ`jYjH~Ju$p^OYmeIu~yG6%mAKjnte-|JysDU@?1=x z9RDrBlWVh86fd-%sR6AYsbNXKQ82C47|jyv>gQ(`+3ww-9rYCmKRPdp;8^^-YW@qF z(s|O2=Ut@!a&mHBqa<;~em0(bxmf%!8t|dF&|9d>!~5ahR&*N7e7+M{_I?d)XoGw# zCi8j)nsB=!oqsV;>5(^k8#;Siox#a(r_+L-()AhOnx8Nxt>p~h0{YG*W1*a7`2;(6rzDFKd z29zLW(1(4kqCOMA0WbdxasobpXv4w(V;uJ(8u5qS8Bf;gJS(yZx3d5tp(QGrPg(2` zf)p@LXnD?G&@kk`CxF21Uyvhl^vM2qu^y?CssDP^hQyxpUHoS>4g3QqFySKsI7yL! zEwu9F-yX67duRy6qAZkt+e*Hk_#XSe_ni+o%nN`)%5pXcTK})TM63NW3PQL5`ibJJ zXiwl3y`|Q`3;nNmR?78nbpUqDr*QSHvKVNKHxBZ#O&Lqb{C_+4*<;I@5^k9kzi7Yl+Ao{=*&G066n={UQdjnU- zQAF;xJ+ZAI(%XnBo=r_{wPd?1{nT@CLGmeSlIxuty?N8xxwZ?b_wNzcx+{#u)xYdU zUAwNjLZ6QUxuqEh1SVt(;5zRCwGX0K0!>@TDFt8}eTRhhzWA7M6pXW^2QmF_1ayb> z?UoKub|3$zn0(=4`1CR11SGKw9*LWy(T+=F>yihLsf_un_G3r$T} zX)L~}P~3dWV6iTxD{e=D5N21*$_wP?OrS7U1JUQuSg5Lr-l0$3NR!aihX)oFRXBX| zaB)@HGPOG8)iY#DGLD}pY_*Wlg!(Fv1*fj6YZ&XS@|EPZD$d_y6KH|M9%-Gv?Kaka zFgiB;oH2WgE-Hh_G&RVX3{+|)5T;^=dZtd9b1_PEoLi}-qf4bjL+fzyTAejv?>8ke(?2BiyP8p5hBa@L=(jJOq zI-;yG!nN*lGb7vhnZO4&Q8s~U5AM>@zc(6@0*R?>NqP(@)JOu~MD$^V8cB@4fVla# zffx{5;A`?dNzlU5Ex*68+@r$ZSPOT~Q)7y5xzz^QH~TbcesF0`=)~TK3t=YqZ}!Ev za^uT!97AbG656yS8Z$`vC}!5~&Tgoy9hr+{pHyjnbb1+Xlw_lK=1r!>`v|^+m+n z^?46X4h5D%dMffX&stEtTU5GmeqyD;7G z%>k8jbe$p}@h`869MYsCU9K{7RFGb8T6~SK&S^XrIr@(P>P4*QS%fp)z?0g_K&P5- z;UAW*L%wg(X=BHI=!dx7)Fa<@1Ji7Sr2bE4sbzJtxuJm z8YolQifB4q{1qR5(d zrC_0tm*4h@;6adOC}9L=4umUyK>q#ofA+XPvfgxbsj&?I3rhLV>`_2#E1-4Xf3=2Q zJMCarEEq8CV<^DXMC!`y_Tx!36r2x(#5U(aVr&;mz|Qp`$uQBf{lX z>4l^N#|`7cWIG8!W{w;$@NfMb=V8DSmWTi|3GzRCbpv)wjXK{T)@;-_ApPK|6Jr1M z>!=e+A*Ys(2VKyppsO4c!xG`%urr{QHNR!{=qyedY#VM}+P*F7SSK>D991HyPfcqv zz3;sGJ3XRdKwepVy3Fz4n3{IsUkMw1RvLv{^g_QaPEoitFPDbm<_7l72ndKS!i z2W%Zl7TzXv3?}EOg_J5O5)H+ zl;Jx{oSiLF&W@eaw`mBS2mJb>w6!XjI)eWI z2`*?rxigr)I#(@`*2y|~C5x{CHxva~H>8^NC0q<~CNES(jTn$} zM&&=qcye&7DyC`s6;VP-X#}D~Ix8Wto+ZL{^~obfOjc2ZJ-LCz0G~75BjP#hD3#(T zU2X$nfIHsEQZk#rj82ml;$irV_f!~3p(3dvaFYKEcr=Z#w`5@M>cGC%n%*c`wTGtO z9k9Hp>5F>1aUkGQAB*d}@6@277*kCoeq2OhzXfFz$hkv5L63LSvvJcUlak=gfPe8j zEdcY(evLQzWG6S9VO-!Mu9A2Gok@S5!j_+JUJ zwc2aX2h|7j&w6aL?oh|b19h!P`HSG0XOIsqGy(p(E;+MzSBmw3jC-q!KOvLo{_#7si%xECVLm@hY%2HK|)GtknS8px*KUk zVnDic228oN>FyeO$nV*||2Y@uVs58jdq1CNt@U0P(@C0trcaRr$QUUO zHz62Z6E-08KU1-L*#tk{cZOdV%Y@3m7Ja3(k`)UGm}m(J(KEl1^4toG(4s&@YZ#(O zY4oIC6$PMKVrvpKloEY$l|uYeRdQ{EFV1`!bxoS$sMBQpnD$=9T|(2bq47D^R+#BL z0ij#U5rMO_?!(qVaxRr%1po9h`dg)qh0HK$`|vm&{CCXx5Dn1Zs!F^(t{GD_Z) z6fb#eZw_t4bedH7UtEz)CtpdUoGVez0b^J{p=IjFfcN6ZiaAb^l3iGns4jd%&ttSK zwOoT0TGrTq*H2b+t)QMOv}HIFHvQV57cAPq%1PR2)3z<+tD5xU2?$RVL7?ms zIf4ioPt}&GU@7(gu^3M&-#*PFiXl-u|PpFh;&!Nld=3|HLn0qIoFJS$7jUG)em+O`t zYqvQlDRG|(I1Y*W-}cMmnu?VK8IG={R9~CWAy(Y1#y)fb=;2j(qD+`1eC#~Z4e9sa znB4?HylM^b|0IvtIQ>g7_CXyYs_&h?7Acw+$P(p@dN&geTB!9^oy(hcwPnZF+Y;zu zay8kE@sxg&o7fPw%@iv?Rv`7`ue?c3(!GBPE`)h?gr(ao)jt$BdXyTHw_U!Y0lT_W ziF1H4VYj(9u|!uEbfL1|HM^g2SDtNaIio)o5dEV2`CRdwp<18##LJ&bd#9YK2rmML-T>k*fSjN@^wzfSjZ#)wXL%Rg!hS*tR%Y&;#A8-d+ z4W1RdUZ`d>H}+Eb;km}HLj)65BfwN#TI zEUBcIi!ZVMb?$X6Oe0XGNjLN^J2xVD;nREc8cERN&2(k#Mn5wHPlZxR|zi{`8`bHl+0FWPgx*pJ0oIWF81Ej<4r?A zh(R>o=g)XhvcDHkIW!qFvSE65;BS5RU`y--$7a^t(nG^~7ve9ypPRE%s!crpWF&2x z2g*xElX)x=wEXKJJ=U;QEl&BfPOiu@LVlvw7r-68A3VSu7XC!xx0(LSV4Zb4Rm`x4 zKx?~n2N~OSX3(r$S@Xw?gTdR8>Go)!(id4aks1$9$;HDi z^h;ixh7Cm+PLJa7`FDD~6`5hwzvHh3c8Ca5z}QTWygX~&BX>2U5y3thax119_12=0 z0DEf6xp_H6DhdNkL_=c|Nl{*bk@Pr6<4Fc#LRS&Ll-$&lxG*kpnTx>N$i0p6MH~$6 zk`q}7P)Fn0&b^QyuP;*4D0-Q^TWE^7ngqjhC*lAmHXEQ55%*iZpe{p7gBiOvzft-6 z=XY)x&+S`iKIHIuGQcO+;*L72)-1+cq~)%*@{@w+3p5*pf!1*;dcw2n5)S&0*@Vh0 zl}-i1&6wo{w26~Q8jwF8`t8?ze0ZY$vn4h%!L)#N|E^jba-AEhmbPKdOZARxbN6xb zpVjXh=+&Uqa6~`w%?0gcF8Wv3UOiTgsCQJGrFgTYZoHRkP$l@B>b(-xF(E(x**}gQ z0p*^FUEm#)>hn%YeaJffG|@#tgl?h!Pn)G((oXWypmli7C&IvGXrC@ddaqb$b`xGj za64zhE4%RPGV-94c$U0{HC&f*WoG$jpi)}!NQR!AOV%YzQ-WF^CZ}pYTKwx+CZ>PI z@0Pfi0!UfxNX`|>PU2Q(h&(z@E;JIS1MpjBoKzmBB276k)vrsCWSBtnY9qSyz|p=LEqfU?=Xz`V+&v$3}{)*^#t~YZ>K9=&*ff;Xv{c^+O{HeH%$<7Pb!VX_-8XG z7%7Ia6rF)!&cqX3n9EiTN6%EUO{O%|#B-a{>YFz>`1)T5rLSnFc6&6o+avWi4R`I&S!(oA{l3Zu_nnzfAH3=ExnMPiv@s zEDRpWq$yH)FY++O<1_oH#qsC0ruZmmdMjQdPT!P~Tw~fY2m%_WvLW!E_BMgle*%73J4{>x&#w#p z-ll7C8LTw&dWMBn)hh>uD@Q;9?s;}2SKS<4t;Xukc;zoKbU$+-3(kdkktQ)nstu|e z--teK&k>{LwmjqzXK5>@b;dx+j@z6zQ{mMSXP-C*7AG>l?;{FC!T3X9g?-FW4VEKD zoe&$R3guN^*RONg>91PPl{|<reE zsm_T%jISrL#I2fc)OG6)C$;bxk}1LAmo{qB?~uCNAri%u^*@0A3mz>~pqTi49j#6N zxn%Q@$7`LR%L zAWh-C%-CcnFO();tl@T-6-~RHlWrxqk-?9aaXUp-^KKCz1@Pm{g}jVBuTzsWX+=OX8PHaBvm{-$NT z$KcCRf12qwm%$u5F~$pvxyu^9Qr}FoL$Yfyu#dCd26_o?Gw(`dFQ90dudR4|$;VWRBR9cvD^B@S9qn2!Yz{h-BA&n7?QDLBhUk8f66By&!BU1)P^riy z>UX7SI|}BlQf&+&oEz+VA7ZB?n;{e!h#EO*oA9(v1794lajHiusUhPxyWjGvp%DJ# zb^O2C4AnjFwX~?REt$^61?r2AdG%?a*G3Q>k@^>pjLsWaga%avIL!4xuOH(_l7%sY{H)^Q);v^KW z7?0(zi;7Xg{?{nSScp9H#e<2kxvOXlq!Y#b=%ZWh`}TtWUjwB6eFW#L^KVql)3kvCczxJC-F(?c>yP=UhaiNCNy`RCw%+4Bjp>eMS4Oc^54k)$!suciPlY;tcvBBP(=6Z|kNz@?U ziCT*V{WRp-Z>J~=a4X!3owZDR1zdIL*sPIU`ah78h#nLO@E~c|VWm+pn~36Ss*gWr zG44bv@-i&SgFQ8n*1WxE`3XYbYt6ij#%+}r{}@0Tm&iwA zt^KaCUv{YJR=Sz!YCh|vfeBKdj&@OC6qzz5NQvZB0y)WzHkn=*6=aBOX?)FekkIj{ zR*I}1>E}8RlE~}b9yBrY;gapd&vxxnIAJh0;Yk#4b(MZP5J*$CNH|ia97(hc2cw_j z5Ox_f2!P>sdif`3_fDPeY#OcZ)-(B!zRZDyPi>!< zLcb`*m0Cig%KOwM*QTd<`IO_&~UUO>uw(>M9(7%p!?n zFj06gndtj7#dhP>95EpolPa-ExgP3BPsh$_&|Vb^cbseLijCn@vB}N{yuU5H=J|Cf zip_r#T$2a1ZD}Dfwko;uBD3cTS{^W)S*JbD5%_O?Ey>S&BZVA2?d+e_UMf!bD_-L| z54ljab-JKT?WsOs2JRjRB#hK8ib1|5epkO=NET861Lv8v9|~~!!ejXHL@JWfC++kx z%2wK#uZ9GWL|u`gNQUd(4%pAZl9`6toTB&3?_@vHfoER=bl+U~^yMxav+&`G9V_#Y zgyN#9ZiCa_0MA$*(+3EiRZe8@XNo$jP1+ZI(`TqwXF7Ep36~7#LqiHCs*h8=jT#@8 zBarO}S1A;!Ou3+#k4)nnQCZmuvwIB_1_;6Y{vzwtHI_~!lmc3%-m|{8R)1Ra7nE~D z+;F#uhEwOG7sEX(I^D;LN!%_|-C|#**^NmNUh~Zu@D46nsG65vY5?wR+~mVT!vA2S zltCS;tb2X4WpQO~tEovk16Ow%kq62I-{UAI^!?B>CwPzJg?TK~bF9aNK~J;XRhvz2 zM2rQ<@f4jsEKLO$N|Vh_gMxeP_Z4>{z5feJ7<*!Qeg60iaDcPROrMPO4~)6S(kPjvSrtzqXanIuX{W;>$2A zD2y2|yRq_YTk;L|sOH&HlC^i{h!`8n_=akb@oj88zeY~n3O1^anrx1j`JLZLog?aW zp0yxaNjlT3!M(tP>JdqKkPLRdR?N#G3jshT$GOqq*f@kT(@KdsWg zIyy$~D{azFqO$RPYs;TpdNJ$8g6a#(!PM@UQl#4g7ks}}myp$5#Ji=v7v}a$M9L_d zI_L)p-~RhM^6lrU+#+Y8g>YU9s2XwVjHNV5jQM*V&KKZMLf<0y!gy?30&DHH{dC09 zh!f^0)-=wor#@OkVx>^1ktknW{jKV}ByVN5Dke8PWH6xKoNbCfBgfIuiGE;xrsHIP zE&YPigCPX{5m2h@kAvn#zW9|}ySIoOzYbke<&Z=1iXIePk?(#SY%rYjH7P{|iGok# z^-KQM?Rv@e0$#|$x&O)Wct&y=Ef_1lnf7{^C%Ajy4{c#ikcQuDsl(v4XXw6 z?IRlpQiVG(77t5$T3i1n-EsodeQ{#GDHk7+ao2apG3G{u{Gka)p1DWbAZV0w}0efc6IQ%_rQ^&53_{39o z6JcL(8zN(d-w5dqj*fqOc6}avYB(6j3j=G~iB0#As{Y&lx4U-LCZjxMlV)|ASFaT-Wv%Fc6a*B59+FtwpWb1|{h8?9k$ID_T`-LD>HykSuFlk~r zE%SBk-X6R5HePZkb7fv#@V1XD=u$az- zvn6<_=_2Q~ab1Ya#R`F+z73`@*}=^c;CAU!0w!)69BLefr>nR(T}Gr zx3Yg0PRH6@W~mevGu)qm{DcNZ5jt7`A#jFDNqa@l_@KTN%J~|(T#U>lr6l=Jb#v*a zRLnlS5Jhr0_Bx;ThS!wL@Jc*#nf5NPFzs9iP&4aUhbN5ZOet;JO4Wm7LyKjw0E2#4 z(O$e};24OW!^X#;tg>pWrO`R@^X638SHaR+Chjr%L>+Tc-2wgYV7v}0sfvFCIQcfk z+R{5a(8{>$p_{IoYEZQ~!fFeAGWP8-6*tOY8hHm^d;9d@uRZLm18;&4Mi_5l-2OA! z({mJ%d7*uJJ#-6<>rXiq-CK026Py0mqC(ZF_sQxmY|yq1HiZ#An3CEb7ff=J(N zgs(^2i%n22v;19=3hWxbPlXFUVN|i^IH*o{q#*J)*H6zeMtNShoDFjK#}+wVRc{GC z1eyrGD;?ql_-fsQ>5o%WFL8UF?_(>yzG-kN3Hv8a2tlRpwR^66=FUiyzNKh1ecvh! zK%$h@oG<<k8EwOQ7tyY(n4 z8vLBBn(5qIueflv2_;MX0*8kCis>EcYxk*FKQ(BtQ$1fdQ^9<6yVtRy<_Mz(+aJro zusGmdNptq%+c+7ga8c(wpF@ShTwj=(^0Tg^`l*qp1Z~$6y!9U_0=h{F_qcUSf9+Aa zhx&S8DBynRiK7#Mb=+4I+>N=fC)uiI^60>garw+>FOiqKfWrYf#fE&5iMaMN-d*Vk4iC>ZCgg8uvmZ<`TpO^xs z1%QM0rDy445VEoyo@(rV##fr3KeIH&xkh!m4jc1|(K^yMpajSIbmMg;ho^kGcAevC z3Q>(Vq4uv)H^|{E*sLWU+J-2*#e_A_pO8%&+T&Yl`7Jx;wy2gq9V7jWkD0p$ zpS~;FhA)-UrZjLDCTKQ~;Th8*b}Az8+E6SR8M#54RS}BKPGmiV z03x+t_hMZ^<<*b3Pg7SR8s$>&1SV)fOnSJV3ajl~;T}P4wj0V)#_;6ifn1kwR6FsF ze~0oTYg5dIMDVWvyLzI#~z%85+f|}NS2l)0-)Hi1t3TT-Hbst zA@od`kO_4SQcUQQ+lX({SlK=_&|Sx6JMsTu;3-|b2|452atyOxDZD;jYA5dfjlg*v z^tL+>>Vq5Wjr$&3;nsSl5n3ttWmRqXI3>n1g8}N`un{A4f&KZNHOi=n-KO9Zaa9cc z){$^3M`g!18}aT5@@JMzut&x%Rg@6xM0f|6p7m|oTO$L>z&L5ruX>N5*H0{p`qN?r zp2$9aZ;k3(XB}3Fij%l&#C?A2sC6`fvNV2EA_aXDM(St!;xb@6`$Fr>UjyIWOZM8l zPrrs41xf9RZN4YRzj9-i7@80vJGq&7^CW<@}%X9A%~GuZu2B9I8R52*;A3 zStlt%=;keZCT_jUhPVeQ>fISC{P-py5szE*-D;V4)z<_OQ>EwGq6~!hQ+n2h-~P46 zng6*c<#rr^LGmz(p6(gkLv|NpA$J4xxte|Gk&ho*m(h^%YnlBc_T~aDfAhX!*+{T( z=7TPT;Y#fl2G`2l9I@noN4f8GjS=>1RP*1zwa)=O-GtI|DGQTWSS&6IIL4h41AGy? zwD9b+_CGs*8s%#T2fDdg9XOMhg=2U@>)Qa9(u@6oeK_k_cKdk2tJwv{X}buye|Z6~ zC(0&vY-KmjBA)9m-VJAaNPQ(cMVz&Mef7ktX!o#B|mPOh7Ce)=%^sGrM44Ya z%=bIQ=v-b~+RglmkwRVtS4HnZD{$0$9lOn{8p2`YZ5ey_&LwzvgdxJiG+E>wdMQs! zNiX!h^*qeQC(o#ok!yl-Q8G^RcNXSt46#Pr6c8m3uf9H9T00`i8vMA;tUOHd98qPv zncEM=U-j%5m7lLxz9~Asryh!=l!%o{q8i@S6{De7Ju z@ipk-RmNlKg| zK}t^2q(HxyG+HD`B`Qnx>^Ajm)EIYNm5B5XB(O>3_5EbF;l?l-txt;||9 zjUgnwvxdT z{p9fFL2py(o1&tR@osr2$N@~&2aKQz8>umh1BPfd6eyY5cSpv=-6A#2ok)=QK+HfE zp|=|GQo#E}#pbeQ*&?>7L-Fu&`6Bx+jV#77{42R{!5=&coA=`1D#$%g(-Tzy z@%ZFxI*t;pHDl|TcVH^qykxY1%O%96W$x0n06-4$+%s|gS`7a~tZDyS>HA|0bG@b!Us0i_d( z$PI0w{EXgY%}eEmA4q=M=+UkPi$ajtIOSD%rXc}oJU^UNPnAU(o3IDHVJ>WF-H6#s zj?WCd3cTFP6Wii%4F((db4rR7*RtcL69bh{+6fB?vow*Mlv6}6a@AD`J457%V1>Pe zyjDaSTiox%D6sWI`hMAtDXq zUc5R)YmXBWlE{7dCo0|aFVR(lW-u*)=0_BR4JK_^d+B1t_#tpbJ!PH+i*7^Rd#dc z9H0N(I{gRwBZKD;vO2)_Exm)$)OCFMm!OxGV0%avEk^F=(Otat4$7|rt^bZ5s$|x5 zOTPc_VPPC>rh1-nZ%+`yUOw{6Bh&jOcmImNkALhdRYTm_f-d~HAI}py@Q2@n`PZ7H zY4QY|<)RfXz_83a<`)X^s7-2Q zK7P;o;YN;YDtpP>&HN*p@yT{xgw8cb3}Hc^?7Z3Vh8HizzBS2`|4F=C6h61BF-XfT zqQRsqshxC#>PB=$sx3c2(4&ngYxQm6wuv&fn2jqdEZWi7YIjD>)7VOh|4~Gk_A4+Z z*`tI)S{AES0(+^@3mI$X`zdWlv)orwFCZAJp#sWpW%*6}DCs@zb!hz0_x+}ME^ZVF zwBEnFbE13odFvU z35;ijZ6>y1aS&djXBuQXCbXpc{s*^;$Myl?yjb(b=osN*SxZBkZS5#ty$ikE@}R_m zW52B`MQ9nDoH8E+T7%$0{4l-hwysX=8*m6EHQ&hPggI6f7qyqld43lSIL2Jx(^jMT zf@D&kC+P7LM$)DXVWWBuhrlnACtekM`I6C!>oXhzBdiR_u~BF`{8)c>>DYEzGUZC- z{f>DAsXV$pn$yquvSkE|PHvy`!8a+QS*P?j!W7YM&KT&T)_PCe&I-1xa}Ve=CoZlH z2VxuuU)N>#S)NT)cb(hgeYBrZt^23}E(Z_h8=Zfv2Z!3>#7Bgf=LU1a8I&^ih)*^j509hW$Oy5-FT}F(&KwFOD&b zHCto4@^dmpn=@wbs{O2xjfP9wLa-{vB{_BkNWkz9$AfW$#ZSWXsctDn(9Orx?UA;) z@o*~f-gwdBD&zIOj112%L^6Hv-pUC7$5iE zz3GKcEZ~M}Ls|uw)f1geY+8M9v805zL0K5)p>N{m7shmTY{u3>ay*LEJiRvYrGbL( zcNUmRDmd3HW9O{0>V$#A*g)BV@hDM7y^}`X%E!%2AY**b)=O44WQ2c@rK%p0T}_L; ztZg7_x$xp;(nWPcB6ufQZS~xedO2%?c=N3Jgw?*VB{>QtX_xe_xs6 z>@{UITegF1%JhD-c~+}4)a{vH*YKOvo)=c z*WVY!L%H94OQEb)ZGjNpY^wZj-}a?6ARIpdSSzae-92+6sPs4fUW~p9O}1~PTWyd0 zAy{PY(@*?v4IM689p<{%cO_%KA|MQnnP??|avvHi>UYr1?_Qv_I{DvY41Sk`2BJ$m z`xnm3*ba|6#^K7Y&pXenj%BFmdVd#2&Toq5`sPMN55X<+M#bxTvg76VF7Fy-lU2yp z<3RlyPhgo^R(#eEiqi+VLtYOWCpD97%)adap|pcI5_#6<%s~_dze_jOBF-RNfl(R4 zQ;LzMgdV?=)IL<^#{-G>f6LfkCIFpr$V~2a2xIA%@+=ukNG9`dQ8P_agzY47oqUbX({bwMzjeFV69e3D?HS$*on^b2f}$f|)S+HBKdmR&3rR%d8le zr|zS$uCo6;_}XCmk6l5?|JFfLxus$ayEkVWobdx@+r|`7^f}TIk*Z!*ec|aw1qYiG zT1jU}C3knp*Z7;lS0AyswHt(gLlOrlxK}hyzq8F3zY0`Ajz>~4)M&zdC4i+7#PkMf zEh=2rv|OH-@J$LA|HlFkt`2mCnmcVR*CT6`L-vq0T1sm854FFKRVPjkY~HooI}UwL zH)u`lWX6ZaxEF*OUU17~o=-t?mVWC(x%TO(_z0c-ZVEI5JGMK+wA!dY_>#>Vas z-~P95+mA)WlR;{*r4ca=Op_iZc0C9NamqacD9lMR>y@9?tv%KM4A4a{mgFZVgRv)p z=r4GkIQwh=fDo0G)Aq63ePXxRJ0P$1g#eoEY^os?ib{D6RG~VqkG$Nyn2nDQ;D-OM zb=sJCW3|=`e&iK?c}M&#|3dH|sM`t%;u$hmCq2zYnk+V%>^_;?hl#}geUeQJAnxgS zXHuLEEK@abBZ!$s5VpP4kC0v<$XWI2H{tlI^~)GA{4(snm`$+lTdxy1L^zehUnuOA9Zz_=H%H* z+B~DSEi-L9urX)X)-jLqJlDHMX@0&Rd!xTn31&}0bT1!vqk4bS z9SzP&KBPkTRet`tWnQF$Xqa`30_>k+=ldhia@8o@n@5BkDtcP?o3MvghZk>m-Vn>( zb8^0#BGq5E{N5Imee=_V=En!JH6-8|^=+b)_4jSu{r@9nPp=)LydcaU;vVL^(+F z;dGEJj2KB)zs&J5(`I&Bj!5)~#&+e_-iQIyacn5stoqGB_*MM+6<<^Fe z$C$wu0m(UGc10+(TSpDY{b$z2KivsnZ5!IYm2b}rlc?(N*nVd&z1&LrnCFc<0z06> zd(zyDGO0cEu8jDOi#HVYk$sXw;E7Y5GHOd0C|+QP*S_4T|AxOL7Ab^SHt=0aITFSr zy-7e~sM&+*dCIE7Cwfk~`^Zc}KU}=4^CINxT>8je`Bi%LC&>|U;GhW5jBWDPbEeOj zJ;Hq6jfo)yXD38k9qDE%57}>mmp`n7!LzYf-*mc?*D`j>Ww)R&!OQFA&{U3cl@aBD z3S-TdxZ}-y-ux+`H0cmq{QeU*a!F%7zB>9Zfn?(<+6rd+^zrg${YStfC&%!(@pQqGStr%eQ`r3J6zR~Vj@MM3p`O($j?V4>cGeT11-Dy z9I{#s%(DcMcynb1iTz6Mx`u{{VJ-ObZjXxU8q{X=%+H(9_@+HyC+yK`?eFbg%58(@ z7s8=Cdpx<17XN{Mjd`WOE*ScSR(G@K&dUGZYDApQ(MW%eceTqi&8@N(+aJ(Borw5& zfwdH2r}OE1)8!<7VBi4f%u-a~Ddor6Q`hPxRq345d4ZfMv$a8_FZ0qSvw?`Y>TvzW znEKpzLWlkYGYv)nTmyUX)+slWUjZ1en!HaXxwkXInX1y9$B7!$My!WWpohzNef#HeD! zTkf`M5u{19LZkIoQJ40t4;o#!T+MsN{oeI-Iq;HJ98(3GHvU`&K zdV%y3OZJ6Eed7CwA1_Ql&%4PpMBwcHVE%=2 z+#rtnm;?FLX17Hl+4HctF9pKNXiYp$2TKI1nF2{_$kLO1- zZg+N>$?$n%pYi2}N1lJV_(UL4m7s)4->vaaOS1j-(O}2x>nd4kMB{c0^ORlQ{7wog ziG&k@f)=!`D|fz5L~0uw+Mh7+Fki$v8NEx>rDgJ~6h#a%#v$4(J>$R|w^+=AEw)<4 zRvgji#KzTUnBe`0VmR2V8e&ZI=OQMhqViwndtrvFPR}EKAa(#k_Ss1AV+orUqxEc* zoZgsmT{VN9Y@&}wOTD)n{^Z51ssZ6u4S(U7w=~_rj0dTazNM*`cV!!5G?V zt^OfKGbO^bCA_L>&}vP55=x@|)rze@DYpej!1$%1-m7&t~ zMm}_)P75yE45$b-iHRA6-^J1G>wiRw^W0RIh*4NOZ04fs_qy-Wr}A^7i^%BVrY?i9 zfE%m9W@;#46gI)lq&yZD`TqfJ4?4+wRa{RAC~%gP8;J*fTUA*Ia*u#vg@X6e>uEQp zZ+etTbai+4nWeMops-mpQzUL+%yErxUU^oMNqHq*;-6LAU(@||v;DPJ6S8fSNggQi z0QaZiTUIHGl4!@l=iU8-SB@Kd9Z^VP-$gWaoTjSAtbv4>7pbxh?P!zz`C9n8^TrL~ zxw$%0&2eRrxqPJh7#kzW8iZ-bTT?C%l>(xwp!7B4L;#3YtPA#I{uAKY;NZ@1Sm(j; zmnJpQcSr%Z%L0!FHO|M>`RHmG_bAm`!6+&DG{`)G&_zYP{z}PYwUd|WLvx;FU`|p= zq_jZ4z*ec5ctHapsJ^+72WzrR7AX;OK3zetp+uQ%1(QU0fsE?|(getzWG-TVrSGsg zbzT=ff(w(7*fx)tUQ_=1^(gosC?_bXOI8LgfTqdu?VI7^W!VOgpTmdp%sieOrgs(0 zU3oMmMIe;<_?t2G>%8sh0Ay=Ik36*xJ{mZTV+=f?Xe3n18(lPpetlkJjn{)ZdEYhx zf70%W4L%0V-dAk)#ncyX{#|i`bCP5Ec0Xyr@dUhN%)R>UH-YEPr&6TE;Q_*%GS*3% zbg<{F#%Hq+fh)}wnBB8vAWa3q;wywkq$&8KfG`-~+PoU%F{jnA%+6s7NJGVw9kI## z%e~#8&pKbeBH!E-I9(`Rz=gY2e18#pqh~cy($<`wZH=$Z!ZmTgy?MIJa*MANG{-Z$9}{`N_|k>%d?AsD!xW3(wgM{M=i zX5TK^=!MjJ5lv4)Ay7b%vObw{ z?9XToUR*jlQY&UX4>h28r@nAS0ybQT3w~JWJn%r-V(7VTNDj7fFBtu#DrSTGvvWf# z$Zx5`L?CRAQ|saaVbTg#iQ9dVnO)~GRHY*{orxs+T7~)hf0liS)46d3jgt)1zkL|0 z8VVB=qO`;h2p-KKw@tLeSy~Ym1<$Sh93!J?m6PLZnJw%`E(l#*2TGNz$Qoy_r_l9yQj<1b^|Ws-1E)3Z;nlrvbg10XbtCFy>_r@*gsV0^cb$C!6^xR-TT| z^b)R=FsUki2)Ad;x?abu!>1~<%bkSL6BrG06E(V0=>!G$d|mysuIhq6>ynX_-A-?) zHcq}`lT0uEaqbRF;VjPtp`!QYp+7@In9BC3uJA~lJN4N^qG4m7vc{wl1a175>Bjc+ z^YaP`6)?=nk`6IY)ENp0>)1qk*s}@opH;XSR?O%uYRqU%M6&w|+ieGnUXwlAILYOx z2hLcLEdPF+MRjDeA{1p~^6t7hSE==P;>kFSV&s)&&+rwN8%5ozp8Av89G}brnSZvE z3rUa4MRxCc@KcT9iZRz*Vt>@u>kOu9LL%*-DqTei8z5QG+qIUm-MJNVi}$?fg!k1I zI#aI3h0PVfFHwE=5s@KMM#lT6Ir?+CBe8(x(pd`W83@-yBa= z-&DjX8rtb=Mc7kH$Co1$(~xXr-QH9fQ(s8mg`dOD*%B~{0^LjENqzQ3631;}rp!!J z?#3r%{xE-`sPr${?EPBJfGHw{UORP|FDe0Pxt9-GARVxc;hjm*gvsKRX-BFES)W6>EN46<$sji+WRlX}sL{M+17isSgtdGI$VKX1 zgh*8Jeh`u1*alHTy*DrK;nx{2?Y1RlA1LZra5p7JsYY);w&cdNT=v^pY}yhK2+UbF zX&->LcwUKPw)d_4x}BZMKY8h&95DjyzKN3Y2wjbxp}Q~AqpKk;b@aqb3cT(eXcw>kg#`Ad*4RPYm*C5fF>bOQ1S(yIHDA~@S;sfr!wjHyN)`YCAT(F0o`EpmO z7Oy-l;~W&BM3{r!!WQm#bd*MV*q8@BN7YOX@4_(636;zD!-h`I`po!-2}=o zcU7PSVI1mh9FIe$D=r3Q_ZO=f5W-c#2}gf$>RE_PN93r1ruxK>@mYYXs$TRYbs?6} zp`~A#if4}YzIvUBGMAs)4+F-%wf_28#P)?Sc1?5sSRTr_zc4C7)t9k}&a+@ws_dvW z`uj3f#C(+P;?88#_Gv`Z%7s1HmmlV|IYGSqsidg5w3v9J_$AsusHQfGD~u;4tQKJ?p@x)Oz+1xAzqfbObPz9YfQ-d*r{Vmy>N&Mdm?yM~(+UwKakxqR`4NJ#%}#-OF;Y`)qeq{{#84U-vUk`=V62l-PP? zu=cu!sYU&b6AN6(yQ7b*R>{3MCefVJx+~;==r0ySZ|f;z7Wn_Lo?|5VIy0MogJ^( z7Y*tnGs{X`jF74M#^O4d#76r3UTlU6C=QVns0qGP&V9H1zcvR1(D2#rb;O9`(MyK< zLU(~(oC=~D`#!Yc*GFFGZ&Jnb&!6T9Zv7xy9dbQMqsr>rZ?YNfH}~X}+q+hPuq}|- z#6?>{WNH}ItqitH9MwQE!UlZd-^7t;x zJ|riHsd;{Er`l8=HGuX=IY*M_H+&(a{1G$o3lUMmx>j9cGml}+YD~+B?!|!y#?!s2 z=Cph_Ai`5%u|B@gxC(9RP<7u&{bawy&TAGw7~~Nm@N@+JsA@9bzGoRU+S9TZh&J6~ znMCx@!y{(+1;8YCRgAl`3inJMglR6Y7iE~!_ti9*(o*hFm6TFNRKoAeD@aw;ym^uv z?2nFTB%1WLKXZA%)Xz&+^6PqRt-pah_$QXw>dQAPD*nMVYkC}#qlMBO8|aq=Ju&4U zeShfR{mVy3DE=b_LX|zZYq){knQe2WKwgue+~`Bw(6VaK@oUEl~h@YBu4A#_4uuF6F+IHFdv3b~646buvu)%riuYh!z}7eu1QT5EvaN za8-8GqVX{N;hfC^anHb1s5qndnO)X16oLBe6Mk$qXXIFxX`qlVgohMXf2yx6x%FUy zCT~jB8YSXyl3qA1!c+_aO>tI&bpnUbW8{Z{5@yy20K(1|yeQo4{ll%w;kA$Q9z?r3P0mk!wf@0ZV zQQ5Px&gK<6j{7NHOa37F-v7F{lVk4sD#j@Hwl4JuRuuO{S_>I$a`a-oX8|?@jDgPj zvRQxW9Pm)&Ia9i-@(eoW1qm$_SQ`_;8*X~7J^1;p^tI?^q<+X!sQW40P2^WXaS_ZE zQtI;q6>hZd8Nys+J4hXp{I27U93@vUX#D}3?W*%~@!>(nxsx+@gqHiRxB9N4ajHdu zr{tq#%k1eVH}{~)pB!ApyW1aXvhc43w~M?G!!S6abirAkXS=;``)hR~E5lD#!!gpT ze8LO{WBp1Q*%U&}f9M+6Ix$bpm>J?e>>+2YZ7v%I)wnk7nc?R6=OWpimt%uXG*n^j zo_s|mD-faN@m%*zHr5@^raQ`<)qeLJk_B4$ZL5QSI%n{oZ&U+er7s05n1>yl2z!=M zVTX5z8$w*nhPAHWz<@k!=+9zoj00Un+)4ij!l|klF#@X74O2zf=O{S_0w7KqDz-;c z0h=;RvL91L)KG-1VwwMl3<@(VM)1WHl$9(E*6`yG7ovzwuyGIW%P#KSP-PozU`jg4 z1Zd-p9f5`12em)-nQArnGoa%CyUD|#aeV!;q27qg&qcR>hE>M0Ii4E4N-=zk!T_&i z_^W}x+~5Q4n!r9IHl}G(L9;t`2A}_-0{CAY6%%8e6|X|F?JFE~YqYk_T-D4&-N=g1sSfYbr1_%;D)1=2UOfN z7%0V;vKGJVi4XvU&Fzw0SF?vY0wvlDWfxityEEtOdk}ryzz+?X(J|b zp)bhh$}dHh7DSmYB+^;E>gN4Mu7*4tKLQ^~80h~dNvcPVCo83HnMAHxYw9OeV7%lj ziSQSj3BGMoB4!2$sn5m@Vu3O5E3{{-cw$tJ|KDz8b7-lkY|XK8Fx(1=D=cv_;?xF*SvJ% zCI~T{cPo~QxMoDk^pMYnmjCTvVLUW3c8MT&pjXiR3mmJ;;=Qbipk(@>>Kz4Hlldfr zQQ&vYiGEajWfhTlPRZ;kw-`8|HA3p7CZptR-ayS7s6sgDf|yx|w0?CcOGrLV1~SIx znRGEi4}1ax8F6s*^%&i3J;7*;F9F!KliOuEKz24#Qt%|&vRwXg*fBWcL9uWB%@eWP zW+%SX=9uuvyz9`_<%+_tA$2?(X}E9_(B^w;0!G+Ov$R8%LpS;RMQ7DpcB0E1F^2Z@ zfAw;=rOWCRatuEoJqY)&Q6LmITBEFa{V@0aMz{xeCWPTQI8d*1J)!+x6HG*Kw+AHy zocHghUGnN_;n%JcQj7Zz3sb=(iR}fRF8DgVs=n0Qg+HEBT`v@KV%WB1&wIIhM=9{t zdd>Sww&`$%r~IHSDs^K47dcG$Q^L2K3aa^b4+S_ljI9IJ*fYaU*u9!ulWWE65{oE4 z@G^9HW~t4OT<9^<^b6liQH#pt(C_A+A+-?m6K@U1YP}1pa1kRXxc9)oW3SHq61S9n zgnu0qTU5{wYC#S6=-g@)-dRtDyPg+Z1lVp%;JVc9eaZ*6$ntcNo<2KE>Qj`s8Q^W- z1F#x){bLaq*kKOq1zp41|3lY%hr_wG?ZcyG1R-KX2}bmi=%O2BBce?7L>nPQ@4bx@ z#OOUb(V|D9NAC$j5TbXY8+9-yzdL*HXFvOWzxVsYakw4sd#!b~)voJ2g9`5OKOl_Q zU5SwQt`}qGpJ$_{+j7=_i;-H1unX<~Rvq8)$5?MwY@P!}^?IPVfzsmmnMdja8kcF~ z4mKLf2U9HZk3Zxn+;I1ScUIBadR+IlEr8U=dn%26sZIrQ=Uij`%nHa^^q4fSu0jIbKS=bo3Mvr9Zuc<$WaJtW zATe;To@*$;cPpxus+E`8r3F?{RQRJyK4Z;k{zwBi(!i%@o7!e?sJn$OaJ4Kw%rZ!W zH~0Ct@rY4y12?t2R)<AFT?Rx0PCv4*jRduxY{o>I1Dg6Ep5T{at;&Svw;O`3ruSmTiZh z;qr9=joo%m^YE7P3`x#nlvDoU_MW;gtQP_7iYzehBDS7AU-NJu!O5@Ov0nkm+eHTb zuTJYs?pbQR^*x%Kn^)F{56S`Mg_hvk2;Gk5i88)afT$pG}G&zenNii-XM)dQ7Ye#qmLm(BjW}7-t0DE* zaipH2e23O}Oa`eGr~q{?&WS*lyB{Z_8&^@OgxOXO62Q#!bkS6M#958tetP13+;t`Y zclius?@6OZk6BS*18un*@t*t*MM_nH>~Vdz7lRhw5AoAt&mt24+o1dkKJEfd zQ?NXXy{G|rhFfV<&!+av;yyI`Hhw!np=h{)9e<;cPfQI~Tkb&+P}9eZZ{5-(g|cNJ z*p(xTuOoQU{b|P6t*C$f8GcN%DS-C@WZ!MMYS0y-oQh3pAo<0R5EQr;#LIWg`{TP+ zM2wPBncR2ZSF4X;^m1yFW--S<3T|*+YNDRNdN&s!t3eZUh z(ae`AWSghR5IxX8Ds11>(^TO5Hm-%YGM~x{`GPkj08N}ohXXlzDlyi0kZ=1Mk|@;N zY2Da-d3u?oo&Uhd82%!}JpIM3>r^sZrZs_K6>2gBsoGXf@iSn z(kZ`CaZ@Ee=0upwRK8U1O~Hk>oN-}+0)u7tH7h(K7z7Vx^n@U=kkN{EQ!T!ezs*KY zSt`}>zKvI^Stxdk)axki&OsSV5c$xZ&6>2_7eS>j98=0(juxuz=92X9#8j5+CansH zGf$3Z-&8^FBrQ_=6ENd_><=1gU?CMsv4?cY%(a)u`R z1emjKqt5r(+MAWArn{DlOOLm4NLB-(wd7Bk@CY{vKZ#}DIUc(l76r;!bl#dFnov*A zb_VwV<2d}j4t=A^?-UcfLQqO|n9~shTU2NkznIKRGEWh^PT%4YP=-7@Pt=nB@P4Vs z6G_tiScLz!GU0IDC{XCAn%HiKjXuxxr=7fZ;|>bjzQQo6!GD8H{kmrMs2;B6dgPj? zawS%Eq&I#UUa$1Y-tma@L%-|+)(aL?mNgGK+9oD3gb5j^TNzZ zjyEo+v1L37nGd{0cWqWoQ_BHiP)0Aj0W8Jt_AqnIw$|KcdYgCnMhjxisqYFIm#-+zSIc#h=(fFdnFZja*_ ztVgV-Z=6L`q3LO7%%MvW-sYJ23*Sj{bJRs0<5w8fH=mZsSKeuf=nRvXF16}|iXh@b zJ(XmDWO<3^hz_Wtjx|8r`AihGmBW{B_#Ejre7%eyCHm@7rHE(;!AJ&|TcpbfPVU{a zhDCaAo&5r_@TjKiQzl8q*_6NN;nvoRRupo$6Rv3zL9{ET*#uw@`(8?@dEVY*5@X80 z@YT0iF_xV%9AidT#?wCH%dpJH2R64YeXhrj2!PtsC-Fv(;HtjB&~})iX_hx*;Yj>W|C2_z05i(Wm`5 z`%ifH0e)Z+<-PZ?yff;M)8wgdne2p`;+@~H&iNOws&FVC&MSFO|jv7 z6zKMOKjzDjqW}FcXo~01KNKRIL zuXs-(MrGxFWvnVDe%b#4jBV@M;R3A{zm8hDjF5NVib=^q-H`_RM$cX~G;HU1X26MA zcsk*h`t1AbBa}6+pVu3m8^bsW6m)I1)%i+r)>Bo zT0hC`y(M#djg<|*n-3p({n5V#aRp9(^m7oettUH?AAnRUlPzOy{{Z6w9fQ=C>QwZ@ zZeGz@gB$sHM0ND0Eu<@*-cci2aZxZr86;JH(%k;MtVzw!16Y zjr&F8xB6+EyPSk4E9`*eH(;+n=wz!;$(AnDH*Mb?19{&?8Fj*(vWWa>V%9a0VdB7g zFVyqF>R2Lt^veS3zQ%+MMOXT)m;p3u&(R?dwSLO+B1Q#t@3Bf}$mBa}PX$}~MPApp zThk6{C1r`;GM_a$gj|H=S?d6@$+b&s;^kzcN@2$oy-ykwP2UVAwu01-tEg>GeNwxI zL|Mms<_7iKB;xzh7rjHgO>&utj|p`hQJ$x%(>;*}#$8Skc!XWdPUI__CIQ?w?=0f- z#fMavT#y)=bAqgIKTliPB{@4I5j&ULFUARX$k_59jIqAt@-?4MD>vDsxgd{S_SLkw zR^})q+Eb%eIvlpKwmpt76Yc%&$rt%;&EAqVW3%b;ybpVBl+JIywsf4yjPVj{V~Ha zxzC~&K*8MDi5c#kJOvh2RP*b;@5}>-ocuQ82v;9SNV^)~pa~*qM^vpva|7y|g$o~x zCVL}cJ)iKAM>|7i`e9dE;b~=AS2lm!!BF$W1ln-cP|fAwYa?B+kbpn8xxlT2q>`;! z9sAWR+(Fc3meVso&EnZjdd}B&vHh05k3=TwZbijZob-4{dw9ZbiBj3#dvN~1 zfvVSg%&A1*rV&E4(paH_on7;pOiJp}Cl%%l`1A23S9$5l0yzMDl?o<~wdoKsXT279 zH}s5;!r-JTT(X9KBGPlo{?T=+f#>w~=sy;`19CHCt7^TkYm>EpuPWGb1rAASuRaFd zPx2-#6mbhe~bMCC5lq->trn&t87yOMTa5aQ_2L=&m9@T95e{>z`` zjk0_0b$ho@(I&X*-tS_waF#w=fTb_lUxO$-(2oq%H&ruZN8YOp&{mqCryuSIo7}n7 z%XeKSeRcJ{@_Bv#_FbqT7P5jP((-ddOB|JBr5t{Nc+8f!!9Wq=S|X;x&(fYVZC&T! zCdRzH4bcVHa~nHjUiWrCS-nWU>Ny!m&Gx2Oxig-a_{6@bk7EhGkFcP9S9U*skmCls zl)Eses6L*M@3^pPjs2eW-le>#i3mT(X-NZxX6QzRIK8Cc+dz_ssy+8XVzl`LKpx_b zwm~3|_-_mtEx9g{DH@kU9@-r1X)FARJ#N<_#ZR-^^#GUIZRTu4+t+){t_;-zZq5J( zbTIGcCEX5=)ld3rZ>0V`?HWN24{!{U4^m!2+}mfW-D)GmYMwGW*k4QC$j6+ig|a5`8Ip z`Zqcx1(;dhJY^>XMMGQNe^x2}N{y50#?2GaW%M1Qyn^TV)9X zvU<-kBu6dg^1zLh?Fz)efTN#ECv=gqxz61J8`QU?y$Pd}w!W7Ck}t19rl)i;S_JX( zwWFNUQe5t#uwf2mv+Tw&j4gHIz8$0_9l#&C7(tZholXO*lYzZpT>8Ab!ixlT#(MVj&e%tZ0s_Y>^ zL9d#Wiu?j4I*1wmR7FV#Lt^5g^GX9p*1V?~8- zsVrRGYVz}e{DarPB6wqdk`wp+{Lzx?F2)@5JvF-`$`HY|BTPM`4#+tB+IZ2jV>_`~5WYnyfhA!p*Gtyvt6v^q4*&lsK4IsDxFr9Z<~ zz{FjrtzKs1hvwsC{zT?jNA$w$nw&cii>wW@zK6EdHa#M04wde;OE6?qmJjKp9`yRy zmu`zW956blOLcsHExRMGoR_Y_)TO8Mlr`4K-)rZjiqel0^X9(j{eaUmmGQhN*0;P4 zJmelJ#9zAD77x64)yP?a6HF@pW~YmLJ~27gj;Gv|%_pDZBihZggEWMrJQyZ(1HK)6 zGQ_x;77r*jC^@vp(-8p4J+NdKJAUZxTth+ ze6p7IT~-%+6#fTVtZOC<{-mCygl|}gI}J!bj}kuS%y|qFeG}cb(_i;hIRkPVXXdFe z#v15PKB0{nZwj5ofv<8zKG!H+$_&ju5gw*JPcFPO^>I5kRi@#X8XRr%3#5j*BR+{{ zswy{$D2OcTwU%yg*nK4@I8*o>16$?{JAncn?POfhO_8!1SEe526__U1mvYffS^*Q9 zy6)k9-OQnBmVdeAyGwtrtxv<8n|?K|@OmIjd#>e!SLOav8#V)|3UAxaI>WuD)|%;o zkq0pSOpgknN%1#-(rnzeN&Fa{^(jL4jy&5UKK!u%02y=4$hyS$DR;qG(ndehjRo)& zL9gH{W>Z%+^0p=2OaoZQz>wa=;TXK7#rj!QW%UP^a&v|5Q`&x};`yw_Xq)@^xV74S z6urquTcMlJ6IPs+`#ZGyf}*0xB`T?w>bs3uRSvH9L#4F|2J+_|W_Y;mGs5T|F|0JO z#v#@1Wj7XwL+H0PYddFbL?rN!>16aw=hasf1ds*E?#zm(VtR8F|pH&g-$-Mcd9ptF=s}SJp`bz`A2ddpUX0rN$c8pTX2?V zt!-Y}9x5H{^SHi@#te7!FULaWZJx=>JMt0z#i6LZr*66&6ep;Xh|p9@vKou#;$D!Q_+D8~DY+r4K>>T>UeoZp0 z_kiGWzR5j#_cD&M#;y2{51z_~)8Nz%lV_K^ALanHOUT~~(Y<9)qw>2cv?&a0}&4pTm^k4TBEDe%j7QpZPW z*JP#x@9ElxxARDSTZ5J9Xt8pC1~V1Cp{R=rYChT3J}$}+lT#*ONn(3 zh<&jQx!ch?O-_+PK)V()Ge@OI-RPA7XLUUG8n40dgOcini8MN>HEx8^gxftV0NdPc!N$&Oa zt#RyfDs!OnLzR6s!fi!x1%BX70H*Tc5J5V~)26~LifRSTg}6{c%ok0NW*BiSyEBc(=akkYnPgB2)mY^Abm(FDr&|q_AF= za$Bl)bPZa-(BkqB3@|%@94&xrG1bNF>MNM;R{R(&fW$cVj_5cT}b zFth#?Ltj3Y8GUoaPos{ib;ekg@&TNb^8h-S4AkN14R`y4FIl^zU2mC9Tnbf6f^mZ9 zN0`Z^>vRl~w-^|LDVQfmRE4n07-PmSfdInn03Luadqjb`xdGj!czo_R0oCq(NZ(3# z`QZwBGBY@z(?Ub_`5L!8Q_>fs};Scr1UXa)ZZq@}|r`m%%YwYW4 zMgg~P281s~+C3j@9M_nOkZBxKDL;OwMu6VbWpflf;8Dr3*=1CJK(yhF<;D}&Dupok zj3)S7OZ2rsKn%-KV&(sx_=x1Fsnh*CrC$UAs=ALm~ENDT#V{jO|3@mxwtCC@4{ z!K7ebuMiL1saK5l_5jN1=+SLdwjaG>yTzIcrkLDvSaKHSJF6B2O^k{CeT8sq&|WyU zO?2Jx?D_g&<@h(%>~Xvve=UJKs2IH&x|5QR)9(g*RXk#iv`r<&{YIWPyHfQwI&VgRdusxjkHdGg9nY8xhGmk;U}imqpH*my}}_-iKw6mMB$)89>)mME9JhZ2^Xp4==`<`hS65)Icq7 z(P{4mH83^~&ksAC^jf7%;Ak<$GUcZq259;2W8Xz4-3ZfbUtMw`m)UObuymJrIm|BM zQo>eoWZ*G2IPt{5@L>{y6cZHq{H+bc@h^}P@}Rs8I53J!Y81GG8>E{*uFB>dU z&ff}4o0EprxOkf(8BQxqUK$7_twC^*@~jLb@8(3m(d#3bhY!Dt6lo$YWa@r_nk*FZ zTEkm-tbEF2?IMfkZa3b^Wl{||cK?FzUv=UAR#n^bV88t$I`r#D*Yd}A{KP0;Y_7du z#h<-kD$Wx%?>5Nljb23DnETO)I#ktpr3U(vr)Wtq#;%`ZGb$17IRK{cuB&Y_G?vl5 zdKm91{bfb|yFI`8$L!8!sWjPDCE-R~NZXRZbX8ETKd)L%i?444;Wv?wJnaiVF*_Ue z3`eNlX6+KASwGmpUel<#rphE0NQivmGxjk79Dp6&(o3N?x@j!*(A#F-XBRxUpE{J+t%4eP`IIq`#U6_?0$LVG;z3}hLtuj4OPp*H} z%<8@DuV!b>GA}%?B>R(T2grGenY?Bm>187p_Q6Nd`$Ha+r8yQcX*MbivtGJ!?=`l6 zd=PTgufJFI{q^Tlrjw-wi|4a?b+u))+f73gB_6J#-J$)%BvM?b1Ox}AN-aiZ`0t-u zs9+82=UM$t33h(S?|n#5Rp@X87X0{`jr%dEcr~ zK!H97jD~@U-hJ&`fDFyN4(s5K&wAQRi$w$>o6Gx~PYu&JoUxAIUteVB1XiV<%<0+N zYB!Hp&IlWQdBJ+w_!In|78>dc?W3UbzO6UU6bw(dgS&=cLD(`(92`riA6yL_@VHfh z!vqp^3Zu%<HSt#Q>HXQYdm;l}7>{-6hMuLs} z=k3RENF||k^=DBYw5DV-Gb&kQ4FYQDVTaK{^1O-&xc1>aA}BcyucGXv9kVEHd`|Jr zC)Df_B@5XpBzKHJAHFcrb z&|37-%obEBD-)2-i!N_v^OGdp)orWq*k2ulVN#*5FD3`YJb?S=k5jXGDvR;?@f5$Y zZcF?q0qorq+gJ)C*}Khy6H_wm1nW>#6p*p!zu9)jPw@1<8O2S*zSoX0PgyX&E(5ej z87FDG>QZz#+gpT>AUugZ*(@&ooin3$7-wxQUPvH%vLW8^HZkvQ;O)54lTFP}_H-P9 zELo|!+X{a?BXI2X)u#5F5}s*+M_qv*n+kt++#mJ6adnYV3u%9CSbw$|6(&Y_q~~4W zKL5%0R3uPmm0%Z6AZl{0W7_9?(C#B5tTpj^7D|a)PPpanrbZ9#SwVXgTFs7VJ-chZ z>`~8aV1iaE{M^xAOuKM-e1dnA-*qCJ2qb5Y+}HBvzuKw}QLTGJtp=Y(|6%mPvrPPC zQ+HJ>`Vr~vvs=@%J73+Iu+X4>Se8#k>@LCbfUhQXPi2}XGwo49L~?8+Nqc~t zenO0rE1Ur3Nl<`BM7vkfBiO%IIhC^zDiW&JiFa%V?Qf}w2Hz0S`sT#oUs56W8{>pN zSdY*QptEs((k=EmL7bYIr|a$$7oxjCpD(+P${68~1=IP6kSuB^g@*+uJnaS^0X+}(M1KIocy%J;1F?RXCQxZAOoB&W5=?$ZP5*R08|{ zPbjvp5N3w#+9L)TB`;L1Fwe};ln>ItFS_&-JE53gcGw#O#6!LI-N$;ZPdwLIRWT6EaH(yf8Mu(euf-)BUU(Z6QBP6$2rP=9 z6^(jN;d2WlUL?xR$&rychR5wy@YAa25$Th!msE7C z-N9=;Q3P~ooxtq%1t-$Do;49DoE+t1dLXIWgxb1yV;eKt!LhpWE*C7&!(qLV?!X;L zpyaGNn#eqYA5$Y0s--THsq4LZZ-xjY$v;1oI9eIjzEY?kfzNd!%Hf@R-IJ*%w4_m{ zMEG&Ll=F~~&XGCqtP9t$NMp}!{3!nFFX=Uk`i-&Xd%#%UNSmG&;jg3{cyKFxbE3Z? zC1RePWEL4{nb+uF0&v%K2k9846}A8Lc|x$8KRXj^Q|H~oQre4OC9mvvnhON`OC9fm zA!hcuD6`Tzjx{0AeQk%KyUbBcVS#t+;;5(Q3t39uA6i`5EH5k0O46H(L6SMXNH>oV z5OE${m)|7bU4hK-Hfc@%FVmN^eS_j4MW~R$pl2xyp&q z6M@9tOUCxbd4%;S0}SM}W?SC|4{Y(YP2IU1zoQIrc_QAAvyZux+HOC?hdZ)-zT*od z>BU|V^koyTKrP4ZTZtJf1z3Z}Iuyq+FM6IlLz<&5Kd=PgfJ@0EqE|*B!}8i@}nV2Ifw2Jxgl}zA6DS z(9f?dzU=v=cFTY-sk%p1fIZxiuwo2Q-h2xO&dHA!x656&meDr^n*X)ubCBE~|ein*OnADsnVcd|P=Gb=-e9OZbR{Imu0wHSV3O zt|n>y7j8UHuan&V)>=e=LTZ1&F`i(&zjcu=D07SmzL4mjm@(V%YqyAPyj0aZu9Ekgviu;`K4E^!l^83F)6B1;XG09v_xy;3x9{jYacLKmw_!9VM$)D3n_H(mlxUgzRMB|7!en&Ur{`B+XWb2jAM}cAp1b&eE{6$H zNKh{%nPyXv(yA`|41E6u(qk!TEa3Alw#;9E8h2)`bBMFF2odkG|9C}SlwTVQYlel2 zl&SKs=qm)`#{|CtL9)luJ+wuHFZ7ichi}D_Z|(4{9MzO{AM)o)hex3^eWEsw7`LOwCM4n39Y<~ zMuxvQu*_qrST!sfDM|YGFnI$ z7?9MX2-%jbKDK&8NHVHc>pDoGgZxx_-{L7*y-6Cr4+iYm$uyrr+n(vpa zLc8_Z^R^}>$!o1kpJl2$GCK)(k#G6G?#J5BNjsX`FSlJc@XA-cGc6vH=`ILurfACi zo#uS_<_+?tCBrtxz3n=(16L;&xe?lw|M}w(L^J*5HDk7S(c@34#VlFrCT|NAy)roM z)g<1%K-}*l2TF`GZ&}gePU@GcsNhS!C6)FSx#`ce2L>C@m0X;IWx#7s4S_3dz?7-2 z70MYnD&KI7HSuu(?8eJ;k!jLvagVN>pMA{PFkT49s(>S;Ez@I4TyLjJ>-CCHbN={{ zd2BXyBJH^{+Pva&G9)kja_w3pT3ph7dE)C3qPDl-+iptr_Dvg>6=O6-`0D5fwRqw& zz6NQR{PUdN1}P*hBZ0~HYq4ZPn>0do_buS@shou5vjJI(E?gN@^O+!qNl~)Oo9n01 zDx$W}*tabv2aClcJ{Fn9LWLg|+YXNzOH(SABP$SpjMX&ehO$&Y zdAFH06iWIPUi+Nf+N<)57Y}52fH4c_Ym~|{G_U|MMtGSGD&42GIh|KB^?8?aw4Vc7ZtPgxjf<`OtZ(oQ zL4O3C0R0@;)TLu~P7A7kOh2<10}_O`KieKDEAo5r*`eW(?IW*nM9cVkzik95PvRNP z+p0wnb%rC;w`Slx6QX^uaaUh3L8febiFhpd6?MWlS}`YbLMmVU!CM$i`VRT zs^x#vP>LPkWaPqsL`4VC+dc9b3lrSok}3H?{244>v;nzlaaIA+09@0JECD77B4&;c zO*!zE`sP|B-}1a-$^*tX45$m6bza!(1qxa9QvTf8S4V4Vu#PZ_I@@(JfJ_8}=1=r= zUfK>n=Nvqp+FA4)zy#%BuAfw8EUU2oH<0k$R=R2-Rb!S(G8_#w$u?jM`l9{f) zcveIZEfTNJ*ILuLy)Abmt*!*pPnETCP!#tfk)ZHtI|y(34YBJdkqg0e4{i`%`eP@^ zo1xoyVQI{>1?KTu@hVX#xg_X>iV$tjcLhcd6vf4Wec5juG2gxlCQAVA@T}l|klI}K z@f0o32myQCM^l}jpCBNK{U-_;5v~~BWQH-kcF#gm4g8!KF8q61W9VM%qQE;HrE7kT zGNm1h+HC6EF~^{#BflTZS?OT}9opLV>wzSKF;;yt*3NPuY5kELF!q56lI%g5Q-*^( zgE%L~4C;Bb*80jvKiW&UYj_z6dA8Xgt788bp9S`U!i9H6mKPH(ExcItp@u~&W9ih2 z+G~nQ)cUHF>Ar!u` z5dL^y`U!H0<-j9)Ir+RY51?g^U{uZhB5_freN5d+a1=FJ?sd5M~>kS?xQUi9)3W{!mpB@VSFnw}4PebV9g8uNrT7KP`ILhN+w@(!3Iio!%9vlExT_@C zn*-?1eFQE@e*ptvPA{okg_a{ncrJn07O=bvz+araV7P!i*a0H|a~9gML~(uzRNA(C zrfUVUgBC7uw1c!OeidFiv9IbgdDPS=^y~PvbXZPJHRC` zX<|pud%ist06@jE@TxHl;BIEcBKu`Bf&K{RZG&;o|L^{^EjeKx;sPq$4(Li?OU}Q$ z_UG?N`*q|oP*V#%qQd?W-F-a@XZBKyZ_-q(s6!2Rd zWmVW~HV8mAH~;eht2=^S5F%sG!5_nqpfbaG+iZmN0L?|~{TwX!h!^r{)Qe5Anb<3- zHjMrVc!e`0sN+*3^mJ!@2_4?Cfiu}d0%F3=3<9vllsMQb(^u%A7ih#CIBn_wTcq3? zA?48XPy}*O3J|C7FA$cGf*3hG*M}ph<;MaG+5bGicAJNBLC_VP{LT`#FYpGbejhgY zZ|x>tg7pCv>i#)A{SoLvJr+2JhIv9UD9pdepb8%|(U-^CrKVl*l`Iq5o&@;V z#Zsime>9~0Z?pTKlEL=}>%HK;O7DAOA8KSDy0STEvQ zvEe`t;8y?DG~h{0_-^-20VlBd+w3_{Z~q=s#$SR#Lh1Y%kpES6D-ehN_RasQ>EU@S z2-i6w_>Vjba2-JKqxviOQ6Gb`d=oJv0a0r_@^(BRkg)tfA<0SHKL0luzdY(~yh(tSJPuOoO>0CMR#9qw;AUeXDSM~oR+EMJt zn8OaQ|0g(U=K-PWpC=&89x(mCLpLDQzarkBF8aTs4EWz7&HuL<{$`2?qA&8V_N9Pm z_^+q`)tmEEb%LjEtd|^r#ebe=Nv2wcH3}tpMk;NyCW}%{uB2W{-rMHL8ISqQRyQvB*$(4j=)UUuR{Ji8*$;<|2y4L z?;{QxoBw$Y*}48(!p6u&-f#a?z~`qM4<{6MjXAK1ledR)kO2hwHfgFo$E8f$w;U|* z&xh#zj-a}XPr1nLsS-eKe>wM`Y6GC0|1%u`p#}>31v1_K*E|A@DE6Nb`4a#>6$wl_ zM`wSUi#(=hap@O`|1bUjcXk58u&n>TO&5~$!=Ud9-w|kxb zsQLORN`;h*ldcy&TJ-GHg1AwYc+{kA752MlMopo0abI*t7J~&8m96>6yA}$4#d;UW zNPTCJH)oUx^`VVT?KmLm67~d`Y=0MwJV4CHrET}}{&d0G2{u?whNW&!ohS)MMpnOr zk$CWmu>AtfUgx|0EX`ar>^>Yr`P=L`@E*S1*c#ZX$EHn$i2DDGBIP}Sb31DeA za70G2y*W3sSbHe9^)@4o0qQ;S+ZNmBQP9e*bFu`N0rZK`R;+S4vPu+_|F)`)TEu&) zfEA@HL6=|apZwKz6i4QjaVge)%c`Ct(qGO}I{UV%IJQ@LoCLvS1^r>dk!Ge|R}X6q zX9RI3W66Ut3sib7Y0M%=Z2oGAAIrTRdvOD(&ky|FQvRhQ z9uOa3U|=m&{No77+tM#Yc4h<1(A+@;h8&6c-M|_2m@XEFh2nT(cL%{(EEakW{*Yrn zz-}Dd;3g{lLI`zSkCBq9B>xD-5#-=_5?~?ql)pfOHmv_Y<7qTd-~|Mr3I7F>2S&0F z`1bNU!2BMJ;UcFu7bnB8?YnVzq*nhK%s$L7pD2MMZkUk+pobA=dZS7 zuq8M==bQ|mILKAs)inS`s~rd;J=(aLcI5Cd&~ThD_o?(@=NEg`C&6E)Jk_OM zkN9T)0zKZx@!C{-8MaRZ+#buYt5;d8lYFhePqo(|9fGh5}1<3rbDx*}OV^5ae0ZN41O z^XSX?Ne`Fh2b&r<8FW@Exs`0Uzq(K`uT}Cf*R)Qn&%SC#(V#a@>6MZGZ}_tQ}lVE>As&$tG@oxm17-jk0M9 zegD+m>!#<=k9a?UHStMACFsa-{wA6gV{TxW0+;+^Auw;4{YN!ZK2tuRgYERC-X|Hg zJ}?H4BV+TU&8ey6+jYJSv&CyYqRi*=GTX)I;?Puu3G@L%l>^F1qRgsrjjVE+{ zYuisbE2T(&<{40Lmc~u}0wKKbKbwm4=Hd1$gy4>s3|>bLFeRH<9j@3Ldg58f^R3TX z(Gl0VNZ4tImf)_Q4G}=vEAPY4HWl+Y_rFI4Dea69-BhDm{N52|nb)Kiy;5=S7FZ6* z^1ro$I%x}G;(A)ianN%_K=k!R9Yz0KY?|yVSD>`$&}e+3UU+J*%l-EquaU}~n9}xD z`sG2VC%sFB3dSD(IZ8V0z`;C4RI~IvBbspH3&m8y)!HYYyxkLU>@Se9>&f=T>+oe* zSHGy?A5h02)g6;EW~ekWRugcts=Ga2jg~yRCE~iHPNODeRfD6>ADez~?JBY|kWJ>w zea?X0XOT}PtmBSfSCQBp|DHKQh_nPS_;$K3zw=oEx4D-BxGTkbCVCVGH58B-vAk=6 z%r_bpr7m`wrV`cFWIQgko@K*L4Mv z=Qa9Rsq;5qjK1y|X)R|YD%rkM0P3REj^u6Bz_+KbmjV~wH(O+^KMo~O+IUS4{3f52 z6WhtzC9$qClOud_Tt*mUTMtlix9$D{(e#LXZu;6qb8FS8HOyQA}*OF9)NWPO^ONw{+ioKMkM9VxS7P8!JP83pbu`XpRr^`e{4N zr%s~BR_zV+YG@Raz}CDY-vh;|sk?n?fdV4k^FU@a;;AV&!zc>00XY!VXy=$#ZypbP zqQo6UE%=7zfx2`izPdKskbvfxD6=|f_EW~*co^5!&qcrd+``>mb!MtBa34a=vl|+l zsyRL$)a^Z#+Vvj3`sF_n*D79&*z?!=o2g1=yy>bj)FB+c>jF1&uY@lRha;ER(Ec?- z9NVhMLYoJZr>)#>+4G9= z6nhsT3)#sV<2nPRF$vBo>_BXBr$~o=@ohti%+UZC*ca-%$HWOY2Us3`$~SePeR+66 zW%B!@s$Dt9A}T=pqJ7_xW$kpc;o&l;@z4kr$gO+Qz#_+b`sT;d39<3_#$TU83IHF8N6+(j(aZ0%r1#B2@36 zu2fO1v0%av)|zS9Gbbh!jGq|=6UO9HJO5aTQD*(=&-?oD4%Dahb#0Iz@}P6$QC!&g zy>a4*?G`0-*y}HeCslY}>6{i$x=D*Aiy_A65BLggT=R|R3&mcpH^I_GSrVJ3k^=_k zYr>`ixAjUCeIE$%{DCict*A%n#Rf}3bO;wgEdc|#mXC|B*dv#4TLt9_2~Rf_81vPR zR_dc>7SettO5Z(tW2(In+LA>6-8`tBfdo`(YIjm_DYa2y(Ce$U9LRH(b!A;e8v0qH z?2SmM3l~1^*C%-6I-hlW%>!)Qw*dwsH5u-ycO4=-*-3$(n(89{+{7a74^=Wk*$gag$ocpB5bpbW$Yy@inwWC0v4=AKR73THidFthN%Q`>qT$N?VTT`3Pt8B4p zPmzS?DX>(y3$JAD^T*@`a|!z9k1tq%$dY;)*W{3YE}!GS(91=7W|t9fo@eG1O&?Z8 zFmVFKNIAXrx4JLOE0EuI8yDY6*Dt#Sys5Io#8>q#!HGm`vstp&0tW0NdwY6mW8b1r zSXy6Z2_BK0+XZJ@bkS1EpOJb9?^^vYNtDc-5+%-0x@S^3iV08`W1x;6+Cm5e z3iKTEW;s*7fF+K4T}z^}xIJ6s(?LKbr~2rWYG`Bq@B%^;H?n)~S!owNb*+g41d$Le zIwSk;$7x0z#ac-E^Qzu?7DtFz>AogmhLc~JyG*`GP7ddmx-VzX!mS%ro%w2Yra8=!I9tA0xiEDt%u&RV-l1QuL4i`XEuJMEx!^xiua` zRjogeI^CJFXPr632N3*bNs@phP72o(VkzqJueE;P3a?-Ur?8gd@)Cb=j2#$~z+1}fMJ1eBWiZ9l z;&ArzlL&e?lN}>FHX%n0DAbd0S~4U+bT&kt}$Z;5N(TwO5RY zWv0|3YL0)(_S*}b(vqxE+-MR5<$or9SwPea9@X*}Rv~oXQC55JD6W0adG@WGadx>~YFr=2!sLnioSaRgKOYvhGyJQ~035v?F;@+9ZL9;R{XmWw{UyZYDyZS=>_BOA`cNok zUS&)w?+-bdKdkGBCi{)k*3TJ%C|6Iu4lRHn2mgm4C+jrQha`>F&?O6Al2P=zsg5I0 z4*hYf4_oUvKcP4Ev$NI15%}oee|j^f}qs)|RRVCL%I*A)p*5>D9v0-jF~9X=IR+AGb#5JeZEqDs&n)5^BxGDx z{0ox=ho-UalFP+g@H1R4f5bk;j-hYA^B!f#%WTTznXt_IgVu$*k0QW@nNO6(&W!w_ z)*2*>>>oH*PH=$2|C*7Rovwoo&EFc@=*A{<@7x#AbAXn;rVF9mgPqY&LeX5nj^+!iAs>)n3W#E)$N%%`{6i7P z%q_qITk`^#*8E#Xim3CE>;G=+^?I|X{5x-_;O>kQWXrw3b$~(Hzpu_!{`b{Rl5HBb zN?F*sNe|f04$we-Ty%nlUQ*jkpYMV4m(ttn!xyb0nk_ZvO2-RMmnYpnNt4Z5c_^L} zZ5H5(L=}RGlN&yGYZcd?=xxgMUPRZ|35j>t30dGJS77%F|BD7Y)M-6zR3|8z{;tUT) zUZ4%unOR2H(T3HWF9d~lJUef{WZ!fuZNWVkVo=EaT9Lh-{X>*PEg-RuT2!DR9y}iW zs?^J*!aeAwz;queKcf@qvnq%(wS~-^IPsd4s7aKWwl#ZZ z@Xg)R`qSnQ7CmiaTdAK`s8vTN%#K6Nlkmvj9M65mX#jC0mgDDlm-OO3h*2{k!=p;o z=29ZlCVTIDuvEqPQ@ruboSViA5!2Be4=$W1i9cCOWr7=Z>7Um=YEiVp4WJQg^ISU8;sO5xsr zN4a1$`u*N5lscGEwqdwjzp-1IxyS&*b4TZW-CP>j;jFd$x?-&u{d+Ng8^G8mm$EnE zT$;{eQv(q}##@jCQ8-T`y z36V#HP#FOsnW_(FOW}Ij>%aK}3_kjSJ`~_d6pQFuBdnPaT--}pmU7jVrn9E}JN9m| z2fJEd7_s2er{E2~M5g8Le}O1sV}FUxm*SGV`z-yPwx16}F?nN@8>n(Dcx(|}))F24 zwdroCVqc%x6pQb7Z9U!&MQPR(hPBbUtmcYdEWASSm=08z=QTkSA|`^T#Y9?LDHp?)gNWVue~_DS zGyT{C;m$8wJ7#Y)TJ4YMTz&e_A*gIm+7&niB@kBv+lkP#p#X|rI2Fv&SM}g=P_uu+ z+gHrbVf43vKa#--BcPo@On#k{{Ny*gQ$U7LuyI3?nqWckt)lEfAO9%e$F+q zJl$DQ23^@^CixJ+Wygw+VmN*dq2M%s9eb#8T!mH=#*lnhXt@$YgX-t;k_OphJYUof z2hQPmf6G4xGb}h~+`o5z9j*Ori!dtVobOC-YAad#H>=9N@oc)Ctg7r@D<=Ch@7yN_ z(H2}1QPSOZ@uaR>+AG9L^`^(buzNZ`vR7w$%*(>P?d;M>z9@!gl7+Jf-~|3Zyms1% zYW@YX_DzQf*134zWOtZuv9@|ld|7Zt3j2Xp>oo1tneS~(L$y~F5hDC{^R>}WqH2k6Doyq5e9=> z-^yOD74GRV2d9}R&R&5-zEYUDi86dmCH%lOA9)!LlJ*hVp9C0c8GkHH978q%2V*Lm zMB>1jS%%jc4jj`F_+d5aVLl@=-x4&S?rIFdk*j1!Q(6q^@>=WI2+ja;?v&1 zW=a%?-rtS0U~agD76$f1*q?hQd)xQ2XPFw-t%%zBB=CLs_cMirNWx9m9&CsaZAi~n z>0>soAt@P}p&;@{6r`ebV-aJ9f~hUJ1NxaI{Z3!+_X5^ZW}yQ`91EF;JcaiGd_aR; zk&yvp@|>%S7*J5)Qjt4v!#)K+dPC7&uGgZSVG>1E_g<_=ZUyUt0W!#!@iFdgTBvGu z+>-gQ%>~Li(Y-4)pmNrVm1BK_*A4x9@tJB%n*g8We`k=JKdzBcRP%FT+C032)&wh^ z8KeN?=u8OI3^YLPwN6^OXkUr_92eb&QKw+0LF)#3sn$)|o2q$4$kPAZh+;8yVLm># z3pz2So4=2gvjy6n?xjnJlAhSyW7-uu_1ShDXi0PhBCk{%J(Sr?aX)%Y7CIJC6T~;{ z3J!t9UG6z9at?t+?2=zDeex-{7kS@R^5i}wx2$|f-$Q0OC2nH&m8=831A`muc*Ulx z-j)6|dg+a3qCA}K>w~H)A=R?Phwh=;BkVn0yUtUAlIRY$aDLIhCdMiwe@9o1c9ku< zTj_4O3VK3~R2#dnXK(YTTOWs1KJ_X5OG>87(@v3d@Wjd|{3%?X(B!MjdkVQ%`IoA%EK26#1Pj3iCR^PPJ#2pP^aN4-;Rce}Hos?Dxn+KHR^qmhhVE_p65&(b z|H0fa?%aM%@w3KcT0MJ~RM@maNDM*>T1PvFJ!#?AO%r!y6({QD_qG$S0Wv8#X)-^7 zrTk*_m?~Eto+N@-dpu}3aBBsI#;X@t>;@z(*bbf_0#Nt!n=fjW~e?(|%#N3ctA z!Jd}zD`k-ZeVJKndFuK8I@uwOyvZOgibfFqW`;;=aj7;r4R_F7xL@U1ut_453(Sg{XwnG*#h{3=$s>6nFD2N0d*0Vex41P%6 z@&0W5iKI;C$O1G1sAG32`YHDu0VkSn$u;`hl6iYSY!U$>9>=Cd*B1IohgM|OZ=$H` z^eO*x?>oP0Xxq})O*Mygah(*6A$I3|a*tQ1`D&G3IY+m<1HVdaNlUf-K_A5i*V>_T z)s=#(Ve>IxpQ(s+NfzZjOs%2Cl@fC7b>q56i=(8Wz?$w-+^EVH3ck)uqxqV=kzKI0 zr$Q3dVP+|vry-i4T2Oahwk5*ypv*Cz=)BUi_ffrOm;76f_UA^wQZ}m#{3nelBjE`} zu{cjGL!RV-h76iA;>&76fdFa{C*X3V&d=+@o_onDBep!_$tS7i6F-%)Fef2^3w#aFvCj7w+e$edm1?v zQE>HGrxYmI)3gJ8Ow%7BI_rHuGV7sCYm}C%HPlb*>=L&Hlg-MUCb45YRm$+iYqK_Q zC0lcQH_&~xHHiJ1Nm*U)eRQQju06|kM_vB&&fg0R8>H6sG)ovBoyMtm9B8{b7E|@< zWm{p-3+IH{i}(51db5P`vPDOR+`ilZ`UKSCpw!JZ+@Re_5~UGE+vy*yPyl=z09d8AbG1Jjwn}xZulI}Vp*XbVyZH~*)y@@;{IVeD zjIv}cwSLOTh$pEPlP02XHOjpLw18x{D1qV`7tjg+mwK0Nwtg}Ud@^7ryBJ1)WXsuJljQ9Z-*N*5IelqHD`E=&4F_TA-4^3IJr1Ng^! zrTqT!JTC%sX2bP>oB_$3$$b0E%4@6S5SANgJ6G6J*^W8_-{83p+NocsS6Rr`hrHoS z$Hpa?)OQHnpa(+gVO)!UlM)zGPs}&o^otbsG#cyPbC|qNpOoK(`*P-*SBj7#4?PjR{ z(rR(>FXK^5Qw&+rak^wlV_cn(xWf47oD{<+&3~zH`cn2C@74@ez^OQ(2CXB8@X(Li zQZa4!6lKh9{Fs#0-pZ062I$or)Rc71I)6qBL_X?e=56?5%f6_U?GeOkUVOX~ESlyt zTBvDY{}m{*9u8a}KXp99{zNC6Yi7ScXMAAQ{v&6%1ZH3r1lk_dXvm(blF{lo^p}=zTu{`c}v%#j5 z4;IM9A`4;vku=W7e?|6>HNb5%GdbPjYEHdLr*2N>MF>qTFll^E8l2a$(+0>HPetg+ zKe$U0zKrK;fHMkKhOTQn;O2Pv@#}my2%U+E*dZA0@>C_wPGRa5xfeexk~PF0;DUBUG;##^g8ArF`HlfJUC$HKe6vZCx4(Exl3q zlzyLX#DB1>`m3U%==->;@qJ*M{}!yH2>O3{0glm<0J2ms^PKPLJJY35`Vo2HNes)p zbxtTXv~k;2`2Q-Eg2nSVCw7 zPke8{NSq68zXhq)RH610tbt*sn+U5d{QRDn3_DP4eaqGo-0{SWVFX$5Z zh-K}F*teV%N1i56EbgPG;%h_FwhyIAK7|&8RXsNrjs+yvJL)kGPLt@vSZI{@o-FtB z<3l!LQ;4^JeJ~z-nK!E@zvl;aLlV7NED^?jAMvI?il4Qo*)L|9wdCz>|G$L^H!~#1 zz}I&k3q%Q7c<1G3KKZel4V4ZK3<4W{!Auy3{b0s-*mnni6m+yHu8`=1frzf*{#QBY zzjmEBJUG=K#a3rcn(F|yu84^v@v1AUf=|PWf*$aMzFdUz&LPhpDdEF4L?fVGk_ zRhzrwi;lF1eC=Wa$H4&KoMyiheETww0qyv2?)un;uYvDhI*24hArz>j(VVJN9fev5 z{5&g$u>$+ z!@}T1Z+kKcEd7EK^s-g4DI)X0mN@w@NnO%+gRiPb8U~ah#f=hhHF=yyUrbDtygjMWQg7ycoXgsps6%zn4Rphmw}!?_gNZ8JM4Ax!_6z0fv= zD`uGxUkE5?S~+z{&4_H{qkp){SRXwkgby|~=1NWU`5XOh8zV1#u#j^uxAqMw)9|fj zLcl_K%G%cL1F$Rlz4JzbcU&R@-8fTU(Fr}V7vrFgiq{14F&AM;yK>;;_>34{^`4hL z?(n59E!GA9m{E=3{vkolAy-Zb9?t%~@wP}4bRKe*Bhq{#>l53?r@+km*&Bv^kvHZu zeNsk8;1@vTe7*cfS!-^Nn!oyME~W0Qd`r<61!DsVWDPl$ zBWT3cZ<+;6`jUglRjM%S%N0Sr1SzX;Aw1di2E(eNbzb!l=Y%1UbTUd8VE4j}A%!`AR z7VZB`KtJPjq|Sekao=;WKeoTXS?G8AxNHCPBJhmL_q6x6(|=>4@!s?>+L|Z7%z5u8 zuazZH68`7XkMAEv(c!O6Bwfwq1=@{uEU$tmt<8Ry57OmfO)X8&=U~KF`xM~clu_Xf zsgwG-NLXvRr?GZ}>8q>TEpY0@)5pQi`3xQK zPnj*xgnHquk~?P@Q0bJb$@4YX84E2EvNzyzXcQGkJO*0^F(i`Dg<%vqN$$pU z4ojD~KqrKkiuPvx8y)&?P8k0fZ>k=nZw2>@62IF|)R;}2lf(<_G<7t(q|6Vn#kc<$ zk()}x&olcbOF>X`*-I6Z?6}``9jnt^kBLR2ucYPMLsW^NCxbepkYZelH46bP(xw?I z1tD;{_S3}m$lxeVr)HL zc&7JlAH|G!V7eAZhV`!P1jZI1Cu;RF(a2)BivN&1>}WDM@ca{)qO%~O*zc(eNwqnn z(TGmBr~zp>gmheNb60Ak<2cVh-GCVqy=Q?HT-Yb)BB zJ&t&n5K&w0t~2~mWk6P04Wu$F6{aa_IHysoJvBTD8vNiWHc_X!LM&O$DQ6O@a8`Yv zd`@0x0Q~7#9~Ok2f^?iYy)`?Ujyu+`6ED_D6wCCk7-ii z*i-BBhLX3b0}uI;IKKBbK}{*as4ZDB!JB0Ovm*+(?($3~9TZrDK|-{h*L@Q{p{E?}^nGIM@1Xj3 zI%A5962hBtF|s^mn9$YwRXFY9-zP4OiB}g(d8Qw3$(2{l`u(q~XbR0!oqjsq*vA#~;%D4BZva3amm(hu@e&nv6y?pbij(>`;UH}Dyn7s=iN(ESEQkr1gVmx-GR z#y@^rxS{y*o8L%A-M9xsVjg_hJFno2eA=2Y^=vaV;Ybx>@}8@J6qQ3J&Zrxz*ySsu zGo7vG;ecCGy`i2oUej|kNvSiKJ+q_zlQSxfJ(2eNnD$+vpz<88EE(uE<2bc;Z1}L7 zW4GI4f&)%U$K+aN#X&KChHT|$24gqrsb2XQFi_10XRc4ggS#AeG$e1iHZv80s>(A8 z3pIB-k<5~NftmTUQ)x2f=a2f+MoOOyu&$gHt(fRFd?ddwiEmWsL@dYRt9)Z9*xDoY z(oz5%w3kV!Dm!q5xgkDvZFuVJ>)Mkc_h^RiT>3?N97^RE>LqX>oP@oY`&O6wREImY zLt?k>rhFanL_g!^pOcM|(MfQwIv$R7w13*vUQ9N}TqQGbAF^wKDVEEW?7B{v8X!_~ zHk0+8DXUUOu3VRI=6!S;?kNGJi1wN7JERrT(fE@#x6?O;-bZdI~Um(yUz!?(>N`6-EQzL0hM=#ootyu*G zB*4xEEr7WfVE>o-4gm6C-OE?!%|HzT&_AFY0RBejs_X6bJODuA0iU-L?C(E*S0v*B zykocx8v!UvD;DT`2l+Mu%ePMf0($bSeI%0pv1OpvFaYmp5;LE)Vi>4OLRRp$OY&gPA3L|eyPLg zRNQIeyE6pYT?8~_&|4BL=&pVr4)A|I{am&GpH7P8qca0}0b;Q!>=xvTWp8_uh|0fi zjs$*F4~(mGg|I0o=?DT`#PfeIf@59<(*TN(#!f6q9BAI009<{4YRWUbhA)LgEq6}5WrQdePRFA%YWwfR>m6r8IJj%sRbBK z0vO|ef#d*~00UaS)d&O_dp~HM^U@xFgERdzy=XuRa8ZuE2mI?~fngR{0jvYSQY*sm ztU~@9S4iRM*S#Brue<(xSaAw~K2!Zbt$C`^?E(K@1*uH62Jjh{))~W?Z&urG@g&zR= zyI7202TR??Z&#bU7Op{QZdLC(QCF7Xm&Q9+A9K-9zHhJ(}0{rP!T-lEQE5r*2v2GAZqUxX8-Yg9LQi_B7oJw6yOrcXC-v=0rDCN-L* zBbvOK2)QU!RC$QN$#xW*{8kJ^v#Ke}4=PGbsJp9%8f#^+lW9`WfOqmUy-N}lno|Y} zNSG?6d@63Iu;&CX0SguAap?eV(JAe8=HdO-%8(g3>k#ff+zK5G;+<-pI&*vFtVoFF zq^A~c3V4)A$SgvEmybL;5e&t1Jij_Ez{*#q}B=h5AXpg(E)(`gS(a%P-&KIUO=3?y6dV*-- zl{6=9%2BzFdcP}f4VXLfr#o5ygSIvIjL-n)x~Taq%M|b2&TH8YihBzGDJ*$V;?lBb zLIe1W=XXYp#w{yeP^bZ9XoEOYm&GWqu2I?;H=2sDM*e#obfpD&r2;0J4MicWspQ4S zMH~>HcA1rR<~04LneK}MlD}n$qH&G9vt=QeKWLP`^v7rP>CHsj-#ZPEhBrIGkD2zT zpDpzV{PWU?H&x}WXKEajsWrG288$M*wK=IjOeLGlX$3rsSYl6B+P~*Dy@dbWi_G1d z5jZsw*Y56mF;M|D5$l(W(xd~J^?a>TE%q8qnxonE@A2=&U1l}OgLrDeR7OcBnV5V2_euPj z7vYk#hHN_43L4 zP2ruhYLl{j`_I1_Gn%%KAWDpo{^@ewy61RetnqH*%pjV2rv;?xyX)*Vi5R*ZjxTQS z-`v2mhI~KsAtMoDR^#d{zhpK1Ff`SuduL^D^|v^BXv^1YQk$TduRAbb95=JC@z1) zf~5CbhExOk%TD#Vzrf6q)R*J09x^Gfk0XP_DU2cVS9zlL&!j?t%Ow!^^ z%CfvICH@!*ifEl###~XITn8*Z57;rgI#rtxrZ}QbhDlxj{3-QiCQ!KC>Fvjv2Rw4p zP$fthE)V&W-yP*z6uJ;wkLJxrt*wgfk*tQ16l4wiMB}4up743mwi;^qMJll9bAQ(G z7wCIKeIwildmrykUi=^dmJgZL|z=&Y6`X1H~|w)(^7@8j+@ay?=JuBIa~bqqUy@UWA)5=bN1SuEubF z(&>w)qq|=P!rRdTfk1S)9Um|?YmXL9dwfh@(NZvH+iX%(iQy;69lM%)5Kb(0$`oqR z`|m+#&Tlojzwiq`S*ab>DxBsoHuq zcVw=EaXWsI?{d(xUYVgJBz;r-lzLV*CQo!*jEy!|s)!CEx2AP495z$Dhh%CV{(`u~#A!ON$INl3eOp%)-Zi0CCcr z@_&J5VgR9gf2}}w2SeMjdCS9W`|yEf-V&RaVbzdz!b+OiK%W%**fT72;|J`_dPaH$ z8Wq2i^&WmJ;`g8W7@v>U1Rj6jrMZ7r#asmMI73xgTeF-&inl% zj-dL65Q3Ne(yy7fItl5K?9B-mSgZ8u`h@{49tK+LE2GfJ)dfQ#{tl_)*wZPjKdX_6 z;5g@Xs|ET)I7;0PcW@2*hLpq{+kL!IYy-I_OIlg)m#P4)!68Q3 z*yb7`IKKV3OIt%a}Z@^zYaFI`4jwh*)+>&*U)dVFervpJ5Dt zc`XV}^JIC`q4e;HHpR%_nm9EuS0=6P>6JM|}dXC~o^ep3C04-?O;lYR-LSGjhSBnFNfYtxM2aYRusr7wX}-*e`9Nt%Sag zL;wqYjeGwGVS8Xcio{q(7S*mfJZ=2=ftifMK(FSXgPzL#+IzJA-U$T{%>T|Wd>USsdK%QS7ni^jgOPO? z9SMDzGQ@_ws3h2-tLtYPdK>6D<;}#+MAUF|Q>}3%2Y?HI#tyq)+2h++B6G_#^z*FH zPQmAMn`c_L@j2s>qOtk3XYoS)U0Cn3Tt`=dx#CBtQ0+CcK6xY_jn!!nqN$J~C7{y6 ztT%U_{hN>3^$Mckz2_}^r}Chi=(E=_TV1o^gN3!qryO3d2}L^9Dlby*=Hw<}-<>B| z(*48)iWz|5rJ=Sn$Z(O5u!LNW!MaA&gJ6+NDqI+Yqa@gas~pTiE0R?*#2zq;cd8(> zuBQl?$X9wloM`hB^+_8N%*Y(vR*8@^wGc;!}7-Wxd6ZxYT;egYHaFdw;m4~VjHxt$U z4DB_E&=SNsdQsuUI#;R86&-aT&+uAgg*&lTl1@)ez%BRyfa$ zdPxS7f79+5*mr)%)fo=><<1M- zX`UvGF-l?ei0*lE$Gr5u=}<}++ig4sGKxSQC#i;zd7{3cd&bh}51v}~{$04HU4uk) zHp%dcN>GcNI0`X(JHVGAkz{}r3e{1BChy4OMVnEXp^V2g8t0m&Gf8d!1!}twjYj6( zTCQ%P`(p&W`UnS=7x5sdxRdgem76dN@t+dWE~Uo2uC=Tp2W}=M zrD{xSXpH5G?%Nlv2YLyOjP8+-vL%Lif=^x%XNDBu%q8Bp*7b0dDLE54mjoBbfDU9x zs*FeOjeKe>V^y0RIV^#m96-_E&PG63rh2pC#v-$AsrKQl0Or3dLFHqScFa9*r=B^F zL9qO^VV6LOh038WaCxbcY&<*W0ge0mP?#a@k^OYGOhAT@yDHw+-dra2C;=y6eug7B z#78sXOZ}4q)k*!sM&X7H*4|<{_soy}T!x~5t`2De<{GR~wn>{EZ~ZC_!wnQ4J8a|k zUZy^LU3P^sOzo?L$oIr~%gWa6ndYM-|6NDPhTT%QVz~=3g-9SZgYheOVmD2>{t78Y znp}wImA?@py=y2ijo9~(mpOZ>6I(CW^= z!h``*c%Y;dgXD!@CId;Tnmva@E_c~cz^*ClZv7OwptB)?jk zA(sz;&bJLG^=j=UAmnXHcqAN%rwF1zO>%l)m&ZK&#x?|v%ZUU`$1~vj3 zTK^t65W|XtZaVRbSbANGc+p7Xx{xlnEb3?91Hl6zp~ooprcbS}HD!Jq1#2$tYE?kX zDEtxh%tXcM?3~AmgIy>0w-x=TtDR|kjv{eY(qN5zUk3>3vXptwEN}Zu?HRts)l(9u zISqQ17H|4A+evekB~M=c-Y=epe}$Vg4C?%S1K{C+GDGBJN5|$pNxlpA6~~LC7O|;h zJW_@-{U73WWlxp_0YI1~#Bs3#NA;|LK{FM|d*>2~h?ziN!~+oVjVw25$jXe`C8ml5T0SPyg_%O_;&#S$S}W@4VZ{O_u1fW)1}Bkh2-$_s*yH&*+9hI>mq zjQ=L6Q%@o=w=q=xYfhU64>KBI$fxB)xil8M`jloSAAwbRN1+k2T=`2R?Sey+@Gn}4 zq2xZHGR;#3mN_3{P$DD3#OezV;)4UIAO=coLcq=?UzB=QZb>G}II>ZAF8Y{-6j8Eo zpNTV`NS+`d=tCVhQ+G>+UNAg>p;{Ms4YxIZ#uP*lt%nW|3k2jY3JUb>ExNL zGYJhJgA|kL+D0NFnVBnn;0T-m4u1W4x3Sz-Vy?$r;n2RcS}wDHl1_L~m&S zdF_H6m1b^b&BF-28oI&pU61c}+5DAWZ==&xbbA_&r@ZLTDyWQYlnq@v1!{%wcq-7H z5w4$YlQ&m&#LGrowkn|GH5j;RI`;Se*jFN&pK*CokmK6fw?~Ri?Q6LxsGrT5%v{V~ z1B}?kRaytMa$ASjKRK-xB@#YblzC0q0Okxks0ZDktYpEE-=J@8I7XR+jYc}kDg+5lPuu4PJ3r7*G z2P%r;{QrC*pJN=W6uH{a=PMMhUU38QW8Z!vQEga)wu{fR=0oL94==wks^djk{A?a? z5uCM+F64gW?|;S!_}hBOag5rckugUN(H^>7P_Hdau}tM{)UBuS?2h@^af(u;Il3eDf*Pn1n5JagC3yM1O2|UrEPPz$4>dpiK>xlfj-UZj(5# za=UgB`G#*L#UfqKORm zP*LH5pT^y_OcVB8BUCZSFO(uZ$U&Q?rP8~3sF6DaH#X2U@qVAHk~#4C3IhV;UR?0>@`e2=mFY>9|om+Z3l8gw1`) z#EYF*EWcTFmOiK5$0h$5LhE-1CXoAxP$rX>GVF$yUu^QTn4|QQlnY?BxG2cdebwn@>#9bc6B3FYI0bK=&zqv$Qjp zaq(tSlTK{0W{Lu1WKKaJUTr*@iX7a}KmRWK*C3BQ&f1U&sPml3a-&SWdesGR>3I)VU}4=4mY2#SYs% zgK5U-myLDwHS=m~T(o1}F_OMx(j+uL-?P&{{iDg$PpRrrvs|PddMRtN-?9bU|rM z;@pr9I^3ac(SXqdzM8NS$L28BGE_XEZZcVp*ppGhZ6d!eIoNrMg=JRrsH$AgbtoUd z(tUv%vf@%$YOc439wDx~yRVmZzchC=CaSv1SgFkV;M=uzqM+ULH351q_AeYdCO9Du z%}Gs1EY==*S$#s}Qg&^_^!>U&tn5i&Z0H)cZqIn^DGo|8Q;v5uq62kbth7@}hEnmx zJr3QKQ|R?04DTRyN_KKL^No7pVogox`%wOf9~zkeI+q+dWiDQErTm2olGbg1O4jBd z_r+x2EO_Jj!L48IAxEEX?}SdlWGd6VsdJG!}v~t4W&3UUicvrhra#CsFn4$IQ_TEa6_(5~Jn0sF)bI{z?@X$WF--XWWW($T} zNt*~hagDZ2fyHiKRg8z$j!`hbuZ8~c!z63|49YxpNyawfU^_#+q+KPcfSC*j3lbTP z&*t1(*6jK3D2~`$9=XY8R6@(YA))*~-@3nct+AuYDXp1EU#{&?92yizzkg|Q50i9j zw7M~6{?{dTaGTX=F@%C~#r^~-he5-<3*Z+(L2%A{(U`HZ+AgTPsV{-+xNEoW-1>_V3I}<^^JyvR1f{YUsSt~au_$F_; zL3v;OFpm5-P$PWKk;AX(bNJUUTwpbyBWcGZk1j?v(6qS3nBUbB4{{W92BEoyOlIgL zAN_P>no8~WSJ>nhG2Q~zfso~rSbO``{+}cV5F-uyH?P;y9|XqQx~&V+E%dl|$>8Lh zPo2Ncxxq(!RMVHujd^!E({bx=Ho{Gj869k2J9}hpkXjNHJ)DH+$TFlW%f!BYTT7xc z{(YMyxGf%ghsxAB;gommqLM;nOYR2iggXb#=>kMavr(;`s(InY2q@TkbYK!Z|$F^>ZnvE<(yNo9Tq^euG!sZzK-y)wLnw^4P7Oz^F$ z7rJ=9+dzGIGpInvf_;(iw0?o^wjZxH{>ugJg`P6yR2oD0uZX2|*2_!%1!CkLF8Uh% zOmUj=PZbtYiKG9!BRj~x81qW97Vx<4u$4#-LQ+HHY4MNlUDLx`#WnAy~3jsdjL7_VxrC@96qU$;$%^xYx24hucryiDaa;wt(eiLUxF zU~JEPU-Td!KTu=KWC7!`igl=$ZPG%goK{>@=l5J2aUJ{ogw5u0i=)~3L>UL4Nf<-p zf^EcaN#;7V*mAzm4Q9D0mmOo}33bGxZvTUvx}Z zm?wBFa`>B1`jp{XrDrsPL91P*I~pUnsY!8&M0%MH6ZgqUu`$A@vw@A&)G`#)&~^ouAB~VEc}>zaU|N_U{nz5yPtIM2hra7Z&kZIc3>hCNzp&89Xc;#jcZRNf zYcYT|Ja;)_1&*zc%mVByE}nEq%YOPIF=(77T6!R`H{^JttjIA$OAy$SFlDmQR12Vd z&b}G1zN5FIkPX=hCQHw&dVK zF30mQ=3v2TZ#m03%f{m-aPBxs{q_8cMM6@%jndS_R+sX>jSDW6Fn|msna|p*zzbyR ziBh9@6(XS%;P9DmBA|Ulg3)Z&h9B@n0ZEx*hEYc9}Tx6wPoaT3IbMckpQ+Xj`JB z&jBZFE|05(SXcwJJ2rY=-AS=0HkX@nfFKyAP-2?Aq3pH$Ka9O~P#j;k?>%^M2(ANx zpuvLcKoS^ya0s42AVBcoGDs2<+}+&?3GPmS5Zrap;6tzh27YhnoadbLoO`Qoy?;>D zRQ2xOy?d|SyVv@z&zd~d)gjL`1?mNGTGgHYih8@}xRFH#+0ZVFe~E`~9Yt&BXu3f+ zm#F$Lt9!c^kBVBCQGUjf6CUyppTTavz&|PMg+|`v)xSc8J!?g-Ho6wAlCHj3;|=cn z>??T5hUOjX(bOwO)-x^63besT-`&H?bPTWJk`~hyB`ykUl;ive$`7_iV(k$T zX_p;T1(BVArUseHD|HTk*e4tjo+#sgg;AZ8eysZqaPwtTwA&(yRe$3%F_gK<0RapW zK+Onku?_(1;Fj}P)4Vvq2-<9nnzI_*8>@uoIW^7 z=pr4o_On(x#L3=_GL<4rFCb zO!!+OQ!X`|L@SI=Z372?b|ER#~Je_0t6gJsWG+lkz zMz|gp{}_{y(3O!39(BVdx7~85Qj@abZ(5)#A!We?1rmATW$m;FKW~^-PBZ#)7UftY zl!DKkOCpCtd)0dZNdqld$Kj_NoIZYk-(;lBiPN2ZvN>+~0{CRS_n>xI>9X7m?S1ya zS75N>_Gj^R)}Y@+y0eJ8Su(rnPWt+{xNu>$Y;Fu}sFkCr7*E@R4t-`qNL%(>%y*2F z8~HRs(Zw-!{Ris!UD!71?&%Rn+M8v?8HL>g?()Pf2_T+}5(VnM6|_>pC&*KcqjCM; z1wMsFo6nB7cz7b?Ve(w_q?$mAbGKKeslyeI+}P`)M||VMP|kbI&Kt5)f8EL~uRa>_ z+#FtMR=jT{IXM;st!Bm|NP%7l4H9b1%RSZMk>zY_=ef6+kJ<)0bnzk8ukEd}*NEUf zE$D@|_W9E2s6}q7iEtpdMB1?Yx0_6hx_F~KR?@m}j&WY`yfGo67xjdbP#LGQIqz!& zi$}CmwAw$YF6K?8iz@uG4IY(ef1%C~@#}xumd^!s^DcMK@8{+D!LE&d-fr!^rj^ad zvB)d_CIZ8ncYZUy3mLUCoih3C*BD99Ag6?6)#J~q<;4?11>Wvi(QeJA%o0~MPiOe6 z`7iLzcf*Jbov&OM+X)8LM?AzW?HR`L4=_eaM-CVvbjdBeXnTvo}xwxk1d6 z{3?6p+I=ssa4G{O5Xth4F>>*H?H;Fx`-~j3x9Y+>w%HoQOPiEb@_}bu_fLFtw!<^@ zP$h3{{Vy*)iM{BViY>$~Iq$Mbpq*6XW)yGM@%^KTjP2&3@1Wf^I5qKIh`e-z3JZ#I z%^?ftrr!xJDle`a2#**BeHp?+eX$yp3&AoP`=oy!wYghNY>n5qX30G>Qd)rC|H)QB zS5%<1g{wRLK%7>KCu}P(fwZ3SD9--3GyV#;EMQ^dAULk`X_X7P_mg2GWr%A<(NfKI zxcRwcOKN&eNWB?Y&FtCMQr#0h42Jjxr_9&&PXcKj3_UAECYOxA6MZgZ|9Z3TY93c! z^$q38+nQ_4`&g~202NLYe7(`u1Np+tVy0}`c3Q{q&9Ut(jdQNV*k-z5(_t@z$}J%$ z_3_$ztg2wd^x&MoXqmUCNAwMA?fq75X2BilxoDPygY3~y&)Er?@5(Nvq3r2b5Q@d_ zYVW6eA;-9DM}qN^*!+llaFjcQpsqA|_(b0W*C63XWDY_LL*gbL!ZZ2FbCtlOTp*Bt z_V@=I1WtGRR1xMvJ+hHMTVQGFA%X0y2tzkBj0yE61ggruGqG;^kdXIm$3q zjBL=oH<}c0{`g!O(dii!q`=9%S?}!6AKAarI=^)CxT5SPOm)v+t*R!py2hC;T(YKK zlB};Vljjl7b|)iJ)_2Z{SE%nf-4j{L3|G^RmOy;71X_NR?_)A*2tvlm4RurcZzPw#)>PKU(=0QqW6}I7u;HnY*}vJ*BBs$P7QNh z?^-x+xzz`32kx$q)@a8p?6>b(RQSJarg|_?lbebV@*m}**PhzqMF$zs%Jfn^d4c?% z_=eX^v>rXk#p}*w@d3^1o(I&sr_sP#F$=-%QP!>tj)#_s?i%lg)LW3w6OIft3ek|? z9}P)LUS8H1Pt@~PbmBfQ9b<7QZm=Uf!g?Y+@4DCqH$3&Mt$rDycKaco41r|R-?D9D zz8Fn{G3Zk17#i%DuJMWRPO3s4NB?( z%U{9SyloTj7<%tX!lk91rS>e()E&Cxb%cj*PS2?Z6+BL<`4pWB>$6|1BnN$X04=4*Rip4sMBL-D9{Y5S<0#+R6r_kwa9s9tQZ2vmBJ-hB0a)}&Pp2dI z7e{LY>4+*tS!i7&lEt`6TEvO) z#$%z=a~}?jH3q}{6?}>Sw0dPjVxGip@ArTQ-DrpQiF(QRj<4smA|B_tDBu4%XFH{% z`hMCfAALLpJ9Yd_Oj%m13Dn&XW`GL;Zk)+p*uGDUz&~*G3bQ-3P zX#B4pK6xuUG$=Q7{;R~p7I}c!BXjJ}#N@*G2b3J2{o&3i84~5c_VD#Cy-@cAYG2yF zbN%QlLp!={EN>e^C!=v!v7tC|v^Cn06^oJ)89WJmj&+cJ<~)%6(z>b1XWQ+Ma{o%| zpT5j^JKm+P_012xJ^y-zZ}Z!FQm%6sEJiIGzIv2N5dHkm)Hj%_-7`DEM~aKW2Rd9k zDRu+gxj-#+1@kkcNiXEpMDbiT1;y(9F;Vmj`9E-KFzR;=Bl1_6_-C}@o1*7&yF+2G z&<`YmAd=`gO-%g{f4X&p@IkVlrx9u*7VDdI;Nw!xgYfG>_P$^FB`FiAa@ha~uw%m> z{asiiK7KkDZq5OS$s_vD*acdK2gQ)AdO7eP*{bn=`C(CoQqyvA~%Qx^6wwTl$G8 z$&uump4;rW(zj|pHjmCAzM)%gg6>9_Vp8oZkuBn%pM1F7d?fwRaw+WH72ax#nydw^ zGs=ANn3L!!?jd-%dagp3RH<%LM@5_|B3dIP^UWcH;UNIp9(x?2bcz>Jj}S|7mfcPa z+j*hmC6I@ecU8T5D_=h+H&)JI6LPH^Bj^ZGqMDc%H}t&J61ma^oT5+7=0UulinSHy zj6OF~w+5Ez%e06rCL}m|jQ7N-hbq;jXm`Y!{CI|9!i7|MD;2$;Gjw0>TuT}Wv}rkE z_P)AxjLs>Jf1-u{<^41VSxrUHaU?xkoBGs{mCzs58TsZQ@{f=J_ly^($CF2ah;(uKx8#q@I3p`BakR zyP1wZ3E!K~@z4SgKx#V{UGonp&Hg@K6deq+OPQR4<~r z==yz{h;j&n60)$5&u5m)rV|@kVzwPi@+umnGg(xcNI~UA z7%kT6sN1SnJ+oK6j|5{1VQ|IKTQg}BcNP7_q_p46Sf~^)1l29hGM`sb@-iD9DY>kw zZKNOb-Js-!QHKCZX#MQ*^qZhfIn(4xAW}Z40Iu?%+4a+NlT5&(t#ns`ebXF1ETUoMb*<-5OD+Fse*96hxGiFhYt zRc*XxcWT;CY0yJWLr|`=JQyjo83zrL@evOdD0=u}jy_;O=650@F*>sOGYltpBp>zq|q~+(5Oi53xLyD|(_1y=iQSZT$V<&f&{x&VWLIEq@N;N6|-X z9P74}?RQ=eqyu1bD+fPZ(}m2U@18m0QS4TSj>ZsrX)QHNr`l+Lu{B(SD&)kFXR@GS7PcpkyJE%e@IKh#R z65Ymqv+dYH@hs<}T1w&tX)rbrh1V|)@qG!tBj%lL3m_O<=d)wTt+z!R?tq8e64n&} zZ`5}{xljXy0}39t!w2!0vFBh#iJdq2HBn;>FQ<)9NXPez(842ags1khoUjPhxq@V6 zRt(nWNT)aE!@W&RpV1X9DI0U4R$;#TZp!nwUmQ8$`hZ70UFP)n+p|wn^f&5;MC-0p zW`^F4?b$iu@Zj(&_DWxHOb5rZce%jf0d4k_+DbA}pwH*MRz?h<@ZQv~tcGe0VhJXN zQl@lU5Q(t)00ll2UqvUsGA^@l>-bkmm-*9nq*Kk~LzP|QpO~g52~q3sSuWW!!R`m< zD|V+bJv3xt={q|!r^9MaeKGxRyt`NfWF$EJyrF_WzNTK^s(vZ+GJ`+OGtf4Genl&z zVsgDBdIgH?qTEGlcp#~-7lW{}cOgYSAg14-iNzKqErAie+(6Wk-#)j-&`N}gLh+m( z%iv`BGJoJJ17bG*bwwefk5?Sh;j#LPRt%?0RWd7kgTf`XQC1O*l3WKG zX7Jp*3lk^nhFG!XO}BFZa>;gDlaGE=u!K73Qol4xR{G*}n9=;snzZj>XH30+@2Fo% zw*W;ziDnb>sQ3PIPS|AYA~Gj6kjNcK?7jrPi`7LoX{~;v->(77IL1A3#ze|O0F1~| zKU(3(K2KH8JImg7UxEG@AgvIxvB&=^#xc7fZLyh$ zn^=73#qT$dhYx#b&M0K}wL0pbi3>@d=-ySrJzMafyiTFAII_B}W9YoJ!;qvh-%;nE zn4Y|=s2S19Pb(U;2PH3v@o!F_SFlXUZ$?ie!Yw6;rfStG*EP8?x;Cp|4F2_|dZ#%F zMJ(J_tMOT*EOa8rn6DE_xIj}uMJ^ zf0t_ef2H&+!?JCs#!xnWPqmkW>#rGS)s_TbJ_xm?541XyDWKn!9i zWh?~Ht789&UUl6>y7nVVo|zeLPTXxPnO5)C0p)EcN9`OpxU6sxeKhQ(>zvzG=j?y0 zz2RqUxr}txRGu%j3NWEq+2a&KwHk$fhN8d)7{?4H>2%Ma$~t@RvF?Z+pyqF;^B=sy)`?D{v@W0&6~q(0zy;y(NeEPN z8C#0QPF+qZOKijv7mARdXzCA9g0>>b6BNF{Bt-@6)wN>DX+KF#`mix+s4H?(9%7rz z-=CHr5>a4f^IYQc&`r7dg@b5z=$MEhx#dU|G$*oxcND}Wqx-q|stDjTD|7X;6k?U~ zvoVy)@>KpZ>)~U0`~lzed%&9N_w63YhiT;wSLjuCT;lQpZxBeUV!Kp(smk}HyN0l01QITg_(Tv_?e(3w)h;}jF_3ez z={w^)K_ffE6pa+G391KY(oC`&CTL-l2X2zh!CjsNAjUR`jmd`f<^qXLb1~P1%X838 zQZn(+7kkyg5F6OaQrTf>=k!G-xw+WOPg(Su9v+z&DHVHvL^7)n8|b!b?3I6!OzB43 z<0n>N@{U`RinNze9)rS---0HfK!l&0TjMe7XJsma`x^^;j(1E2?P~Nst^fe%x&H^C zjsdIe-re3?I-1x-AMO(!uUuVBjN3ATOHoTbcYZ^*(tM8LJ1%*3Za-Z=E$?DB+g_=| zZ00%34)xUTg{Pz&&!^$q$2jldv~8kH+gXhfBI`_a`uwWzts!o(EeKUL(fb-5lzT;Y z#U710&2&%_k>hp+oYD3~0FfC}Q}4YHCPrN;OrU18_jnb8gj7Ybp71Mqvldp>P9L&L1bjtSj>?8hL% z$F-x6EB)zAkYz3!Z?R-P*IsFG#?f5aYcy3*8wl@jQ%<{Gkh}APS@e{_|-1HKcK@997!Nc)X%Vd zpg|4`DS-#JnR5IFd(H-r5JHdo*H@U0Rje(qEq5Gz*|KB2O~@JU5a)&o|17rxq^-*L zIiETzf0rFA$bZySvRl~64IW~E+2>GQdP(*!hHG*0{dwe-2>VB<-^V}i(JRsJ0ro|bcd1~9^`4Z9UxaZh^^PSvW4B|EUA*gjx zqluD5j2*!#;dbh2^;7Z*aove`-6%JJ@gk5$pibablh0QL?3^voJmK?E=|#w&+4)e$ ze?V)zg8-E&BK!3l7)hxPYF|!&Zw8&RW2Y+a<;RwM+R%8{xS_HY)o7w{o9a3qJPj17 z+za1*n;%YTrIcy++`5u@W%)bR-4@G(YIZFt(9G`^y@Zis`744KMLuJ?C+2=dqt3W_ zlqo75k7dG7oINU}c@;B%fL(@pvW?sQDdRPD;s(DM+H+GMKT8cCBF&(?9f`b8%KZMg zh4%dtwV~6kSn!ET{=vll&(muqNpdgp%n+W{veLn#g}Z#kC*n9DFVWR~4h)vQJA6g7Kvzo*-Pyi=< z{$!smTAbFhd5GO}Xpnhk(Er(t)r^cj*T+!BcOjtOJeGL44isTnKlUX(y2$DBQjjmw zN$?l={RclrA~?hsaZrE}(kG){n_9sw`_K$OGezJD3_g<^e$Z28_axh>`J*M2E$Aqy z`Eps&y9H%o?5GYzhZg2A-Ijcw*ZCdq#rR&FP(-3g4nq`7tSzBh3fSPEhL4NU2JyTi zFmJPl86dC&PoM6ce0E5Tg9av`<0m}At~>|mj}(#V~RJAe?>R1y}X%#CMJZX-e1XN_q?DtWZrts8ok5?q#e4Bm_XZLkXlI-bD{WX{? z4s$ID77m69KEf|1mih%ob{Z6(lnV-i4x%r@PL1IG(6@dJ@{rTZO2lUCwTv!qz5Bx- zUn|%>hnMvALZr^d{IB};0I>1cmlKvIvDfqcbn5uxy8w4LQx3CD=(Ku0(Z{2{vaRjL z!O~5WT2{B`%ViDdWj`IApKT=AKMs8`c!CzMwDUZXJ^JwVMI~9Q6`fq>8OmVpqraCs zV#Lb!aZ^j(@=L?O*=N4%>!(M$sG7lAfQ(8_Zg)g*9rBz_En&cWK=#hwCDq@Ff=-l{ z6My*Xu>R}}Ut*ZId5_S;y&NUV|2{3mOzj;#HLZk;q`CM0gBpHj&eOd1TkxXO{iKO= z(iZ>Wo!E>svGkBditW&=}CrV{1cqlZh~?r5^{GHzYcOw#UpCa z8jqgre_c{?i)H;WRwg^@esTO}+I}+6eu!K4UA!7{|BYD2IPdg5*xcA*m8ltdSwiF` z)cYe`yGh1+x8yrq$o!@8D*Y_Ov$-SZU^(N41^MH!(0hm$w~e>qm)@qq4dWU;vJ_rf zeKg&=@^ZnR6rho&k_NuD0U7%}CZKXRj{&N00|X?W&Vd@zC-hM@pR4p}1rnjc0x&_+ z#Csmd>EfU8GeJ68QyXT{&G7h6jrRct+rRQ78o2@S!vAp+K!xs&cOUEvxtG2d{c~N| z?+L&M^nt`W9t+?y?63xl;Q-(x^MO|oQ0o`4kIl|aRT_LnP-N*89I_=&8~~ApP$a zXBMZ0fd38J1wSX6gopyIuR|Sa3+{~nSFZq-5YQ{&od40Q7}N`YVDAcC4`^MJGWt|# zCI+GQe>5otnvnhHji9~IKo>qd|IcfjuASDTg4S(PMBx86V$2J0?(-}3BWA3>k1Fmz z9~Bt+*_#v?W$52gKBJaDQ04l+ZpDNcuX|B{!+d_x&hv_V_g$$T)sOD(u{_bOPFfig zlE#YO!g*8nSx*a*7=}0Iy2ldIP$1?x`rtr4=ETy_9E-*1oob(c`7V21C#*k#r)}b! z0W%Ii_k3Z00A1`dk&bJ)D`m!8d6uGnTFgZ4R}Z{PbFgoxme+xYP4adM6=U&z^5_rq zhJ5AxZNy9ll1?;BWgydZ>oB>}L3cq8-y5K<>D{w7!&X;zc>SZ}LeIecVfWG}rsDn1 z09sjLV}TD5Fl!uW8G-ld9s1}x@;_;7Mt^B*Li53tA)P z+_o)!$;n%V1js_nRP17|I~}T`Qdyi6EcsNV88}Js^EWUrWKM-NIv2lL-OY^ssq{O7 zY0ZE=E)K8ozQzq<{gxuA#Pun$swZ(zKHPIptb6wvI;IMZA#Cz2Yta$>(XaT0&0Kd+ zb5A=&zg*oFpd6dJsw`$@a|fkTHWe}f2@hnG+$G^Ye|MLYR;)=~>mH>&-}x1C1OKRI z61i|=fTHf~dZ;hTP7_qAgC3FHj-Mu}M{en%3P5F)pdYDHq01g+V$t<_U=Al={jXg? zcEy-FuM;E3pK>+f3MoocT7`q`N>_rYSP#NWgyTJLbTR$ZZd+B-j`%qmUke&@@+hDG zsCeo?Uw0~^v!4>f5cyQ*P=Wb_O&QOjg|F$XQ>IC)@yCJB^Wb(E!TjxXXpy9*eV12C z>nD-HH7tw)9JSdvq;9ryAyzQaQ|WO$QA%4YM_JP6y4Kn*1gajKBB0f}MK4|Dw;1_h z(vM(qi`PHaA?Tz90Hvc)aSf@|B{wS4*3$iA)uTiy*H8Q4E{flR5nL+=#!VhJ%E5cJaf^T31hP{GmYnOtR2;~m+(CK5%Esw7T#rX{B*cA#<+3NDI^`^?Jus4*jrr;cSZ4fiT8Q)q$a4x8?f*8 zG;+*Y|A4&Q(~kc5D&zfxPys0lLDOptXwh#QbA6ttryP98E|AXw1CUS9b>88+rR(!{ z)y4anhB4fw-${A`6I@N-(BmoZsLi9GU2zhLn>yB{juCj z_84v@C=KOryRkwS#aN$1?SbrGujM4ZGcC!h`jKOmmDA>95$|7jUE! zxGE`%B*=>Z!sLMzx_&_lRZ`p_o-w*;v);U&N;W4gg_{Ykhy2o;;Z+PiwnX0f>t>rJ zRk-;N^XQhjgq0xSLF|RU-NR$XVrCOfq05sXfYv0ud`>x{cfcD+MIn@I34K0Ujqw$m z2?xXq>{heVUmd99F!@eo>OABYmM0mNepGNXx%D~$Q!)i2cmVs-TkJO(Pmol;KR~nB zeIOt4fi4^(t+AB6ue2Kxte% zFE4t7N|{koT?>vqQspt^57`Hh-QbtmT*!;TPofLw2chjWyPvctjmB19-TQ_bDZS}F zF#niu3O&W@vF-gXD0P`am!cjQBituGGe=3^K7oI z(r5Y4p(*#)gnfqLPe6SZmGADNqsTL?%+rf)Rc${mF~~@8u8mt0cCMB~cF>S+R&z77 zhEp3GF_U_Wkzl^G*{-_OD@Rv{>`1w7KgF>m>VS37twZOTzo4y&@iqW?H_w>6s8jDWrY7?&2j<|UWWawDksa5{L`eWSQq zJoCGf$jKvM=>({Mxoeud}oH?%ib9k12@11dCRlewo{z0Jri8+9=DHZf?Ma&$U!^q+UK z`SWOT^9lO$P)>JDlV_lD{m4PSUM=H5i-jGF-HDd_Tw>46!Z`0&*;&P9NB*{7DpQ$5 z;iNxd&4HMjkE4AB)}JWek89^lt|u?)i{s$=s|*^?R`ODbf?R-zHWXX;6G!CEUXR_- z`;NTf$!66QN&-{&@MU>H`(|8j_xYJ%^(1lD3(61DA;RfexIEu9zFJ03-W9?oHns z^Q<7=>Rv={UjY()QIjL+#JMPC*ofvkm9L*(d(q;2?)N>_>-|ev$olgOtl6fR&)E3u<3wZMe=x+=&__6^@t2;jGG`f%phrrZQ=}w0K(7pgxSI|% zyF^}hWDl_UjQVzV!-zB54K^*BV9SeGlyppQUJaosfgS10cC5nVnV$woR-Yo5&%jj6 z#JHZDZjp`332vic)Di{j0$c%<0Lw2bEex20Wd$!bhiaxng0gvp3^;Q zH?6_^YNV{a-+18{C+V)brS$ZhwW|T8tI~3$SCRgp@iB`jfhmDRAv=cr1E_DAG{v7P zBTo>sy#%E&AT9){P@0=sddb?&7cC3VCbUz79syFx-N^*(ixNu;<~owP652u;ZA)qA zkN0#IWT*~&ju?-uPyCO6tj7i_qG1quhf-7+;2U!Aj#`iU?))Y-fr$`Kjz*z*oqMSZ zx*&wc_X^*2ra`e-)54^&frMvPbE3Q0$?WkeGVu=EcCdq{>y5ylvh(*fH@}_cp6K~~ zQKU31mDfpT2dS{UzbwoT5`9msDa(IdoG7I9tW#hb{?Y6dx81q?e%%oB;06 zfs~O?9}L=?CsN3hu`VvzzuMDk+7&@9Th*w75?$41)9Ku2v*Px-moY;yGI@|sevt@!U=Am{Vny4L1^p|YiwsmH3ysat4+}D zI_BWsiG@I4YT7Va7a-Gs^xhMqDa7(Srhfa-^ydJU>x8O0To0J_^?aqyOb^?HqzjclHKkT$%6Rnh0N{sm`j98zSFusm`K%yw& zQOu9g52+F)J5|XB5cdEx>J-TH3HiQvr|x|K~pxQkCID^BKj5*#t5 zr*b$i3G3z2zcC8E3XmmM(cJQRpr7GF)kyP?;N7As_B0Ls) z>&$AuDFe-&*e}1kWdOF*i0 z$6P$DY&(_Wodn5T98Qr$&yAFNL3;08=JVoo7$t@dLaYNZKJ(ec->1-pPWhr7Ikc@Z zrg@Ix<;cGnb|e%!n{`>*uEE05k0al&cv%{Bq9Lvww;CkYCceQ95Gd7{3}oUcQZ71X8J;Sr=uxW8 zk9GQ%4^Kl6G_nPrvh7Rhk*Tv`%d+rI1&u!A&%Y?55dwBx2t}i)K;z;@ZQq&HHu9=3yjh3)f=KGG&^?fl4|kWJ9n}iiqSKWxd*Q!A5)#qpdfd zTEucM($%8DX)o{gRI&(*sT5Q~fcGd9haQycRbvC}tJSOK!koaxPJG|sC-vYw;B8a! z_igiHW_R49RaR&1?oC~A*DrCB{eaIu&D#ZXYbk$q0`Ky({9D>~P6i;vbjzkdG@NFdImz|PErp&kzzP9ps}KHAkn z=`|;FNbKgL$cZ%(5ga?RzT2?py4=G%nIr84+4b1gAqu(p3`Lls>D)o|u%5)5DR({0 z$xD$$587N%EN%c#@f2^4YP?t1qSVx;)@MBT*}@0@!PBAw3*9HWR!pU%pcj0DRhY}n z7owO!Eb6_FP4+zlq#10*kNFq^qI6{&I|Q9#+M7;lVZQ-w+jRra zWQ>v&W^5@qAUtZ1dj0FhnZj;Ur73##_7^VQo7hJcq&o1Fz*Nb~L+#M?@YvnZ@Pjk7 zRES*sY#{yb#gEms@XH6$^#M+B@4`fthPy4iVk0--iwn_>Yz$;wHqWU#wNoVDqr0Q2 z_dQrwfrY2n*)tQ~!W%$3?SsRM7yw}oW5nYWej)qiws-zMpkflyIEltWv>O`Ln@!qN z)c3tg!A@ZxWR|4_?^;kCxnAq>yegNo(;Ox(aZXCAlX9e6sLsed=_e&)Qy~qj{A^^2 zQG(y~OHS_wV{Ai~_ZNB!hizP*v$JKm9No9K1!6wcd0`A~4UQRrc1=-dJ>!A<(#=c_YCReQ}WTRq^yWqC=1KvZ|4H>D{m-b9dMobJEs|LUl|R zGn*Xa=_B^B2!@_V8M45pnlKRi{>5Bc8e&(1=N$e8rhikDR!HBT{qxMgAZme0wI!Yo zz$keZ)~KQe5pO0%`(~>W`5JOzsRbw-CiqF-*qrFj=PI`HN69uUJi+lAe)EjhLVsCG zW60wUC7l@F+C4aKoA_PH2Dj*!DX|;xyHzML_ue&8PBm{KY6h;5fl`Z(qyuD%&a5ahaGx_A_l5 zk_BOi1R0L3!x4t!$=nB;*%9Y=7R$~8D^uJ1KQkwhc0$?Q-7ao^h6@eu4~9|9=h?b( za~CDnwVWd5DxxgVt;TB+9}=j=Y%ylY117s*bLE$04Q{gB$R?qWOy$qV%TDxWB6W^r zxyaw8%i9U>K}A?&MsYI~$}u$Fn`4gWpVCC0-_i|VGemwXyML_RRI?cw$kE((YFKAx z5J2&=Zu$sz;#l|)Bd1L|^iT=9Y4o~4=RGIA=A_-y>>`O6Om{AjbAQae8d}Wt=F=z! zOQe%0Xm>A?^jDMddCq487Y8YhoQ(+5Y|g0Xad!jTDmM=m0ClI~=+>Xm?j9k7hA5wl ze?Y?aIb^_&dY|n7Pw|rf*D+Lk?p+OnC8>XQ-9ul0(a~ZuvDHMa) zs^%)RkGTFOt+%dyp*clC5Jx4Sju;6uW)|24%tF%`PC3EP0(gghCX^X}4p4Q}6H% zNVeZLCWX^Rz7JOz`V#6BRs~UKX7NkMS)gQ>QPanyFQJ@HU zvhIgV#@zdpN;eX0#C-jI!Fslj)1vWqH2kwwv!&?_g)6>I%2^;s z&TKAZ=S$f-P#$@Evo~@T8&z(@46V}of2!8goC`Z8WR zVKaw_^tvP+x=jOwVg5#C4tl}oFp-#H$i1j3>uz}DsoE_s;R3+_*7*k{xEr?y@9{#! z+;IM@MajQ@wm`SRzzJ&POf%DsA>Y2X=iK86oRQkGbuvr;TL*x10L?Q27`yBw1cf+hVETdK7jy7civHqg8xJS zV*&ukJrM94PG87>3_&$1<3#ws-$2{H#zgZRJ}huA3Pp3u(f$L<_bRy82I?=bpDJ+! zf%R8@5Hx|s4&xu`sm&T9t9zB5xNF6~<39rYWVA&bC&Uz5pzWI&JyiUdBt2 zegS}DQ=%psCMqAIawK? zyt@s~AVtxh*RZkSr5_DDs7xg@7qpeN`qq5AcQ{o~t8!|ID%?q&w8d@L!6^dtjRYWX ziQ>D>bR`#wGO||zqb!(d-IUoc`&9;n)Ve4!@IP#%TG@Zq5FE#`jSNm_lVGs7+0&xp zna1F7RmB%sZJP?(NPS4)>0M0VY5#%pQ@Cofpe)ZruRzLchPQ+6%DI-Vqb#%voWaWa zcRcDFk&#;1O5*2*Ld~)~@5V`Y)gQ23vt!@!bpNvF*2_uN-EW<%{28>u3J>DxcBnV2H)>!Oz$z4#gnV}?#~ zCU>{=3MQ+JKw0M?NtEBe4DGe|SucsE9MfCWMc?1Ygii>L^(ezUl!r)d|NG4J17_yn zC&=%txBq|=fdf@O@Ai;HUtAGi*BXVvyTVVfTvIX}Pe?ij|a+C1? zFi01@Tt=J!F_``%cCQ>{=Ko$(B$2-$TiJHtzhls(PXCM;ykKNL1}I)ruEXl$mUEcB z%@jBht8s&MzySp?CX_jJQI6sF^6g)ns0hyL{16E6CEsWX-H!fmTad-Nrw}0gJEHKD zRA2GE=8|u1F z%uM^Tr!7PxH9ui!Fi|+B$_1!bp|WjcQ}y3#fmdG)k-!JE6_0T)y~q5mVxD<0sXq95 z-1%UY!ulFHkPpdq(EI@^$&aX|lK zMuDn&*rd%azTt;mumdBzSGDxRa))iVko37}UDIzZa%reM#Ba3r`gfnV*p1WBX%^T8ClW<&HLjyt=DdHsWlv^FNhqJBHGN|`JvD`2%&lPOZ@{H@9UcVv7M3f=J<3;W1&$dJBI@z9Kgd~FXE^B zkp-Xe(L?(>!Rx--b&|S;?KAcV^-e+tZjb(0ddUs58Y#N6S=pce<+TD8`)4>5S3H*(Bnuieu_2TCz^NddlP6GYG)ecd} zhIYF)jz?ort+8;o(DfiC1`kaA0Hg$ZzFvF z@VhsFKHNXKxfg@`Oo0QlS_*c^RlRe|40sfXBv>vBosuq-B|oJrs42hwN;q4wj2X%J zUR2Jm8Y`+eh>n5UG(Ay(N(&NyUoWtzAj4gZU8qBzZkcnJpm}BxL_;~}_*sKHOR1*B7V|4f4@!$wg$IOicM{qmOnZgye*?%`IQ(3oBP}xR{Xx}e{pGY{ z?gzeKU!{BKM_Xnos$G7#%EfK32+@8@X{7vMlZvlMo1YY3Iq>K6nkQ#Q05!|iQpkZyL2u!3&UU&CnlzuWn81;DM(bI41}pM>s1Eb} z7=6`MFzT%8FAoBWnR0|XVv9By}eg*Ty5hl$a35U z;s&2$HwN16mUZUA?A5x19lgDGneD5Ne2oFd4?}Gem77hYr`fEn+I_`>5$)o}vmRMW zo3Qs^YaJtAIc;AxF$O8&?;U0JRIYhj!DeNoOILakBUvPuLqxSFzZMcPm3QaCd4r-9 zqoqCm@vx%HiO%c}&!)SK`Z3|1L__};rH{7jQ4Hpt-}yVmv*VhHUHW1p=7PJ~qkD2T zh#~S#$mFbzEMb_~sn32RHKOB>6Kj}xGZWNG!zOWg+Q%%zwIjKuBje(0GhL5peUAy$ z1*!a1Sy_dEtP-k4`aJyeT!nY`ZSO2I@x;QpfuCQgv6|8BGnr3sh!e(S>V3%4V(gc& zBD_l_o0|6LHt$RyGaImv(#>fPy0C{#;Z)o1JwSDXq$VcBYCThq`Iv_~t~2as@K_%SNbw ziv?H`v=ejH09%j~kx5#9W0;g~kn_Z)4*o?~ajT{C;G7@dA7QpB!_M2XN;4gYtzflX9vYFDv)Q#&-K;i8W!n+(sw=}+CO3zJqlAdED zb3$^Xe?KvN$lcs(v*|#d3BHoYLW;g@H+tjqx>tMUw&DUlXFxe8bNtI|6Y@o_J5MoR z9@W$#UDUnxqU0ts5HuGG2p6n2d}K5>B358{L$(W;Ify84i&MF+S=y#|e|RT{zCv`m z2QpCEH8Vi6<$wq0C~y2`IztU*1UFj|lcvKAiR4qTrQpu1H=I_KVfIUz zc*oR~YB%Gf1lKZ~m-fT4ZWp>T>KhCS52e+85)mcm+e}{3^m!!96|1SBS7;Rm){!Nm zFU_6VzV92VRB1>1XXex3YwJ(V{C&hA00x@;UI6ctUVJu{Aj%WHLW|@s5cm&lvc6S% z`8tQjj?&SYQ@cPXy(nAn<7W~>5ijGT^zjdA7<)d|S>5p&i${f_?D?x=>;Mn;mw{VD z6-QIISI5??J50Ce6 zI~msgj{Az_r%Un1dZ5m2{}UJrP{1Ff>xQDO4eG}$jXqq^l1`5Tgi6+b^)Hk5I&8oa z!MOwVw;${cdN*z~L0Z+~)@LH8ENaMvLKb=;nWb?E(7&EKDoUKnM8x~QKZZ`;sDC%5 z1-|emOAg57y1%As^UoQ{H94 z#&3DO37bg|wT$b~bep&qKbu^(PFDl>Uams=Ek$xcotS}mcRArCCQD&VN#=oAaq|O> zhfigIpga7sB}=`Am0&egIcUDF#XDbE8{ez2KxQJZfbdXFo}7*gNeHgnqf_MmO4)A* z9{`^~1=X#U9)BkJ3GD~HM|B8tjuKCQ^ymYkqCQpfpZEg-fOrc)I&JI(dF+Z;MCyxU z2lQ;oHC3+6B%VdfX~2?9#M#4dGP|y3d)q*TQ2gUF2SH%z@@bo7t$a+*#Q^N0vx*#j z)xg7$^X>MpFD&dPJLg$SjqQo4E{)2@DLOU4@8TJqBMZN|Ruc$5*| zk0`V@e2zd^$jS}Q!)U=}TYz7E$m}Xbo>(tvWH*ro|3e(FI5%FSnvb*;1-IC#>mX$X z_!;)KE&I9ZjpNWS>L-!aMo^VjRbYs_nVUc$o0Oxfxrgx6Jnt*WLM~jiau`$VTF%W3oy@nqo zyli_53*&W{6T<`O=q%H@${%_q5?RKE1@6VvWsb=bi!ysX=KpPR-`b!@Q2=v3j zH?G=00{=A+6M}pmMh4C4Zp6j!a1UU>|1zr#|Ae)Sf0MSW?>=xTM+Y&}UM9Rf+p+s2 zLi@D$&SGhCh^uS_oeD~o`)e;3@`WwSSg(KtHIa7^)~jdgLi103;)N(dL*F5m1@hyo z3$K3y%1h!`q_Q&^KlE+|9o{jCIwiBb8)_$j_@6 zLB;>cpUrt+U&Y;$vd5wIFe)~ax|{OfTvJr#A_simLfQYpG0$!`SmIrGMDutJ4dw5x z*g04PFP7SPb%jT$d!jg9XMt*D{Azr|;QoiDs~oAYV$1j6o!PwIaWu~K^RKyQ?H`<0 ze*OoP?Km1p!f{k(&%49BZEF3*>iNWc`bni9=N&rLS%V(DaEb6g3y>U%fAmx~U5qVLZzx&Jd7AG%Ce5BDyvU%L?rGI8Sr9j>}(=-a;R0Jr$6|h_Fj<2QAk2N$Rzx_1k$W zt*Q!6#ZjE(xZrjRXlf{31VUr#eBKfsYwW7!_`=0S4*m?7F6q08 z-N`=NJ2uGqkU%<}iF$(nBiovh`2d-ghx99nHXyMYX)dz7$Rz}PR)u6ZoWal4n$A#At|A2fm#fwJ?biul0;`k}rCClT% zGpR`Okir04JpFJ}AQ6xBPd>fKV?S+z-_r0p-4JLlEz($B8=nO|rtIrCiia}QsUvp* zn-UU$r(N=rE_xO7{X?apK=2=lztX+JLQ|}o-a~~y!%kI!H#UdGfS>M70B_1MTNqaa zW++-lR<(4VE@xGK6uAGErkM+Oj3i`A9ZO!f5ALtgKDhFf>Hl&y-HOedneCS$tv|kp zYR+c(m7&Dfh#kESp6Wugiy)C15?+{R(-?`z~283O=KQ z{MIsQzcoGoW@1{;TD86A$f>*%Yi-aH@5lw>TVoG@p;tw$EM~PE!c#cz?WZ|b?d6TS ze%+ex>J;A^U*-~c!AUbBezt8&KR}?vS50W(b6bV z`F`50s(NaeZe(=d!_is28T+mfE@&Fw7GjB(uW8pgz378|@;X$VnMw#L7kV2 zTO^R2LLaY~R&5;5F%ads!l!p(IN+x!0V!R}sr0qz&AHpPyhvq?Ra28>vkgjuu0LS0 zysm-7$56x~?U?`&9a*uMAs<+=pOcQ|tPkrk@T1>9JloS_{T*&as1UUweE0 zvd~fwbbQ|2qV#R-gU}-0dYi)IWS-VPv=-Z`p>9X8-9Hv_Ue*d%3U8&q^E-o|zs6l$ zik{HFEHLsa(VTa6ktT-@`~3g|@u;vFY+!Az-$KwOVyAPoaP+ki(%a~p>C3hN8t01- zH-CQ-u}#qIL07?|CDpa!VW#v&UImn2Pe;+4ZKNcgMe&NZzu`e?n0(>7?x{3#jR(?D zXvK@D>^^K$Q;NR>l`O;l@$sPmUfPhV!#9?i)G0#r)CK2IP=e*4xM< zB|XBq0JOWAO|UD=@S@CW-5&cni;WFI^DiC#O-&y;jB%{SaT7@|*Lgna%G? z%UzxM3V$`6LRH?l#T3_&5a(5$t~fa{xoeG0ffp25?K<1RuqqW}4e>sMc=93K8Mp5x_t zc%BjFakUB9XWQ8(D;)fJSL}Jy&rQvH$!ClDB!AY@4KT1OnHqM4-e~2&-g>iW^5*^c zQ_79Z7KTH&;UjeEze>NWGqd@0sq5>#}4 zX0*vd5S6`&L_~;0^B}0qy=_d>_bZE%OikwV?w`EvWCx?LwH<5?^6`^-!iOdn$!_xX-o@v6i?!RFqhN%W=kSWr_55St?zdSsHylI2Z-#bv6wI? z&7V*T3Qzv1qWt1fC8r|cF4Cme5xfSwzBjgXm&SiJFHRmv*aALmPk&*P4; z&Yi<62K6BUy61acPN(eef@L|svb93S7oqRmmv6ngn4IEEce&J>$KNFf+j}M{SM@ga zPoHfYoH-gPwjWLQhhZX%>%*KVdy}`KniRLgb$(OB(zlVtye*5xD;!#C6B+$8=9N|z za!yy#mHB2f3rcsDm|c^_cBqtg_jR`TY~CG>UmI_r??lv1zDA4RzqP)UGtepvnf(OR z>bW7OFOEFpODQD{n5xPVcnwC#$I465-!rp|i`RHXMEq!uerm9c;Icgc)>}>cMyF7w zb+yArsz~EPrxRAvD5F-mjIum*nxFCRQ==O;q7hhM%}U*GhV|l?q3YiK-k+ zT-7gqw%M9S8BER+rFs9$V-B+&p-TZ~IGtyob6N~Bm`*9e!;cw4ibeHp1f+`A{Ak#& zi8(3!yhcHlUjNI-7&8m11^sM^YD%-6tLVC#*lp&w^eU zEifKGEkpe>?)gq!${flo{ODuT_QQP`FUOw8{T|ou;O^X)`$b|J90P_4%!C5gM4lHL6{?lCX09pIOaXe8+A8BssgTXP3|j$jF@V&?m(xkU@{0rFn<@rw zDc=(K<84*a7xf%j6O|*>!g1m{iuMsd)EzU!XZKdt3q?6_5tf#V5JuKCl7lk!I#=?P z=AQ9rd!H5IDccHzlyiwuFQC`(3Q!RN6_kv^Rh~t+4`9)f$K8$6brg9zH}-Xu&_oj& zro6|~sj73oQWDR|iRY~;_rv5Bv6T!upt32nWTBGOn?PG5b@YS03kz6zerH&@mhBi$ z-79YgkO;zTYZvFGNlAK14YI!dz;L{C%4Uxj*^l>k{=;hPKI*(N{w5=cO}*CZf#%P) zJJ#VKB;iSzn{bk8ksValWO4Um#O6TXlO-Bi>YKWxGp?PUnj8C#*Xs!@@W;tRLmc-# zohnoYAGfPLj{N0{5n{X%M8l?wSAHY2*T6J?Z}>(N4UV6zB8 zoM)u$81hD**B=c6J!=1igtu9&o-t&-Y_WJSog2^bc4rXT~f^I9>L4%U&bY#h5e09*75@;sS3$dco8ThLuJ)=xC&0}R@ zVoWX_(q#Zl;iSPRR(v4b5)CqXKhgm0URU3&e9|E>;;PN-#2f$(<`%EY=`>y%ZPg)6 z_AgdjeITYRvCtdoH@0}(7T=mTb zW8FH!+?(ik*`Sd)I_hvk-<9aAm?;0qYQxyz#N8V%phd;CQup(iw(`ZKjM()zj9H-F z$Og1rn!vW?kL6pv!J-7xUSCe~%I1J=7&3oQsW>zn9<;X-1SbM_#=Q>_Qs$l?27z_o zCyG45Yc};Nx$M`|?Yko`9VTfjU4mc3w*&7GKd{^A%1&}*OX@6c&@$#&(Lz-%`5O3) z63>wk2eHNoYO+G(8!#iTS_DW-iR}D`X++9mEZTUnb}yipD=~RNjOe%}0+df#BdsO< zp)zTo*-@*0wrLwG3!hCMTha(VVHz5JkBmqc)~~kew?_7YsJh(j&BSe%{_wGL}6xKhPWxQ~8fo;PW9`VFqu^flw zAWt`$x`RJuN9~H^Qx%@TBzPs4Dt9gs*i|J|v!CsZC^X7Q2{2_*Q(+UxHZ1ub-}ZJ& zKW76zhOV34%vpm?Cr|R9Z45@mJnnzXDJ3Nn{a+lFW3BsA4PB~c#XHb^%G>LW&Yf$4 z;D107-_P3VkHZSD+xa+UG)6~W&6eI!F&|ZJYJbEoE~|S%5JscK%-17SFl-$4Bz2{a ztOx@%z@6-g499EUK8yUza)Hzq-ux|qE`JZVc$7A=uP?HYl`dzo`swx<>#_(~cQV_D z_)Bhfx1Gb-H~@!<>?_mwN5et)PI%qhpUJ#HP*ek98zy}Vtj>3^MTc6T+Z-9kX6aR@ zoK%h-N}o(gb8p||XEU>1^S%h~q^G3= zpqxQBqwYw{ea!+wp$A;P7y?uRnJ8CNF=7J zY;p~yM3-Cw(}9uhT7cp*LNe$9h~z`&eHFk z6}?lX-^3Z}LVTjX^?C!o{Gx3#xG1cnxT78zQr`Z~g{0EF(?H*18Ay|q%0znzH?0KA zQf|TFfR|fZthCHJb>C*!b{GRG%e-a38T0vDbT~FM0PiW)6 z34z|BHijqJRDw7o>^AZ>-THGkJ~Pxh5@&Y52|L@BrI^zaP6rI(`cL}KFGRK*rrXAL>QFUrnGbz39I$+ z8g*K{*EpP}#zyO`g}uAFL*(OK+|SYbaFCha<3V!LQiueNY1$rGFwI9h$D-@(-M{>< zBJ62*$5E_za1^xR=jJoHn8=-u;9JrvTP93~+NXA|8!^Hp+(hGYi(|Ud76SriccL!k zG&WFZrlMP58M>|0iSah1(Z1GhwIfSoFytRIK1#(Xk_a*SH zO20Go-cR&g>+-MVn@(*GQ!x#k=Dp=CO#_>F3-xgU!io`GzY@mOlq%pBlx0@^1sDe z3c$$6vG&WME7eTK-OrqA8)3H1BQKEN7ClP=WL5eVF@bhhT1$uFu&=G`jpIrUhq^t( z@dL3~k~K9%XZiT=n)sn3KE1IHPhk9T0Hw2;Qka9pJ;HS!eM~uOpBE2pTOf+?M6;r`GwF#8Kd+2yYZqP6vLtYxq zFeEKPT1geTpjl?u7id>1aI#KS7j#9^l^VI46Yjn>E+BdidRZ7NzoJ}nSkcOVJLHfleR(>CXCJNxxpwMf6wx2w6X z7ZE2wOltB+nZnp?$e#X1{_c6|?v`_)twl}W*#AuA8eRY)knYu$ybY= zIKNhSo~R}DxiziEAHHH{_~KG*E5;WCeLb`E90?s^?!)`=j-*IYNZHypzqD9F%CUYj z=}Mp%^c*RH{`O7KNVh^FM8Fo0J1>Zg9WMbGf93w~lakvQ-ZWyUsb^=rd6lQouZ{iw zzEg?<3`K8iepNqBzV*z`#`qs_(lLxrNE;>?cz6%BIy zd!)Pt_1{5zSI?Oi@%w@j!L-$4Gp?Cu2YzS8_ohlHC95I3srM3QUpPL=Pxc%q5=t?Aeb&M*L>c>StBJgYuQw!hkY&`WEx|#p*O;}f39weujpZ( zJkoue;=q!jqsqHo@rFyRuvZfNCWu+%9Ys?qH9A9?{J2JG#=D&TylkB7m|$3qIV6+| zWvPbJQD2a@orASP=SUKDY6=$*pfPS@!c_#suRBYBixK1&^)+eF533+Spbez9cwQP2 zcRmTLEddH->S~ZJT@i3)P%-}2Z1=2ykVi#l2fFkoU#~&7_)BRg2*@y~Hp4=fb0iK{ zf!u}@c_6nzq8TDYoht?$S|F+?v&@Y3%)5TP28+@?ku3KAPQ(;C71m;X0GaT@PxY_d zHv#X{cd(Uyu33>&f0f82ZY46c)w2DQe?Xy)3yzAS{v&UF5Pe#-2;1HGt(3zIKWdaI z8XqJj;Mqn84{4(7l`1vKyMmp=&R#$}(WjHo7^nt|bp(PHD_gReB^=WN6ZhMx-d z^7~H6yK52y(ZfKPb@#~twe?gMigbWuDv0y27d&y@H1ebwZ$ z^P5Lp#^AS)uqo->fdjcW14GHOUP51yGⅆ4s9LByUazs_tSPq2N6uu-=U0+M;G>2 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 literal 0 HcmV?d00001 diff --git a/docs/quizzes/job-post.md b/docs/quizzes/00 job-post.md similarity index 100% rename from docs/quizzes/job-post.md rename to docs/quizzes/00 job-post.md diff --git a/docs/quizzes/job-software-engineer.md b/docs/quizzes/job-software-engineer.md deleted file mode 100644 index 8a0fdd5b..00000000 --- a/docs/quizzes/job-software-engineer.md +++ /dev/null @@ -1,143 +0,0 @@ -# 🚀 Software Development Engineer - -**Location:** San Francisco, CA (Hybrid) or Remote -**Type:** Full-time -**Team:** Engineering - ---- - -## About Aden - -We're building the future of AI agents. Aden is an open-source framework for creating self-improving, production-ready AI agents with built-in cost controls, human-in-the-loop capabilities, and comprehensive observability. - -Our mission: Make AI agents reliable enough for real-world production use. - ---- - -## The Role - -We're looking for a Software Development Engineer to help build and scale our AI agent platform. You'll work across the full stack, from our React dashboard to our Node.js backend, contributing to core infrastructure that powers autonomous AI systems. - -This is an opportunity to work on cutting-edge AI infrastructure alongside a small, experienced team passionate about shipping great software. - ---- - -## What You'll Do - -- Build and maintain features across our full-stack TypeScript codebase -- Design and implement APIs for agent management, monitoring, and control -- Work with real-time systems (WebSockets, event streaming) -- Optimize database performance (TimescaleDB, MongoDB, Redis) -- Contribute to our Model Context Protocol (MCP) server and tooling -- Collaborate on architecture decisions for scalability and reliability -- Write clean, tested, well-documented code -- Participate in code reviews and help maintain code quality - ---- - -## Tech Stack - -**Frontend (Honeycomb Dashboard)** -- React 18 + TypeScript -- Vite -- Tailwind CSS + Radix UI -- Zustand (state management) -- TanStack Query -- Recharts + Vega (data visualization) -- Socket.io (real-time updates) - -**Backend (Hive)** -- Node.js + Express + TypeScript -- Socket.io (WebSocket) -- Model Context Protocol (MCP) -- Zod (validation) -- Passport + JWT (authentication) - -**Data Layer** -- TimescaleDB (time-series metrics) -- MongoDB (policies, configuration) -- Redis (caching, pub/sub) - -**Infrastructure** -- Docker + Docker Compose -- Kubernetes + Kustomize -- GitHub Actions (CI/CD) -- Nginx - ---- - -## What We're Looking For - -**Required:** -- 2+ years of professional software development experience -- Strong proficiency in TypeScript and Node.js -- Experience with React and modern frontend development -- Familiarity with SQL and NoSQL databases -- Understanding of RESTful APIs and WebSocket communication -- Comfortable with Git and collaborative development workflows -- Strong problem-solving skills and attention to detail - -**Nice to Have:** -- Experience with AI/LLM applications or agent frameworks -- Knowledge of time-series databases (TimescaleDB, InfluxDB) -- Kubernetes and container orchestration experience -- Experience with real-time systems at scale -- Contributions to open-source projects -- Familiarity with Model Context Protocol (MCP) - ---- - -## What We Offer - -- Competitive salary + equity -- Health, dental, and vision insurance -- Flexible work arrangements (hybrid/remote) -- Learning & development budget -- Home office setup stipend -- Opportunity to work on open-source AI infrastructure -- Small team, big impact - ---- - -## How to Apply - -1. **Complete a challenge** from our [quiz collection](./README.md): - - [Getting Started](./01-getting-started.md) (required, 30 min) - - Plus ONE of: - - [Architecture Deep Dive](./02-architecture-deep-dive.md) (backend focus) - - [Frontend Challenge](./04-frontend-challenge.md) (frontend focus) - -2. **Submit your application:** - - Email: `contact@adenhq.com` - - Subject: `[SDE] Your Name` - - Include: - - Resume/CV - - GitHub profile - - Link to your completed challenge (GitHub Gist) - - Brief intro about yourself - -3. **What happens next:** - - We review your submission (1-2 weeks) - - Technical interview (60 min) - - Team interview (45 min) - - Offer 🎉 - ---- - -## Why Join Us? - -- **Impact:** Your code will power AI agents used by developers worldwide -- **Open Source:** Everything we build is open source -- **Learning:** Work with cutting-edge AI and distributed systems -- **Culture:** Small team, low ego, high trust, ship fast -- **Growth:** Early-stage company with room to grow - ---- - -*Aden is an equal opportunity employer. We celebrate diversity and are committed to creating an inclusive environment for all employees.* - ---- - -**Questions?** Email us at `careers@adenhq.com` or open an issue on [GitHub](https://github.com/adenhq/hive). - -Made with 🔥 Passion in San Francisco From 76563a32745dceb2a22fedcc7d87c71a6a65f573 Mon Sep 17 00:00:00 2001 From: Vincent Jiang Date: Wed, 21 Jan 2026 14:21:33 -0800 Subject: [PATCH 13/27] updated email contact@adenhq.com --- docs/quizzes/00 job-post.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/quizzes/00 job-post.md b/docs/quizzes/00 job-post.md index d7a42028..35a4fbce 100644 --- a/docs/quizzes/00 job-post.md +++ b/docs/quizzes/00 job-post.md @@ -122,7 +122,7 @@ This is an opportunity to work on cutting-edge AI infrastructure alongside a sma - Respond to code review feedback 4. **Submit your application:** - - Email: `careers@adenhq.com` + - Email: `contact@adenhq.com` - Subject: `[SDE] Your Name` - Include: - Resume/CV @@ -152,6 +152,6 @@ This is an opportunity to work on cutting-edge AI infrastructure alongside a sma --- -**Questions?** Email us at `careers@adenhq.com` or open an issue on [GitHub](https://github.com/adenhq/hive). +**Questions?** Email us at `contact@adenhq.com` or open an issue on [GitHub](https://github.com/adenhq/hive). Made with 🔥 Passion in San Francisco From 989801dd77079dd69f3df84fc3711130343df9bd Mon Sep 17 00:00:00 2001 From: Richard T Date: Wed, 21 Jan 2026 16:40:30 -0800 Subject: [PATCH 14/27] fix: fix dependency issues --- package-lock.json | 5051 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 4797 insertions(+), 254 deletions(-) diff --git a/package-lock.json b/package-lock.json index 558220b2..291f77c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -134,6 +134,8 @@ }, "node_modules/@acho-inc/administration": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@acho-inc/administration/-/administration-1.0.7.tgz", + "integrity": "sha512-ZeWiufXWqQQU/rEHvkvIV+GMppxF2FAvtcxmud3zDPwuCrAmOpMUdFqEwUIBa9OtgJYETUNciHKpzaTkT3u7iA==", "license": "UNLICENSED", "dependencies": { "bcrypt": "^6.0.0", @@ -155,11 +157,15 @@ }, "node_modules/@adobe/css-tools": { "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz", + "integrity": "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==", "dev": true, "license": "MIT" }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", "license": "MIT", "engines": { "node": ">=10" @@ -170,6 +176,8 @@ }, "node_modules/@asamuzakjp/css-color": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", + "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", "dev": true, "license": "MIT", "dependencies": { @@ -182,11 +190,15 @@ }, "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true, "license": "ISC" }, "node_modules/@babel/code-frame": { "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz", + "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==", "dev": true, "license": "MIT", "dependencies": { @@ -200,6 +212,8 @@ }, "node_modules/@babel/compat-data": { "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.6.tgz", + "integrity": "sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==", "dev": true, "license": "MIT", "engines": { @@ -208,6 +222,8 @@ }, "node_modules/@babel/core": { "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz", + "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", "dev": true, "license": "MIT", "dependencies": { @@ -237,6 +253,8 @@ }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "license": "ISC", "bin": { @@ -245,6 +263,8 @@ }, "node_modules/@babel/generator": { "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.6.tgz", + "integrity": "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==", "dev": true, "license": "MIT", "dependencies": { @@ -260,6 +280,8 @@ }, "node_modules/@babel/helper-compilation-targets": { "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", "dev": true, "license": "MIT", "dependencies": { @@ -275,6 +297,8 @@ }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "license": "ISC", "bin": { @@ -283,6 +307,8 @@ }, "node_modules/@babel/helper-globals": { "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", "dev": true, "license": "MIT", "engines": { @@ -291,6 +317,8 @@ }, "node_modules/@babel/helper-module-imports": { "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "dev": true, "license": "MIT", "dependencies": { @@ -303,6 +331,8 @@ }, "node_modules/@babel/helper-module-transforms": { "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "dev": true, "license": "MIT", "dependencies": { @@ -319,6 +349,8 @@ }, "node_modules/@babel/helper-plugin-utils": { "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", "dev": true, "license": "MIT", "engines": { @@ -327,6 +359,8 @@ }, "node_modules/@babel/helper-string-parser": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, "license": "MIT", "engines": { @@ -335,6 +369,8 @@ }, "node_modules/@babel/helper-validator-identifier": { "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "dev": true, "license": "MIT", "engines": { @@ -343,6 +379,8 @@ }, "node_modules/@babel/helper-validator-option": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "dev": true, "license": "MIT", "engines": { @@ -351,6 +389,8 @@ }, "node_modules/@babel/helpers": { "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", "dev": true, "license": "MIT", "dependencies": { @@ -363,6 +403,8 @@ }, "node_modules/@babel/parser": { "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz", + "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", "dev": true, "license": "MIT", "dependencies": { @@ -377,6 +419,8 @@ }, "node_modules/@babel/plugin-syntax-async-generators": { "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "dev": true, "license": "MIT", "dependencies": { @@ -388,6 +432,8 @@ }, "node_modules/@babel/plugin-syntax-bigint": { "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", "dev": true, "license": "MIT", "dependencies": { @@ -399,6 +445,8 @@ }, "node_modules/@babel/plugin-syntax-class-properties": { "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, "license": "MIT", "dependencies": { @@ -410,6 +458,8 @@ }, "node_modules/@babel/plugin-syntax-class-static-block": { "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", "dev": true, "license": "MIT", "dependencies": { @@ -424,6 +474,8 @@ }, "node_modules/@babel/plugin-syntax-import-attributes": { "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", + "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", "dev": true, "license": "MIT", "dependencies": { @@ -438,6 +490,8 @@ }, "node_modules/@babel/plugin-syntax-import-meta": { "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, "license": "MIT", "dependencies": { @@ -449,6 +503,8 @@ }, "node_modules/@babel/plugin-syntax-json-strings": { "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "dev": true, "license": "MIT", "dependencies": { @@ -460,6 +516,8 @@ }, "node_modules/@babel/plugin-syntax-jsx": { "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", "dev": true, "license": "MIT", "dependencies": { @@ -474,6 +532,8 @@ }, "node_modules/@babel/plugin-syntax-logical-assignment-operators": { "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "dev": true, "license": "MIT", "dependencies": { @@ -485,6 +545,8 @@ }, "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "dev": true, "license": "MIT", "dependencies": { @@ -496,6 +558,8 @@ }, "node_modules/@babel/plugin-syntax-numeric-separator": { "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", "dev": true, "license": "MIT", "dependencies": { @@ -507,6 +571,8 @@ }, "node_modules/@babel/plugin-syntax-object-rest-spread": { "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "dev": true, "license": "MIT", "dependencies": { @@ -518,6 +584,8 @@ }, "node_modules/@babel/plugin-syntax-optional-catch-binding": { "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "dev": true, "license": "MIT", "dependencies": { @@ -529,6 +597,8 @@ }, "node_modules/@babel/plugin-syntax-optional-chaining": { "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "dev": true, "license": "MIT", "dependencies": { @@ -540,6 +610,8 @@ }, "node_modules/@babel/plugin-syntax-private-property-in-object": { "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", "dev": true, "license": "MIT", "dependencies": { @@ -554,6 +626,8 @@ }, "node_modules/@babel/plugin-syntax-top-level-await": { "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, "license": "MIT", "dependencies": { @@ -568,6 +642,8 @@ }, "node_modules/@babel/plugin-syntax-typescript": { "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", + "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", "dev": true, "license": "MIT", "dependencies": { @@ -582,6 +658,8 @@ }, "node_modules/@babel/plugin-transform-react-jsx-self": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", "dev": true, "license": "MIT", "dependencies": { @@ -596,6 +674,8 @@ }, "node_modules/@babel/plugin-transform-react-jsx-source": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", "dev": true, "license": "MIT", "dependencies": { @@ -610,6 +690,8 @@ }, "node_modules/@babel/runtime": { "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", + "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", "dev": true, "license": "MIT", "engines": { @@ -618,6 +700,8 @@ }, "node_modules/@babel/template": { "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "dev": true, "license": "MIT", "dependencies": { @@ -631,6 +715,8 @@ }, "node_modules/@babel/traverse": { "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.6.tgz", + "integrity": "sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==", "dev": true, "license": "MIT", "dependencies": { @@ -648,6 +734,8 @@ }, "node_modules/@babel/types": { "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz", + "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", "dev": true, "license": "MIT", "dependencies": { @@ -660,11 +748,15 @@ }, "node_modules/@bcoe/v8-coverage": { "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true, "license": "MIT" }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, "license": "MIT", "dependencies": { @@ -676,6 +768,8 @@ }, "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, "license": "MIT", "dependencies": { @@ -685,6 +779,8 @@ }, "node_modules/@csstools/color-helpers": { "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", "dev": true, "funding": [ { @@ -703,6 +799,8 @@ }, "node_modules/@csstools/css-calc": { "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", "dev": true, "funding": [ { @@ -725,6 +823,8 @@ }, "node_modules/@csstools/css-color-parser": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", "dev": true, "funding": [ { @@ -751,6 +851,8 @@ }, "node_modules/@csstools/css-parser-algorithms": { "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", "dev": true, "funding": [ { @@ -772,6 +874,8 @@ }, "node_modules/@csstools/css-tokenizer": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", "dev": true, "funding": [ { @@ -790,10 +894,439 @@ }, "node_modules/@date-fns/tz": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@date-fns/tz/-/tz-1.4.1.tgz", + "integrity": "sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==", "license": "MIT" }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/win32-x64": { "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", "cpu": [ "x64" ], @@ -809,6 +1342,8 @@ }, "node_modules/@eslint-community/eslint-utils": { "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", "dev": true, "license": "MIT", "dependencies": { @@ -826,6 +1361,8 @@ }, "node_modules/@eslint-community/regexpp": { "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", "dev": true, "license": "MIT", "engines": { @@ -834,6 +1371,8 @@ }, "node_modules/@eslint/eslintrc": { "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "license": "MIT", "dependencies": { @@ -856,6 +1395,8 @@ }, "node_modules/@eslint/eslintrc/node_modules/ajv": { "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", "dependencies": { @@ -871,6 +1412,8 @@ }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -880,11 +1423,15 @@ }, "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, "license": "MIT" }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", "dependencies": { @@ -896,6 +1443,8 @@ }, "node_modules/@eslint/js": { "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "dev": true, "license": "MIT", "engines": { @@ -904,6 +1453,8 @@ }, "node_modules/@floating-ui/core": { "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", "license": "MIT", "dependencies": { "@floating-ui/utils": "^0.2.10" @@ -911,6 +1462,8 @@ }, "node_modules/@floating-ui/dom": { "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", + "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", "license": "MIT", "dependencies": { "@floating-ui/core": "^1.7.3", @@ -919,6 +1472,8 @@ }, "node_modules/@floating-ui/react-dom": { "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz", + "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==", "license": "MIT", "dependencies": { "@floating-ui/dom": "^1.7.4" @@ -930,10 +1485,14 @@ }, "node_modules/@floating-ui/utils": { "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", "license": "MIT" }, "node_modules/@hono/node-server": { "version": "1.19.9", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.9.tgz", + "integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==", "license": "MIT", "engines": { "node": ">=18.14.1" @@ -944,6 +1503,8 @@ }, "node_modules/@hookform/resolvers": { "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-5.2.2.tgz", + "integrity": "sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA==", "license": "MIT", "dependencies": { "@standard-schema/utils": "^0.3.0" @@ -954,6 +1515,9 @@ }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -967,6 +1531,8 @@ }, "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -976,6 +1542,8 @@ }, "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", "dependencies": { @@ -987,6 +1555,8 @@ }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -999,15 +1569,22 @@ }, "node_modules/@humanwhocodes/object-schema": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", "dev": true, "license": "BSD-3-Clause" }, "node_modules/@ioredis/commands": { "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.5.0.tgz", + "integrity": "sha512-eUgLqrMf8nJkZxT24JvVRrQya1vZkQh8BBeYNwGDqa5I0VUi8ACx7uFvAaLxintokpTenkK6DASvo/bvNbBGow==", "license": "MIT" }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, "license": "ISC", "dependencies": { @@ -1023,6 +1600,8 @@ }, "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "license": "MIT", "dependencies": { @@ -1031,6 +1610,8 @@ }, "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "license": "MIT", "dependencies": { @@ -1043,6 +1624,8 @@ }, "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "dev": true, "license": "MIT", "dependencies": { @@ -1055,6 +1638,8 @@ }, "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "license": "MIT", "dependencies": { @@ -1066,6 +1651,8 @@ }, "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "license": "MIT", "dependencies": { @@ -1080,6 +1667,8 @@ }, "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "license": "MIT", "dependencies": { @@ -1091,6 +1680,8 @@ }, "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, "license": "MIT", "engines": { @@ -1099,6 +1690,8 @@ }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, "license": "MIT", "engines": { @@ -1107,6 +1700,8 @@ }, "node_modules/@jest/console": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", "dev": true, "license": "MIT", "dependencies": { @@ -1121,8 +1716,84 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/console/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/console/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/console/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/console/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, "node_modules/@jest/core": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", "dev": true, "license": "MIT", "dependencies": { @@ -1169,6 +1840,8 @@ }, "node_modules/@jest/core/node_modules/ansi-styles": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", "engines": { @@ -1178,8 +1851,49 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/@jest/core/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/@jest/core/node_modules/pretty-format": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1193,6 +1907,8 @@ }, "node_modules/@jest/core/node_modules/react-is": { "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true, "license": "MIT" }, @@ -1208,6 +1924,8 @@ }, "node_modules/@jest/environment": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", "dev": true, "license": "MIT", "dependencies": { @@ -1220,8 +1938,43 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/environment/node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/environment/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/@jest/expect": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1233,7 +1986,22 @@ } }, "node_modules/@jest/expect-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", + "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect/node_modules/@jest/expect-utils": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", "dev": true, "license": "MIT", "dependencies": { @@ -1243,8 +2011,133 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/expect/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/expect/node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect/node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, "node_modules/@jest/fake-timers": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1259,6 +2152,95 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/fake-timers/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/fake-timers/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers/node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, "node_modules/@jest/get-type": { "version": "30.1.0", "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", @@ -1271,6 +2253,8 @@ }, "node_modules/@jest/globals": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1283,6 +2267,39 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/globals/node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/@jest/pattern": { "version": "30.0.1", "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", @@ -1309,6 +2326,8 @@ }, "node_modules/@jest/reporters": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", "dev": true, "license": "MIT", "dependencies": { @@ -1349,8 +2368,84 @@ } } }, + "node_modules/@jest/reporters/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, "node_modules/@jest/schemas": { "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, "license": "MIT", "dependencies": { @@ -1362,6 +2457,8 @@ }, "node_modules/@jest/source-map": { "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", "dev": true, "license": "MIT", "dependencies": { @@ -1375,6 +2472,8 @@ }, "node_modules/@jest/test-result": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", "dev": true, "license": "MIT", "dependencies": { @@ -1389,6 +2488,8 @@ }, "node_modules/@jest/test-sequencer": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", "dev": true, "license": "MIT", "dependencies": { @@ -1403,6 +2504,8 @@ }, "node_modules/@jest/transform": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", "dev": true, "license": "MIT", "dependencies": { @@ -1426,8 +2529,28 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/transform/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/@jest/types": { "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, "license": "MIT", "dependencies": { @@ -1444,6 +2567,8 @@ }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", @@ -1452,6 +2577,8 @@ }, "node_modules/@jridgewell/remapping": { "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1461,6 +2588,8 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "license": "MIT", "engines": { "node": ">=6.0.0" @@ -1468,10 +2597,14 @@ }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1480,6 +2613,8 @@ }, "node_modules/@modelcontextprotocol/sdk": { "version": "1.25.3", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.25.3.tgz", + "integrity": "sha512-vsAMBMERybvYgKbg/l4L1rhS7VXV1c0CtyJg72vwxONVX0l4ZfKVAnZEWTQixJGTzKnELjQ59e4NbdFDALRiAQ==", "license": "MIT", "dependencies": { "@hono/node-server": "^1.19.9", @@ -1517,6 +2652,8 @@ }, "node_modules/@modelcontextprotocol/sdk/node_modules/accepts": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "license": "MIT", "dependencies": { "mime-types": "^3.0.0", @@ -1528,6 +2665,8 @@ }, "node_modules/@modelcontextprotocol/sdk/node_modules/body-parser": { "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", "license": "MIT", "dependencies": { "bytes": "^3.1.2", @@ -1550,6 +2689,8 @@ }, "node_modules/@modelcontextprotocol/sdk/node_modules/content-disposition": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", "license": "MIT", "engines": { "node": ">=18" @@ -1561,6 +2702,8 @@ }, "node_modules/@modelcontextprotocol/sdk/node_modules/cookie-signature": { "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", "license": "MIT", "engines": { "node": ">=6.6.0" @@ -1568,6 +2711,8 @@ }, "node_modules/@modelcontextprotocol/sdk/node_modules/debug": { "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -1583,6 +2728,8 @@ }, "node_modules/@modelcontextprotocol/sdk/node_modules/express": { "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", "dependencies": { "accepts": "^2.0.0", @@ -1624,6 +2771,8 @@ }, "node_modules/@modelcontextprotocol/sdk/node_modules/finalhandler": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "license": "MIT", "dependencies": { "debug": "^4.4.0", @@ -1643,6 +2792,8 @@ }, "node_modules/@modelcontextprotocol/sdk/node_modules/fresh": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -1650,6 +2801,8 @@ }, "node_modules/@modelcontextprotocol/sdk/node_modules/iconv-lite": { "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -1664,6 +2817,8 @@ }, "node_modules/@modelcontextprotocol/sdk/node_modules/media-typer": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -1671,6 +2826,8 @@ }, "node_modules/@modelcontextprotocol/sdk/node_modules/merge-descriptors": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "license": "MIT", "engines": { "node": ">=18" @@ -1681,6 +2838,8 @@ }, "node_modules/@modelcontextprotocol/sdk/node_modules/mime-types": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "license": "MIT", "dependencies": { "mime-db": "^1.54.0" @@ -1695,6 +2854,8 @@ }, "node_modules/@modelcontextprotocol/sdk/node_modules/negotiator": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -1702,6 +2863,8 @@ }, "node_modules/@modelcontextprotocol/sdk/node_modules/send": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", "license": "MIT", "dependencies": { "debug": "^4.4.3", @@ -1726,6 +2889,8 @@ }, "node_modules/@modelcontextprotocol/sdk/node_modules/serve-static": { "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "license": "MIT", "dependencies": { "encodeurl": "^2.0.0", @@ -1743,6 +2908,8 @@ }, "node_modules/@modelcontextprotocol/sdk/node_modules/type-is": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", "license": "MIT", "dependencies": { "content-type": "^1.0.5", @@ -1755,6 +2922,8 @@ }, "node_modules/@mongodb-js/saslprep": { "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.4.5.tgz", + "integrity": "sha512-k64Lbyb7ycCSXHSLzxVdb2xsKGPMvYZfCICXvDsI8Z65CeWQzTEKS4YmGbnqw+U9RBvLPTsB6UCmwkgsDTGWIw==", "license": "MIT", "dependencies": { "sparse-bitfield": "^3.0.3" @@ -1775,6 +2944,8 @@ }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -1786,6 +2957,8 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "license": "MIT", "engines": { "node": ">= 8" @@ -1793,6 +2966,8 @@ }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -1814,14 +2989,20 @@ }, "node_modules/@radix-ui/number": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", "license": "MIT" }, "node_modules/@radix-ui/primitive": { "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", "license": "MIT" }, "node_modules/@radix-ui/react-arrow": { "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.3" @@ -1843,6 +3024,8 @@ }, "node_modules/@radix-ui/react-arrow/node_modules/@radix-ui/react-primitive": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.3" @@ -1864,6 +3047,8 @@ }, "node_modules/@radix-ui/react-arrow/node_modules/@radix-ui/react-slot": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -1880,6 +3065,8 @@ }, "node_modules/@radix-ui/react-avatar": { "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.11.tgz", + "integrity": "sha512-0Qk603AHGV28BOBO34p7IgD5m+V5Sg/YovfayABkoDDBM5d3NCx0Mp4gGrjzLGes1jV5eNOE1r3itqOR33VC6Q==", "license": "MIT", "dependencies": { "@radix-ui/react-context": "1.1.3", @@ -1905,6 +3092,8 @@ }, "node_modules/@radix-ui/react-collection": { "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", @@ -1929,6 +3118,8 @@ }, "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-context": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -1942,6 +3133,8 @@ }, "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-primitive": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.3" @@ -1963,6 +3156,8 @@ }, "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -1979,6 +3174,8 @@ }, "node_modules/@radix-ui/react-compose-refs": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -1992,6 +3189,8 @@ }, "node_modules/@radix-ui/react-context": { "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.3.tgz", + "integrity": "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -2005,6 +3204,8 @@ }, "node_modules/@radix-ui/react-dialog": { "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", + "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", @@ -2039,6 +3240,8 @@ }, "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-context": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -2052,6 +3255,8 @@ }, "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-primitive": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.3" @@ -2073,6 +3278,8 @@ }, "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -2089,6 +3296,8 @@ }, "node_modules/@radix-ui/react-direction": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -2102,6 +3311,8 @@ }, "node_modules/@radix-ui/react-dismissable-layer": { "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", + "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", @@ -2127,6 +3338,8 @@ }, "node_modules/@radix-ui/react-dismissable-layer/node_modules/@radix-ui/react-primitive": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.3" @@ -2148,6 +3361,8 @@ }, "node_modules/@radix-ui/react-dismissable-layer/node_modules/@radix-ui/react-slot": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -2164,6 +3379,8 @@ }, "node_modules/@radix-ui/react-dropdown-menu": { "version": "2.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz", + "integrity": "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", @@ -2191,6 +3408,8 @@ }, "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-context": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -2204,6 +3423,8 @@ }, "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-primitive": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.3" @@ -2225,6 +3446,8 @@ }, "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-slot": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -2241,6 +3464,8 @@ }, "node_modules/@radix-ui/react-focus-guards": { "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", + "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -2254,6 +3479,8 @@ }, "node_modules/@radix-ui/react-focus-scope": { "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", @@ -2277,6 +3504,8 @@ }, "node_modules/@radix-ui/react-focus-scope/node_modules/@radix-ui/react-primitive": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.3" @@ -2298,6 +3527,8 @@ }, "node_modules/@radix-ui/react-focus-scope/node_modules/@radix-ui/react-slot": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -2314,6 +3545,8 @@ }, "node_modules/@radix-ui/react-id": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", "license": "MIT", "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" @@ -2330,6 +3563,8 @@ }, "node_modules/@radix-ui/react-label": { "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.8.tgz", + "integrity": "sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==", "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.4" @@ -2351,6 +3586,8 @@ }, "node_modules/@radix-ui/react-menu": { "version": "2.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz", + "integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", @@ -2389,6 +3626,8 @@ }, "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-context": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -2402,6 +3641,8 @@ }, "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-primitive": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.3" @@ -2423,6 +3664,8 @@ }, "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-slot": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -2439,6 +3682,8 @@ }, "node_modules/@radix-ui/react-popover": { "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz", + "integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", @@ -2474,6 +3719,8 @@ }, "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-context": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -2487,6 +3734,8 @@ }, "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-primitive": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.3" @@ -2508,6 +3757,8 @@ }, "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-slot": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -2524,6 +3775,8 @@ }, "node_modules/@radix-ui/react-popper": { "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", + "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", "license": "MIT", "dependencies": { "@floating-ui/react-dom": "^2.0.0", @@ -2554,6 +3807,8 @@ }, "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-context": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -2567,6 +3822,8 @@ }, "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-primitive": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.3" @@ -2588,6 +3845,8 @@ }, "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-slot": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -2604,6 +3863,8 @@ }, "node_modules/@radix-ui/react-portal": { "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.3", @@ -2626,6 +3887,8 @@ }, "node_modules/@radix-ui/react-portal/node_modules/@radix-ui/react-primitive": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.3" @@ -2647,6 +3910,8 @@ }, "node_modules/@radix-ui/react-portal/node_modules/@radix-ui/react-slot": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -2663,6 +3928,8 @@ }, "node_modules/@radix-ui/react-presence": { "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", @@ -2685,6 +3952,8 @@ }, "node_modules/@radix-ui/react-primitive": { "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.4" @@ -2706,6 +3975,8 @@ }, "node_modules/@radix-ui/react-progress": { "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.8.tgz", + "integrity": "sha512-+gISHcSPUJ7ktBy9RnTqbdKW78bcGke3t6taawyZ71pio1JewwGSJizycs7rLhGTvMJYCQB1DBK4KQsxs7U8dA==", "license": "MIT", "dependencies": { "@radix-ui/react-context": "1.1.3", @@ -2728,6 +3999,8 @@ }, "node_modules/@radix-ui/react-roving-focus": { "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", + "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", @@ -2757,6 +4030,8 @@ }, "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-context": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -2770,6 +4045,8 @@ }, "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-primitive": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.3" @@ -2791,6 +4068,8 @@ }, "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-slot": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -2807,6 +4086,8 @@ }, "node_modules/@radix-ui/react-scroll-area": { "version": "1.2.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.10.tgz", + "integrity": "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==", "license": "MIT", "dependencies": { "@radix-ui/number": "1.1.1", @@ -2836,6 +4117,8 @@ }, "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-context": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -2849,6 +4132,8 @@ }, "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-primitive": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.3" @@ -2870,6 +4155,8 @@ }, "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-slot": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -2886,6 +4173,8 @@ }, "node_modules/@radix-ui/react-select": { "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz", + "integrity": "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==", "license": "MIT", "dependencies": { "@radix-ui/number": "1.1.1", @@ -2927,6 +4216,8 @@ }, "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-context": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -2940,6 +4231,8 @@ }, "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-primitive": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.3" @@ -2961,6 +4254,8 @@ }, "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-slot": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -2977,6 +4272,8 @@ }, "node_modules/@radix-ui/react-separator": { "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.8.tgz", + "integrity": "sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g==", "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.4" @@ -2998,6 +4295,8 @@ }, "node_modules/@radix-ui/react-slot": { "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.4.tgz", + "integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -3014,6 +4313,8 @@ }, "node_modules/@radix-ui/react-switch": { "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.6.tgz", + "integrity": "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", @@ -3041,6 +4342,8 @@ }, "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-context": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -3054,6 +4357,8 @@ }, "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-primitive": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.3" @@ -3075,6 +4380,8 @@ }, "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-slot": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -3091,6 +4398,8 @@ }, "node_modules/@radix-ui/react-tabs": { "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", + "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", @@ -3119,6 +4428,8 @@ }, "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-context": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -3132,6 +4443,8 @@ }, "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-primitive": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.3" @@ -3153,6 +4466,8 @@ }, "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-slot": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -3169,6 +4484,8 @@ }, "node_modules/@radix-ui/react-tooltip": { "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz", + "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", @@ -3201,6 +4518,8 @@ }, "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-context": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -3214,6 +4533,8 @@ }, "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-primitive": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.3" @@ -3235,6 +4556,8 @@ }, "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -3251,6 +4574,8 @@ }, "node_modules/@radix-ui/react-use-callback-ref": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -3264,6 +4589,8 @@ }, "node_modules/@radix-ui/react-use-controllable-state": { "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", "license": "MIT", "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", @@ -3281,6 +4608,8 @@ }, "node_modules/@radix-ui/react-use-effect-event": { "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", "license": "MIT", "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" @@ -3297,6 +4626,8 @@ }, "node_modules/@radix-ui/react-use-escape-keydown": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", "license": "MIT", "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" @@ -3313,6 +4644,8 @@ }, "node_modules/@radix-ui/react-use-is-hydrated": { "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz", + "integrity": "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==", "license": "MIT", "dependencies": { "use-sync-external-store": "^1.5.0" @@ -3329,6 +4662,8 @@ }, "node_modules/@radix-ui/react-use-layout-effect": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -3342,6 +4677,8 @@ }, "node_modules/@radix-ui/react-use-previous": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -3355,6 +4692,8 @@ }, "node_modules/@radix-ui/react-use-rect": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", + "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", "license": "MIT", "dependencies": { "@radix-ui/rect": "1.1.1" @@ -3371,6 +4710,8 @@ }, "node_modules/@radix-ui/react-use-size": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", "license": "MIT", "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" @@ -3387,6 +4728,8 @@ }, "node_modules/@radix-ui/react-visually-hidden": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.3" @@ -3408,6 +4751,8 @@ }, "node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-primitive": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.3" @@ -3429,6 +4774,8 @@ }, "node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-slot": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -3445,10 +4792,14 @@ }, "node_modules/@radix-ui/rect": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", + "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", "license": "MIT" }, "node_modules/@reduxjs/toolkit": { "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.11.2.tgz", + "integrity": "sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==", "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.0.0", @@ -3473,6 +4824,8 @@ }, "node_modules/@reduxjs/toolkit/node_modules/immer": { "version": "11.1.3", + "resolved": "https://registry.npmjs.org/immer/-/immer-11.1.3.tgz", + "integrity": "sha512-6jQTc5z0KJFtr1UgFpIL3N9XSC3saRaI9PwWtzM2pSqkNGtiNkYY2OSwkOGDK2XcTRcLb1pi/aNkKZz0nxVH4Q==", "license": "MIT", "funding": { "type": "opencollective", @@ -3481,6 +4834,8 @@ }, "node_modules/@remix-run/router": { "version": "1.23.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.2.tgz", + "integrity": "sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w==", "license": "MIT", "engines": { "node": ">=14.0.0" @@ -3488,11 +4843,337 @@ }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", "dev": true, "license": "MIT" }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.3.tgz", + "integrity": "sha512-qyX8+93kK/7R5BEXPC2PjUt0+fS/VO2BVHjEHyIEWiYn88rcRBHmdLgoJjktBltgAf+NY7RfCGB1SoyKS/p9kg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.3.tgz", + "integrity": "sha512-6sHrL42bjt5dHQzJ12Q4vMKfN+kUnZ0atHHnv4V0Wd9JMTk7FDzSY35+7qbz3ypQYMBPANbpGK7JpnWNnhGt8g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.3.tgz", + "integrity": "sha512-1ht2SpGIjEl2igJ9AbNpPIKzb1B5goXOcmtD0RFxnwNuMxqkR6AUaaErZz+4o+FKmzxcSNBOLrzsICZVNYa1Rw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.3.tgz", + "integrity": "sha512-FYZ4iVunXxtT+CZqQoPVwPhH7549e/Gy7PIRRtq4t5f/vt54pX6eG9ebttRH6QSH7r/zxAFA4EZGlQ0h0FvXiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.3.tgz", + "integrity": "sha512-M/mwDCJ4wLsIgyxv2Lj7Len+UMHd4zAXu4GQ2UaCdksStglWhP61U3uowkaYBQBhVoNpwx5Hputo8eSqM7K82Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.3.tgz", + "integrity": "sha512-5jZT2c7jBCrMegKYTYTpni8mg8y3uY8gzeq2ndFOANwNuC/xJbVAoGKR9LhMDA0H3nIhvaqUoBEuJoICBudFrA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.3.tgz", + "integrity": "sha512-YeGUhkN1oA+iSPzzhEjVPS29YbViOr8s4lSsFaZKLHswgqP911xx25fPOyE9+khmN6W4VeM0aevbDp4kkEoHiA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.3.tgz", + "integrity": "sha512-eo0iOIOvcAlWB3Z3eh8pVM8hZ0oVkK3AjEM9nSrkSug2l15qHzF3TOwT0747omI6+CJJvl7drwZepT+re6Fy/w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.3.tgz", + "integrity": "sha512-DJay3ep76bKUDImmn//W5SvpjRN5LmK/ntWyeJs/dcnwiiHESd3N4uteK9FDLf0S0W8E6Y0sVRXpOCoQclQqNg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.3.tgz", + "integrity": "sha512-BKKWQkY2WgJ5MC/ayvIJTHjy0JUGb5efaHCUiG/39sSUvAYRBaO3+/EK0AZT1RF3pSj86O24GLLik9mAYu0IJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.3.tgz", + "integrity": "sha512-Q9nVlWtKAG7ISW80OiZGxTr6rYtyDSkauHUtvkQI6TNOJjFvpj4gcH+KaJihqYInnAzEEUetPQubRwHef4exVg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.3.tgz", + "integrity": "sha512-2H5LmhzrpC4fFRNwknzmmTvvyJPHwESoJgyReXeFoYYuIDfBhP29TEXOkCJE/KxHi27mj7wDUClNq78ue3QEBQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.3.tgz", + "integrity": "sha512-9S542V0ie9LCTznPYlvaeySwBeIEa7rDBgLHKZ5S9DBgcqdJYburabm8TqiqG6mrdTzfV5uttQRHcbKff9lWtA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.3.tgz", + "integrity": "sha512-ukxw+YH3XXpcezLgbJeasgxyTbdpnNAkrIlFGDl7t+pgCxZ89/6n1a+MxlY7CegU+nDgrgdqDelPRNQ/47zs0g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.3.tgz", + "integrity": "sha512-Iauw9UsTTvlF++FhghFJjqYxyXdggXsOqGpFBylaRopVpcbfyIIsNvkf9oGwfgIcf57z3m8+/oSYTo6HutBFNw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.3.tgz", + "integrity": "sha512-3OqKAHSEQXKdq9mQ4eajqUgNIK27VZPW3I26EP8miIzuKzCJ3aW3oEn2pzF+4/Hj/Moc0YDsOtBgT5bZ56/vcA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.3.tgz", + "integrity": "sha512-0CM8dSVzVIaqMcXIFej8zZrSFLnGrAE8qlNbbHfTw1EEPnFTg1U1ekI0JdzjPyzSfUsHWtodilQQG/RA55berA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.3.tgz", + "integrity": "sha512-+fgJE12FZMIgBaKIAGd45rxf+5ftcycANJRWk8Vz0NnMTM5rADPGuRFTYar+Mqs560xuART7XsX2lSACa1iOmQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.3.tgz", + "integrity": "sha512-tMD7NnbAolWPzQlJQJjVFh/fNH3K/KnA7K8gv2dJWCwwnaK6DFCYST1QXYWfu5V0cDwarWC8Sf/cfMHniNq21A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.3.tgz", + "integrity": "sha512-u5KsqxOxjEeIbn7bUK1MPM34jrnPwjeqgyin4/N6e/KzXKfpE9Mi0nCxcQjaM9lLmPcHmn/xx1yOjgTMtu1jWQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.3.tgz", + "integrity": "sha512-vo54aXwjpTtsAnb3ca7Yxs9t2INZg7QdXN/7yaoG7nPGbOBXYXQY41Km+S1Ov26vzOAzLcAjmMdjyEqS1JkVhw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.3.tgz", + "integrity": "sha512-HI+PIVZ+m+9AgpnY3pt6rinUdRYrGHvmVdsNQ4odNqQ/eRF78DVpMR7mOq7nW06QxpczibwBmeQzB68wJ+4W4A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.3.tgz", + "integrity": "sha512-vRByotbdMo3Wdi+8oC2nVxtc3RkkFKrGaok+a62AT8lz/YBuQjaVYAS5Zcs3tPzW43Vsf9J0wehJbUY5xRSekA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.55.2", + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.3.tgz", + "integrity": "sha512-POZHq7UeuzMJljC5NjKi8vKMFN6/5EOqcX1yGntNLp7rUTpBAXQ1hW8kWPFxYLv07QMcNM75xqVLGPWQq6TKFA==", "cpu": [ "x64" ], @@ -3504,7 +5185,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.55.2", + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.3.tgz", + "integrity": "sha512-aPFONczE4fUFKNXszdvnd2GqKEYQdV5oEsIbKPujJmWlCI9zEsv1Otig8RKK+X9bed9gFUN6LAeN4ZcNuu4zjg==", "cpu": [ "x64" ], @@ -3517,11 +5200,15 @@ }, "node_modules/@sinclair/typebox": { "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", "dev": true, "license": "MIT" }, "node_modules/@sinonjs/commons": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -3530,6 +5217,8 @@ }, "node_modules/@sinonjs/fake-timers": { "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -3538,10 +5227,14 @@ }, "node_modules/@socket.io/component-emitter": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", "license": "MIT" }, "node_modules/@socket.io/redis-adapter": { "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@socket.io/redis-adapter/-/redis-adapter-8.3.0.tgz", + "integrity": "sha512-ly0cra+48hDmChxmIpnESKrc94LjRL80TEmZVscuQ/WWkRP81nNj8W8cCGMqbI4L6NCuAaPRSzZF1a9GlAxxnA==", "license": "MIT", "dependencies": { "debug": "~4.3.1", @@ -3557,6 +5250,8 @@ }, "node_modules/@socket.io/redis-emitter": { "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/redis-emitter/-/redis-emitter-5.1.0.tgz", + "integrity": "sha512-QQUFPBq6JX7JIuM/X1811ymKlAfwufnQ8w6G2/59Jaqp09hdF1GJ/+e8eo/XdcmT0TqkvcSa2TT98ggTXa5QYw==", "license": "MIT", "dependencies": { "debug": "~4.3.1", @@ -3566,14 +5261,20 @@ }, "node_modules/@standard-schema/spec": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", "license": "MIT" }, "node_modules/@standard-schema/utils": { "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz", + "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", "license": "MIT" }, "node_modules/@tanstack/query-core": { "version": "5.90.19", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.19.tgz", + "integrity": "sha512-GLW5sjPVIvH491VV1ufddnfldyVB+teCnpPIvweEfkpRx7CfUmUGhoh9cdcUKBh/KwVxk22aNEDxeTsvmyB/WA==", "license": "MIT", "funding": { "type": "github", @@ -3582,6 +5283,8 @@ }, "node_modules/@tanstack/react-query": { "version": "5.90.19", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.19.tgz", + "integrity": "sha512-qTZRZ4QyTzQc+M0IzrbKHxSeISUmRB3RPGmao5bT+sI6ayxSRhn0FXEnT5Hg3as8SBFcRosrXXRFB+yAcxVxJQ==", "license": "MIT", "dependencies": { "@tanstack/query-core": "5.90.19" @@ -3596,6 +5299,8 @@ }, "node_modules/@testing-library/dom": { "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", "dev": true, "license": "MIT", "peer": true, @@ -3615,6 +5320,8 @@ }, "node_modules/@testing-library/jest-dom": { "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", + "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==", "dev": true, "license": "MIT", "dependencies": { @@ -3633,11 +5340,15 @@ }, "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", "dev": true, "license": "MIT" }, "node_modules/@testing-library/react": { "version": "14.3.1", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.3.1.tgz", + "integrity": "sha512-H99XjUhWQw0lTgyMN05W3xQG1Nh4lq574D8keFf1dDoNTJgp66VbJozRaczoF+wsiaPJNt/TcnfpLGufGxSrZQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3655,6 +5366,8 @@ }, "node_modules/@testing-library/react/node_modules/@testing-library/dom": { "version": "9.3.4", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz", + "integrity": "sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3673,6 +5386,8 @@ }, "node_modules/@testing-library/react/node_modules/aria-query": { "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -3681,6 +5396,8 @@ }, "node_modules/@testing-library/user-event": { "version": "14.6.1", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz", + "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==", "dev": true, "license": "MIT", "engines": { @@ -3693,31 +5410,43 @@ }, "node_modules/@tsconfig/node10": { "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", "dev": true, "license": "MIT" }, "node_modules/@types/aria-query": { "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", "dev": true, "license": "MIT" }, "node_modules/@types/babel__core": { "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, "license": "MIT", "dependencies": { @@ -3730,6 +5459,8 @@ }, "node_modules/@types/babel__generator": { "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", "dev": true, "license": "MIT", "dependencies": { @@ -3738,6 +5469,8 @@ }, "node_modules/@types/babel__template": { "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, "license": "MIT", "dependencies": { @@ -3747,6 +5480,8 @@ }, "node_modules/@types/babel__traverse": { "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", "dev": true, "license": "MIT", "dependencies": { @@ -3755,6 +5490,8 @@ }, "node_modules/@types/body-parser": { "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", "dev": true, "license": "MIT", "dependencies": { @@ -3764,6 +5501,8 @@ }, "node_modules/@types/compression": { "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-kCFuWS0ebDbmxs0AXYn6e2r2nrGAb5KwQhknjSPSPgJcGd8+HVSILlUyFhGqML2gk39HcG7D1ydW9/qpYkN00Q==", "dev": true, "license": "MIT", "dependencies": { @@ -3773,6 +5512,8 @@ }, "node_modules/@types/connect": { "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, "license": "MIT", "dependencies": { @@ -3788,6 +5529,8 @@ }, "node_modules/@types/cors": { "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", "license": "MIT", "dependencies": { "@types/node": "*" @@ -3795,18 +5538,26 @@ }, "node_modules/@types/d3-array": { "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", "license": "MIT" }, "node_modules/@types/d3-color": { "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", "license": "MIT" }, "node_modules/@types/d3-ease": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", "license": "MIT" }, "node_modules/@types/d3-interpolate": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", "license": "MIT", "dependencies": { "@types/d3-color": "*" @@ -3814,10 +5565,14 @@ }, "node_modules/@types/d3-path": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", "license": "MIT" }, "node_modules/@types/d3-scale": { "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", "license": "MIT", "dependencies": { "@types/d3-time": "*" @@ -3825,6 +5580,8 @@ }, "node_modules/@types/d3-shape": { "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", "license": "MIT", "dependencies": { "@types/d3-path": "*" @@ -3832,14 +5589,20 @@ }, "node_modules/@types/d3-time": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", "license": "MIT" }, "node_modules/@types/d3-timer": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", "license": "MIT" }, "node_modules/@types/debug": { "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", "license": "MIT", "dependencies": { "@types/ms": "*" @@ -3847,10 +5610,14 @@ }, "node_modules/@types/estree": { "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "license": "MIT" }, "node_modules/@types/estree-jsx": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", "license": "MIT", "dependencies": { "@types/estree": "*" @@ -3858,6 +5625,8 @@ }, "node_modules/@types/express": { "version": "4.17.25", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz", + "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", "dev": true, "license": "MIT", "dependencies": { @@ -3869,6 +5638,8 @@ }, "node_modules/@types/express-serve-static-core": { "version": "4.19.8", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.8.tgz", + "integrity": "sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==", "dev": true, "license": "MIT", "dependencies": { @@ -3880,10 +5651,14 @@ }, "node_modules/@types/geojson": { "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", "license": "MIT" }, "node_modules/@types/graceful-fs": { "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3892,6 +5667,8 @@ }, "node_modules/@types/hast": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", "license": "MIT", "dependencies": { "@types/unist": "*" @@ -3899,16 +5676,22 @@ }, "node_modules/@types/http-errors": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", "dev": true, "license": "MIT" }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", "dev": true, "license": "MIT" }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", "dev": true, "license": "MIT", "dependencies": { @@ -3917,6 +5700,8 @@ }, "node_modules/@types/istanbul-reports": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3934,19 +5719,6 @@ "pretty-format": "^30.0.0" } }, - "node_modules/@types/jest/node_modules/@jest/expect-utils": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", - "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/get-type": "30.1.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, "node_modules/@types/jest/node_modules/@jest/schemas": { "version": "30.0.5", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", @@ -3960,25 +5732,6 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@types/jest/node_modules/@jest/types": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", - "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/pattern": "30.0.1", - "@jest/schemas": "30.0.5", - "@types/istanbul-lib-coverage": "^2.0.6", - "@types/istanbul-reports": "^3.0.4", - "@types/node": "*", - "@types/yargs": "^17.0.33", - "chalk": "^4.1.2" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, "node_modules/@types/jest/node_modules/@sinclair/typebox": { "version": "0.34.47", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.47.tgz", @@ -3999,139 +5752,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@types/jest/node_modules/ci-info": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", - "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@types/jest/node_modules/expect": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", - "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/expect-utils": "30.2.0", - "@jest/get-type": "30.1.0", - "jest-matcher-utils": "30.2.0", - "jest-message-util": "30.2.0", - "jest-mock": "30.2.0", - "jest-util": "30.2.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@types/jest/node_modules/jest-diff": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", - "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/diff-sequences": "30.0.1", - "@jest/get-type": "30.1.0", - "chalk": "^4.1.2", - "pretty-format": "30.2.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@types/jest/node_modules/jest-matcher-utils": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", - "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/get-type": "30.1.0", - "chalk": "^4.1.2", - "jest-diff": "30.2.0", - "pretty-format": "30.2.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@types/jest/node_modules/jest-message-util": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", - "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@jest/types": "30.2.0", - "@types/stack-utils": "^2.0.3", - "chalk": "^4.1.2", - "graceful-fs": "^4.2.11", - "micromatch": "^4.0.8", - "pretty-format": "30.2.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.6" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@types/jest/node_modules/jest-mock": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz", - "integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "30.2.0", - "@types/node": "*", - "jest-util": "30.2.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@types/jest/node_modules/jest-util": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", - "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "30.2.0", - "@types/node": "*", - "chalk": "^4.1.2", - "ci-info": "^4.2.0", - "graceful-fs": "^4.2.11", - "picomatch": "^4.0.2" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@types/jest/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/@types/jest/node_modules/pretty-format": { "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", @@ -4156,11 +5776,15 @@ }, "node_modules/@types/json-schema": { "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true, "license": "MIT" }, "node_modules/@types/jsonwebtoken": { "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", + "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==", "dev": true, "license": "MIT", "dependencies": { @@ -4170,6 +5794,8 @@ }, "node_modules/@types/mdast": { "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", "license": "MIT", "dependencies": { "@types/unist": "*" @@ -4184,11 +5810,15 @@ }, "node_modules/@types/mime": { "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", "dev": true, "license": "MIT" }, "node_modules/@types/morgan": { "version": "1.9.10", + "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.10.tgz", + "integrity": "sha512-sS4A1zheMvsADRVfT0lYbJ4S9lmsey8Zo2F7cnbYjWHP67Q0AwMYuuzLlkIM2N8gAbb9cubhIVFwcIN2XyYCkA==", "dev": true, "license": "MIT", "dependencies": { @@ -4197,10 +5827,14 @@ }, "node_modules/@types/ms": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", "license": "MIT" }, "node_modules/@types/node": { "version": "20.19.30", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.30.tgz", + "integrity": "sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==", "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -4208,6 +5842,8 @@ }, "node_modules/@types/passport": { "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.17.tgz", + "integrity": "sha512-aciLyx+wDwT2t2/kJGJR2AEeBz0nJU4WuRX04Wu9Dqc5lSUtwu0WERPHYsLhF9PtseiAMPBGNUOtFjxZ56prsg==", "dev": true, "license": "MIT", "dependencies": { @@ -4216,6 +5852,8 @@ }, "node_modules/@types/passport-jwt": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/passport-jwt/-/passport-jwt-4.0.1.tgz", + "integrity": "sha512-Y0Ykz6nWP4jpxgEUYq8NoVZeCQPo1ZndJLfapI249g1jHChvRfZRO/LS3tqu26YgAS/laI1qx98sYGz0IalRXQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4225,6 +5863,8 @@ }, "node_modules/@types/passport-strategy": { "version": "0.2.38", + "resolved": "https://registry.npmjs.org/@types/passport-strategy/-/passport-strategy-0.2.38.tgz", + "integrity": "sha512-GC6eMqqojOooq993Tmnmp7AUTbbQSgilyvpCYQjT+H6JfG/g6RGc7nXEniZlp0zyKJ0WUdOiZWLBZft9Yug1uA==", "dev": true, "license": "MIT", "dependencies": { @@ -4234,6 +5874,8 @@ }, "node_modules/@types/pg": { "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.16.0.tgz", + "integrity": "sha512-RmhMd/wD+CF8Dfo+cVIy3RR5cl8CyfXQ0tGgW6XBL8L4LM/UTEbNXYRbLwU6w+CgrKBNbrQWt4FUtTfaU5jSYQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4244,20 +5886,28 @@ }, "node_modules/@types/prop-types": { "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", "license": "MIT" }, "node_modules/@types/qs": { "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", "dev": true, "license": "MIT" }, "node_modules/@types/range-parser": { "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", "dev": true, "license": "MIT" }, "node_modules/@types/react": { "version": "18.3.27", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", + "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -4266,6 +5916,8 @@ }, "node_modules/@types/react-dom": { "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", "devOptional": true, "license": "MIT", "peerDependencies": { @@ -4274,11 +5926,15 @@ }, "node_modules/@types/semver": { "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", "dev": true, "license": "MIT" }, "node_modules/@types/send": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4287,6 +5943,8 @@ }, "node_modules/@types/serve-static": { "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", + "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", "dev": true, "license": "MIT", "dependencies": { @@ -4297,6 +5955,8 @@ }, "node_modules/@types/serve-static/node_modules/@types/send": { "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", + "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", "dev": true, "license": "MIT", "dependencies": { @@ -4306,16 +5966,22 @@ }, "node_modules/@types/stack-utils": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", "dev": true, "license": "MIT" }, "node_modules/@types/strip-bom": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==", "dev": true, "license": "MIT" }, "node_modules/@types/strip-json-comments": { "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", + "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", "dev": true, "license": "MIT" }, @@ -4345,18 +6011,26 @@ }, "node_modules/@types/unist": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", "license": "MIT" }, "node_modules/@types/use-sync-external-store": { "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", "license": "MIT" }, "node_modules/@types/webidl-conversions": { "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", "license": "MIT" }, "node_modules/@types/whatwg-url": { "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", "license": "MIT", "dependencies": { "@types/webidl-conversions": "*" @@ -4364,6 +6038,8 @@ }, "node_modules/@types/yargs": { "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", "dev": true, "license": "MIT", "dependencies": { @@ -4372,11 +6048,15 @@ }, "node_modules/@types/yargs-parser": { "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", "dev": true, "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", + "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", "dev": true, "license": "MIT", "dependencies": { @@ -4411,6 +6091,8 @@ }, "node_modules/@typescript-eslint/parser": { "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -4438,6 +6120,8 @@ }, "node_modules/@typescript-eslint/scope-manager": { "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", "dev": true, "license": "MIT", "dependencies": { @@ -4454,6 +6138,8 @@ }, "node_modules/@typescript-eslint/type-utils": { "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", "dev": true, "license": "MIT", "dependencies": { @@ -4480,6 +6166,8 @@ }, "node_modules/@typescript-eslint/types": { "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", "dev": true, "license": "MIT", "engines": { @@ -4492,6 +6180,8 @@ }, "node_modules/@typescript-eslint/typescript-estree": { "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -4519,6 +6209,8 @@ }, "node_modules/@typescript-eslint/utils": { "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4543,6 +6235,8 @@ }, "node_modules/@typescript-eslint/visitor-keys": { "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", "dev": true, "license": "MIT", "dependencies": { @@ -4559,10 +6253,14 @@ }, "node_modules/@ungap/structured-clone": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", "license": "ISC" }, "node_modules/@vitejs/plugin-react": { "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", "dev": true, "license": "MIT", "dependencies": { @@ -4582,6 +6280,8 @@ }, "node_modules/@vitest/expect": { "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.1.tgz", + "integrity": "sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog==", "dev": true, "license": "MIT", "dependencies": { @@ -4595,6 +6295,8 @@ }, "node_modules/@vitest/runner": { "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.1.tgz", + "integrity": "sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA==", "dev": true, "license": "MIT", "dependencies": { @@ -4608,6 +6310,8 @@ }, "node_modules/@vitest/runner/node_modules/p-limit": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz", + "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4622,6 +6326,8 @@ }, "node_modules/@vitest/runner/node_modules/yocto-queue": { "version": "1.2.2", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", + "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", "dev": true, "license": "MIT", "engines": { @@ -4633,6 +6339,8 @@ }, "node_modules/@vitest/snapshot": { "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.1.tgz", + "integrity": "sha512-WvidQuWAzU2p95u8GAKlRMqMyN1yOJkGHnx3M1PL9Raf7AQ1kwLKg04ADlCa3+OXUZE7BceOhVZiuWAbzCKcUQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4646,6 +6354,8 @@ }, "node_modules/@vitest/snapshot/node_modules/ansi-styles": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", "engines": { @@ -4657,6 +6367,8 @@ }, "node_modules/@vitest/snapshot/node_modules/pretty-format": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4670,11 +6382,15 @@ }, "node_modules/@vitest/snapshot/node_modules/react-is": { "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true, "license": "MIT" }, "node_modules/@vitest/spy": { "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.1.tgz", + "integrity": "sha512-MGcMmpGkZebsMZhbQKkAf9CX5zGvjkBTqf8Zx3ApYWXr3wG+QvEu2eXWfnIIWYSJExIp4V9FCKDEeygzkYrXMw==", "dev": true, "license": "MIT", "dependencies": { @@ -4686,6 +6402,8 @@ }, "node_modules/@vitest/utils": { "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.1.tgz", + "integrity": "sha512-jOrrUvXM4Av9ZWiG1EajNto0u96kWAhJ1LmPmJhXXQx/32MecEKd10pOLYgS2BQx1TgkGhloPU1ArDW2vvaY6g==", "dev": true, "license": "MIT", "dependencies": { @@ -4700,6 +6418,8 @@ }, "node_modules/@vitest/utils/node_modules/ansi-styles": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", "engines": { @@ -4711,6 +6431,8 @@ }, "node_modules/@vitest/utils/node_modules/pretty-format": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4724,11 +6446,15 @@ }, "node_modules/@vitest/utils/node_modules/react-is": { "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true, "license": "MIT" }, "node_modules/accepts": { "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "license": "MIT", "dependencies": { "mime-types": "~2.1.34", @@ -4740,6 +6466,8 @@ }, "node_modules/accepts/node_modules/negotiator": { "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -4747,6 +6475,8 @@ }, "node_modules/acorn": { "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", "bin": { @@ -4758,6 +6488,8 @@ }, "node_modules/acorn-jsx": { "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "license": "MIT", "peerDependencies": { @@ -4766,6 +6498,8 @@ }, "node_modules/acorn-walk": { "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", "dev": true, "license": "MIT", "dependencies": { @@ -4777,6 +6511,8 @@ }, "node_modules/agent-base": { "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "dev": true, "license": "MIT", "engines": { @@ -4785,6 +6521,8 @@ }, "node_modules/ajv": { "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -4799,6 +6537,8 @@ }, "node_modules/ajv-formats": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -4814,6 +6554,8 @@ }, "node_modules/ansi-escapes": { "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4828,6 +6570,8 @@ }, "node_modules/ansi-escapes/node_modules/type-fest": { "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { @@ -4839,6 +6583,8 @@ }, "node_modules/ansi-regex": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", "engines": { @@ -4847,6 +6593,8 @@ }, "node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -4861,10 +6609,14 @@ }, "node_modules/any-promise": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", "license": "MIT" }, "node_modules/anymatch": { "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -4876,15 +6628,21 @@ }, "node_modules/arg": { "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", "license": "MIT" }, "node_modules/argparse": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, "license": "Python-2.0" }, "node_modules/aria-hidden": { "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", "license": "MIT", "dependencies": { "tslib": "^2.0.0" @@ -4895,6 +6653,8 @@ }, "node_modules/aria-query": { "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -4903,6 +6663,8 @@ }, "node_modules/array-buffer-byte-length": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", "dev": true, "license": "MIT", "dependencies": { @@ -4918,10 +6680,14 @@ }, "node_modules/array-flatten": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", "license": "MIT" }, "node_modules/array-union": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, "license": "MIT", "engines": { @@ -4937,6 +6703,8 @@ }, "node_modules/assertion-error": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true, "license": "MIT", "engines": { @@ -4945,11 +6713,15 @@ }, "node_modules/asynckit": { "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true, "license": "MIT" }, "node_modules/autoprefixer": { "version": "10.4.23", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.23.tgz", + "integrity": "sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA==", "dev": true, "funding": [ { @@ -4985,6 +6757,8 @@ }, "node_modules/available-typed-arrays": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4999,6 +6773,8 @@ }, "node_modules/babel-jest": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", "dev": true, "license": "MIT", "dependencies": { @@ -5019,6 +6795,8 @@ }, "node_modules/babel-plugin-istanbul": { "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -5034,6 +6812,8 @@ }, "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -5049,6 +6829,8 @@ }, "node_modules/babel-plugin-istanbul/node_modules/semver": { "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "license": "ISC", "bin": { @@ -5057,6 +6839,8 @@ }, "node_modules/babel-plugin-jest-hoist": { "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", "dev": true, "license": "MIT", "dependencies": { @@ -5071,6 +6855,8 @@ }, "node_modules/babel-preset-current-node-syntax": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", "dev": true, "license": "MIT", "dependencies": { @@ -5096,6 +6882,8 @@ }, "node_modules/babel-preset-jest": { "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", "dev": true, "license": "MIT", "dependencies": { @@ -5111,6 +6899,8 @@ }, "node_modules/bail": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", "license": "MIT", "funding": { "type": "github", @@ -5119,18 +6909,24 @@ }, "node_modules/balanced-match": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true, "license": "MIT" }, "node_modules/base64id": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", "license": "MIT", "engines": { "node": "^4.5.0 || >= 5.9" } }, "node_modules/baseline-browser-mapping": { - "version": "2.9.16", + "version": "2.9.17", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.17.tgz", + "integrity": "sha512-agD0MgJFUP/4nvjqzIB29zRPUuCF7Ge6mEv9s8dHrtYD7QWXRcx75rOADE/d5ah1NI+0vkDl0yorDd5U852IQQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -5139,6 +6935,8 @@ }, "node_modules/basic-auth": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", "license": "MIT", "dependencies": { "safe-buffer": "5.1.2" @@ -5149,10 +6947,14 @@ }, "node_modules/basic-auth/node_modules/safe-buffer": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "license": "MIT" }, "node_modules/bcrypt": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz", + "integrity": "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -5165,6 +6967,8 @@ }, "node_modules/bignumber.js": { "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==", "license": "MIT", "engines": { "node": "*" @@ -5172,6 +6976,8 @@ }, "node_modules/binary-extensions": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "license": "MIT", "engines": { "node": ">=8" @@ -5182,6 +6988,8 @@ }, "node_modules/body-parser": { "version": "1.20.4", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", "license": "MIT", "dependencies": { "bytes": "~3.1.2", @@ -5204,6 +7012,8 @@ }, "node_modules/body-parser/node_modules/debug": { "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -5211,10 +7021,14 @@ }, "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, "node_modules/body-parser/node_modules/raw-body": { "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", "license": "MIT", "dependencies": { "bytes": "~3.1.2", @@ -5228,6 +7042,8 @@ }, "node_modules/brace-expansion": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5236,6 +7052,8 @@ }, "node_modules/braces": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -5246,6 +7064,8 @@ }, "node_modules/browserslist": { "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "dev": true, "funding": [ { @@ -5291,6 +7111,8 @@ }, "node_modules/bser": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -5299,6 +7121,8 @@ }, "node_modules/bson": { "version": "6.10.4", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.10.4.tgz", + "integrity": "sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng==", "license": "Apache-2.0", "engines": { "node": ">=16.20.1" @@ -5306,15 +7130,21 @@ }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", "license": "BSD-3-Clause" }, "node_modules/buffer-from": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true, "license": "MIT" }, "node_modules/bytes": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -5322,6 +7152,8 @@ }, "node_modules/cac": { "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", "dev": true, "license": "MIT", "engines": { @@ -5330,6 +7162,8 @@ }, "node_modules/call-bind": { "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", "dev": true, "license": "MIT", "dependencies": { @@ -5347,6 +7181,8 @@ }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -5358,6 +7194,8 @@ }, "node_modules/call-bound": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -5372,6 +7210,8 @@ }, "node_modules/callsites": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, "license": "MIT", "engines": { @@ -5380,6 +7220,8 @@ }, "node_modules/camelcase": { "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, "license": "MIT", "engines": { @@ -5388,6 +7230,8 @@ }, "node_modules/camelcase-css": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", "license": "MIT", "engines": { "node": ">= 6" @@ -5395,6 +7239,8 @@ }, "node_modules/caniuse-lite": { "version": "1.0.30001765", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001765.tgz", + "integrity": "sha512-LWcNtSyZrakjECqmpP4qdg0MMGdN368D7X8XvvAqOcqMv0RxnlqVKZl2V6/mBR68oYMxOZPLw/gO7DuisMHUvQ==", "dev": true, "funding": [ { @@ -5414,6 +7260,8 @@ }, "node_modules/ccount": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", "license": "MIT", "funding": { "type": "github", @@ -5422,6 +7270,8 @@ }, "node_modules/chai": { "version": "4.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", + "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", "dev": true, "license": "MIT", "dependencies": { @@ -5439,6 +7289,8 @@ }, "node_modules/chai/node_modules/type-detect": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", "dev": true, "license": "MIT", "engines": { @@ -5447,6 +7299,8 @@ }, "node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -5462,6 +7316,8 @@ }, "node_modules/char-regex": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true, "license": "MIT", "engines": { @@ -5470,6 +7326,8 @@ }, "node_modules/character-entities": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", "license": "MIT", "funding": { "type": "github", @@ -5478,6 +7336,8 @@ }, "node_modules/character-entities-html4": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", "license": "MIT", "funding": { "type": "github", @@ -5486,6 +7346,8 @@ }, "node_modules/character-entities-legacy": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", "license": "MIT", "funding": { "type": "github", @@ -5494,6 +7356,8 @@ }, "node_modules/character-reference-invalid": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", "license": "MIT", "funding": { "type": "github", @@ -5502,6 +7366,8 @@ }, "node_modules/check-error": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", "dev": true, "license": "MIT", "dependencies": { @@ -5513,6 +7379,8 @@ }, "node_modules/chokidar": { "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "license": "MIT", "dependencies": { "anymatch": "~3.1.2", @@ -5535,6 +7403,8 @@ }, "node_modules/chokidar/node_modules/glob-parent": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -5545,6 +7415,8 @@ }, "node_modules/ci-info": { "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", "dev": true, "funding": [ { @@ -5559,11 +7431,15 @@ }, "node_modules/cjs-module-lexer": { "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", "dev": true, "license": "MIT" }, "node_modules/class-variance-authority": { "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", "license": "Apache-2.0", "dependencies": { "clsx": "^2.1.1" @@ -5574,6 +7450,8 @@ }, "node_modules/cliui": { "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "license": "ISC", "dependencies": { @@ -5587,6 +7465,8 @@ }, "node_modules/clsx": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", "license": "MIT", "engines": { "node": ">=6" @@ -5594,6 +7474,8 @@ }, "node_modules/cluster-key-slot": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", "license": "Apache-2.0", "engines": { "node": ">=0.10.0" @@ -5601,6 +7483,8 @@ }, "node_modules/co": { "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true, "license": "MIT", "engines": { @@ -5610,11 +7494,15 @@ }, "node_modules/collect-v8-coverage": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", "dev": true, "license": "MIT" }, "node_modules/color-convert": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5626,11 +7514,15 @@ }, "node_modules/color-name": { "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, "license": "MIT" }, "node_modules/combined-stream": { "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, "license": "MIT", "dependencies": { @@ -5642,6 +7534,8 @@ }, "node_modules/comma-separated-tokens": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", "license": "MIT", "funding": { "type": "github", @@ -5650,6 +7544,8 @@ }, "node_modules/commander": { "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", "license": "MIT", "engines": { "node": ">= 6" @@ -5667,6 +7563,8 @@ }, "node_modules/compressible": { "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "license": "MIT", "dependencies": { "mime-db": ">= 1.43.0 < 2" @@ -5677,6 +7575,8 @@ }, "node_modules/compression": { "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", "license": "MIT", "dependencies": { "bytes": "3.1.2", @@ -5693,6 +7593,8 @@ }, "node_modules/compression/node_modules/debug": { "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -5700,20 +7602,28 @@ }, "node_modules/compression/node_modules/ms": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, "node_modules/concat-map": { "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true, "license": "MIT" }, "node_modules/confbox": { "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", "dev": true, "license": "MIT" }, "node_modules/content-disposition": { "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" @@ -5724,6 +7634,8 @@ }, "node_modules/content-type": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -5731,11 +7643,15 @@ }, "node_modules/convert-source-map": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true, "license": "MIT" }, "node_modules/cookie": { "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -5743,6 +7659,8 @@ }, "node_modules/cookie-signature": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", "license": "MIT" }, "node_modules/cookiejar": { @@ -5754,10 +7672,14 @@ }, "node_modules/core-util-is": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "license": "MIT" }, "node_modules/cors": { "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", "license": "MIT", "dependencies": { "object-assign": "^4", @@ -5769,6 +7691,8 @@ }, "node_modules/create-jest": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", "dev": true, "license": "MIT", "dependencies": { @@ -5787,13 +7711,35 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/create-jest/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/create-require": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true, "license": "MIT" }, "node_modules/cross-spawn": { "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -5806,11 +7752,15 @@ }, "node_modules/css.escape": { "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", "dev": true, "license": "MIT" }, "node_modules/cssesc": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "license": "MIT", "bin": { "cssesc": "bin/cssesc" @@ -5821,6 +7771,8 @@ }, "node_modules/cssstyle": { "version": "4.6.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", + "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", "dev": true, "license": "MIT", "dependencies": { @@ -5833,15 +7785,21 @@ }, "node_modules/cssstyle/node_modules/rrweb-cssom": { "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", "dev": true, "license": "MIT" }, "node_modules/csstype": { "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "license": "MIT" }, "node_modules/d3-array": { "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", "license": "ISC", "dependencies": { "internmap": "1 - 2" @@ -5852,6 +7810,8 @@ }, "node_modules/d3-color": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", "license": "ISC", "engines": { "node": ">=12" @@ -5859,6 +7819,8 @@ }, "node_modules/d3-delaunay": { "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", "license": "ISC", "dependencies": { "delaunator": "5" @@ -5869,6 +7831,8 @@ }, "node_modules/d3-dispatch": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", "license": "ISC", "engines": { "node": ">=12" @@ -5876,6 +7840,8 @@ }, "node_modules/d3-dsv": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", "license": "ISC", "dependencies": { "commander": "7", @@ -5899,6 +7865,8 @@ }, "node_modules/d3-dsv/node_modules/commander": { "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "license": "MIT", "engines": { "node": ">= 10" @@ -5906,6 +7874,8 @@ }, "node_modules/d3-dsv/node_modules/iconv-lite": { "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -5916,6 +7886,8 @@ }, "node_modules/d3-ease": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", "license": "BSD-3-Clause", "engines": { "node": ">=12" @@ -5923,6 +7895,8 @@ }, "node_modules/d3-force": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", "license": "ISC", "dependencies": { "d3-dispatch": "1 - 3", @@ -5935,6 +7909,8 @@ }, "node_modules/d3-format": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", "license": "ISC", "engines": { "node": ">=12" @@ -5942,6 +7918,8 @@ }, "node_modules/d3-geo": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", "license": "ISC", "dependencies": { "d3-array": "2.5.0 - 3" @@ -5952,6 +7930,8 @@ }, "node_modules/d3-geo-projection": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/d3-geo-projection/-/d3-geo-projection-4.0.0.tgz", + "integrity": "sha512-p0bK60CEzph1iqmnxut7d/1kyTmm3UWtPlwdkM31AU+LW+BXazd5zJdoCn7VFxNCHXRngPHRnsNn5uGjLRGndg==", "license": "ISC", "dependencies": { "commander": "7", @@ -5971,6 +7951,8 @@ }, "node_modules/d3-geo-projection/node_modules/commander": { "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "license": "MIT", "engines": { "node": ">= 10" @@ -5978,6 +7960,8 @@ }, "node_modules/d3-hierarchy": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", "license": "ISC", "engines": { "node": ">=12" @@ -5985,6 +7969,8 @@ }, "node_modules/d3-interpolate": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", "license": "ISC", "dependencies": { "d3-color": "1 - 3" @@ -5995,6 +7981,8 @@ }, "node_modules/d3-path": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", "license": "ISC", "engines": { "node": ">=12" @@ -6002,6 +7990,8 @@ }, "node_modules/d3-quadtree": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", "license": "ISC", "engines": { "node": ">=12" @@ -6009,6 +7999,8 @@ }, "node_modules/d3-scale": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", "license": "ISC", "dependencies": { "d3-array": "2.10.0 - 3", @@ -6023,6 +8015,8 @@ }, "node_modules/d3-scale-chromatic": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", "license": "ISC", "dependencies": { "d3-color": "1 - 3", @@ -6034,6 +8028,8 @@ }, "node_modules/d3-shape": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", "license": "ISC", "dependencies": { "d3-path": "^3.1.0" @@ -6044,6 +8040,8 @@ }, "node_modules/d3-time": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", "license": "ISC", "dependencies": { "d3-array": "2 - 3" @@ -6054,6 +8052,8 @@ }, "node_modules/d3-time-format": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", "license": "ISC", "dependencies": { "d3-time": "1 - 3" @@ -6064,6 +8064,8 @@ }, "node_modules/d3-timer": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", "license": "ISC", "engines": { "node": ">=12" @@ -6071,6 +8073,8 @@ }, "node_modules/data-urls": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", "dev": true, "license": "MIT", "dependencies": { @@ -6083,6 +8087,8 @@ }, "node_modules/date-fns": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", "license": "MIT", "funding": { "type": "github", @@ -6091,10 +8097,14 @@ }, "node_modules/date-fns-jalali": { "version": "4.1.0-0", + "resolved": "https://registry.npmjs.org/date-fns-jalali/-/date-fns-jalali-4.1.0-0.tgz", + "integrity": "sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==", "license": "MIT" }, "node_modules/debug": { "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -6110,15 +8120,21 @@ }, "node_modules/decimal.js": { "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", "dev": true, "license": "MIT" }, "node_modules/decimal.js-light": { "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", "license": "MIT" }, "node_modules/decode-named-character-reference": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", "license": "MIT", "dependencies": { "character-entities": "^2.0.0" @@ -6130,6 +8146,8 @@ }, "node_modules/dedent": { "version": "1.7.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.1.tgz", + "integrity": "sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg==", "dev": true, "license": "MIT", "peerDependencies": { @@ -6143,6 +8161,8 @@ }, "node_modules/deep-eql": { "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", "dev": true, "license": "MIT", "dependencies": { @@ -6154,6 +8174,8 @@ }, "node_modules/deep-equal": { "version": "2.2.3", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", + "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", "dev": true, "license": "MIT", "dependencies": { @@ -6185,16 +8207,22 @@ }, "node_modules/deep-equal/node_modules/isarray": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true, "license": "MIT" }, "node_modules/deep-is": { "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true, "license": "MIT" }, "node_modules/deepmerge": { "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, "license": "MIT", "engines": { @@ -6203,6 +8231,8 @@ }, "node_modules/define-data-property": { "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, "license": "MIT", "dependencies": { @@ -6219,6 +8249,8 @@ }, "node_modules/define-properties": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, "license": "MIT", "dependencies": { @@ -6235,6 +8267,8 @@ }, "node_modules/delaunator": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", "license": "ISC", "dependencies": { "robust-predicates": "^3.0.2" @@ -6242,6 +8276,8 @@ }, "node_modules/delayed-stream": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, "license": "MIT", "engines": { @@ -6250,6 +8286,8 @@ }, "node_modules/denque": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", "license": "Apache-2.0", "engines": { "node": ">=0.10" @@ -6257,6 +8295,8 @@ }, "node_modules/depd": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -6264,6 +8304,8 @@ }, "node_modules/dequal": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "license": "MIT", "engines": { "node": ">=6" @@ -6271,6 +8313,8 @@ }, "node_modules/destroy": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "license": "MIT", "engines": { "node": ">= 0.8", @@ -6279,6 +8323,8 @@ }, "node_modules/detect-newline": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true, "license": "MIT", "engines": { @@ -6287,10 +8333,14 @@ }, "node_modules/detect-node-es": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", "license": "MIT" }, "node_modules/devlop": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", "license": "MIT", "dependencies": { "dequal": "^2.0.0" @@ -6313,10 +8363,14 @@ }, "node_modules/didyoumean": { "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", "license": "Apache-2.0" }, "node_modules/diff": { "version": "4.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -6325,6 +8379,8 @@ }, "node_modules/diff-sequences": { "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", "dev": true, "license": "MIT", "engines": { @@ -6333,6 +8389,8 @@ }, "node_modules/dir-glob": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, "license": "MIT", "dependencies": { @@ -6344,10 +8402,14 @@ }, "node_modules/dlv": { "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", "license": "MIT" }, "node_modules/doctrine": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -6359,11 +8421,15 @@ }, "node_modules/dom-accessibility-api": { "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", "dev": true, "license": "MIT" }, "node_modules/dotenv": { "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -6374,6 +8440,8 @@ }, "node_modules/dunder-proto": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -6386,6 +8454,8 @@ }, "node_modules/dynamic-dedupe": { "version": "0.3.0", + "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", + "integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6394,6 +8464,8 @@ }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" @@ -6401,15 +8473,21 @@ }, "node_modules/ee-first": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "license": "MIT" }, "node_modules/electron-to-chromium": { "version": "1.5.267", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", + "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", "dev": true, "license": "ISC" }, "node_modules/emittery": { "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", "dev": true, "license": "MIT", "engines": { @@ -6421,11 +8499,15 @@ }, "node_modules/emoji-regex": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, "license": "MIT" }, "node_modules/encodeurl": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -6433,6 +8515,8 @@ }, "node_modules/engine.io": { "version": "6.6.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.5.tgz", + "integrity": "sha512-2RZdgEbXmp5+dVbRm0P7HQUImZpICccJy7rN7Tv+SFa55pH+lxnuw6/K1ZxxBfHoYpSkHLAO92oa8O4SwFXA2A==", "license": "MIT", "dependencies": { "@types/cors": "^2.8.12", @@ -6451,6 +8535,8 @@ }, "node_modules/engine.io-client": { "version": "6.6.4", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.4.tgz", + "integrity": "sha512-+kjUJnZGwzewFDw951CDWcwj35vMNf2fcj7xQWOctq1F2i1jkDdVvdFG9kM/BEChymCH36KgjnW0NsL58JYRxw==", "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", @@ -6462,6 +8548,8 @@ }, "node_modules/engine.io-client/node_modules/debug": { "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -6477,6 +8565,8 @@ }, "node_modules/engine.io-client/node_modules/ws": { "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -6496,6 +8586,8 @@ }, "node_modules/engine.io-parser": { "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -6503,6 +8595,8 @@ }, "node_modules/engine.io/node_modules/debug": { "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -6518,6 +8612,8 @@ }, "node_modules/engine.io/node_modules/ws": { "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -6537,6 +8633,8 @@ }, "node_modules/entities": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -6548,6 +8646,8 @@ }, "node_modules/error-ex": { "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6556,6 +8656,8 @@ }, "node_modules/es-define-property": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -6563,6 +8665,8 @@ }, "node_modules/es-errors": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -6570,6 +8674,8 @@ }, "node_modules/es-get-iterator": { "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", "dev": true, "license": "MIT", "dependencies": { @@ -6589,11 +8695,15 @@ }, "node_modules/es-get-iterator/node_modules/isarray": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true, "license": "MIT" }, "node_modules/es-object-atoms": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -6604,6 +8714,8 @@ }, "node_modules/es-set-tostringtag": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "dev": true, "license": "MIT", "dependencies": { @@ -6618,6 +8730,8 @@ }, "node_modules/es-toolkit": { "version": "1.44.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.44.0.tgz", + "integrity": "sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg==", "license": "MIT", "workspaces": [ "docs", @@ -6626,6 +8740,8 @@ }, "node_modules/esbuild": { "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", "devOptional": true, "hasInstallScript": true, "license": "MIT", @@ -6666,6 +8782,8 @@ }, "node_modules/escalade": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "license": "MIT", "engines": { "node": ">=6" @@ -6673,10 +8791,14 @@ }, "node_modules/escape-html": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", "license": "MIT" }, "node_modules/escape-string-regexp": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "license": "MIT", "engines": { @@ -6688,6 +8810,9 @@ }, "node_modules/eslint": { "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", "dependencies": { @@ -6742,6 +8867,8 @@ }, "node_modules/eslint-plugin-react-hooks": { "version": "4.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", + "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", "dev": true, "license": "MIT", "engines": { @@ -6753,6 +8880,8 @@ }, "node_modules/eslint-plugin-react-refresh": { "version": "0.4.26", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.26.tgz", + "integrity": "sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==", "dev": true, "license": "MIT", "peerDependencies": { @@ -6761,6 +8890,8 @@ }, "node_modules/eslint-scope": { "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -6776,6 +8907,8 @@ }, "node_modules/eslint-visitor-keys": { "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "license": "Apache-2.0", "engines": { @@ -6787,6 +8920,8 @@ }, "node_modules/eslint/node_modules/ajv": { "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", "dependencies": { @@ -6802,6 +8937,8 @@ }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -6811,11 +8948,15 @@ }, "node_modules/eslint/node_modules/json-schema-traverse": { "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, "license": "MIT" }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", "dependencies": { @@ -6827,6 +8968,8 @@ }, "node_modules/espree": { "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -6843,6 +8986,8 @@ }, "node_modules/esprima": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, "license": "BSD-2-Clause", "bin": { @@ -6855,6 +9000,8 @@ }, "node_modules/esquery": { "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -6866,6 +9013,8 @@ }, "node_modules/esrecurse": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -6877,6 +9026,8 @@ }, "node_modules/estraverse": { "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -6885,6 +9036,8 @@ }, "node_modules/estree-util-is-identifier-name": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", "license": "MIT", "funding": { "type": "opencollective", @@ -6893,6 +9046,8 @@ }, "node_modules/estree-walker": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", "dev": true, "license": "MIT", "dependencies": { @@ -6901,6 +9056,8 @@ }, "node_modules/esutils": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -6909,6 +9066,8 @@ }, "node_modules/etag": { "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -6916,10 +9075,14 @@ }, "node_modules/eventemitter3": { "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", "license": "MIT" }, "node_modules/eventsource": { "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", "license": "MIT", "dependencies": { "eventsource-parser": "^3.0.1" @@ -6930,6 +9093,8 @@ }, "node_modules/eventsource-parser": { "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", "license": "MIT", "engines": { "node": ">=18.0.0" @@ -6937,6 +9102,8 @@ }, "node_modules/execa": { "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "license": "MIT", "dependencies": { @@ -6959,28 +9126,35 @@ }, "node_modules/exit": { "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "dev": true, "engines": { "node": ">= 0.8.0" } }, "node_modules/expect": { - "version": "29.7.0", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", + "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/expect-utils": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0" + "@jest/expect-utils": "30.2.0", + "@jest/get-type": "30.1.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-util": "30.2.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/express": { "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", "license": "MIT", "dependencies": { "accepts": "~1.3.8", @@ -7025,6 +9199,8 @@ }, "node_modules/express-rate-limit": { "version": "7.5.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz", + "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==", "license": "MIT", "engines": { "node": ">= 16" @@ -7038,6 +9214,8 @@ }, "node_modules/express/node_modules/debug": { "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -7045,18 +9223,26 @@ }, "node_modules/express/node_modules/ms": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, "node_modules/extend": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "license": "MIT" }, "node_modules/fast-deep-equal": { "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "license": "MIT" }, "node_modules/fast-glob": { "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -7071,6 +9257,8 @@ }, "node_modules/fast-glob/node_modules/glob-parent": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -7081,15 +9269,21 @@ }, "node_modules/fast-json-patch": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", + "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==", "license": "MIT" }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true, "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true, "license": "MIT" }, @@ -7102,6 +9296,8 @@ }, "node_modules/fast-uri": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", "funding": [ { "type": "github", @@ -7116,6 +9312,8 @@ }, "node_modules/fastq": { "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -7123,6 +9321,8 @@ }, "node_modules/fb-watchman": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -7131,6 +9331,8 @@ }, "node_modules/file-entry-cache": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, "license": "MIT", "dependencies": { @@ -7142,6 +9344,8 @@ }, "node_modules/fill-range": { "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -7152,6 +9356,8 @@ }, "node_modules/finalhandler": { "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", "license": "MIT", "dependencies": { "debug": "2.6.9", @@ -7168,6 +9374,8 @@ }, "node_modules/finalhandler/node_modules/debug": { "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -7175,10 +9383,14 @@ }, "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, "node_modules/find-up": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "license": "MIT", "dependencies": { @@ -7194,6 +9406,8 @@ }, "node_modules/flat-cache": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, "license": "MIT", "dependencies": { @@ -7207,11 +9421,15 @@ }, "node_modules/flatted": { "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", "dev": true, "license": "ISC" }, "node_modules/for-each": { "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "dev": true, "license": "MIT", "dependencies": { @@ -7226,6 +9444,8 @@ }, "node_modules/form-data": { "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", "dev": true, "license": "MIT", "dependencies": { @@ -7259,6 +9479,8 @@ }, "node_modules/forwarded": { "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -7266,6 +9488,8 @@ }, "node_modules/fraction.js": { "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", "dev": true, "license": "MIT", "engines": { @@ -7278,6 +9502,8 @@ }, "node_modules/fresh": { "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -7285,11 +9511,29 @@ }, "node_modules/fs.realpath": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true, "license": "ISC" }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7297,6 +9541,8 @@ }, "node_modules/functions-have-names": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, "license": "MIT", "funding": { @@ -7305,6 +9551,8 @@ }, "node_modules/gensync": { "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, "license": "MIT", "engines": { @@ -7313,6 +9561,8 @@ }, "node_modules/get-caller-file": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" @@ -7320,6 +9570,8 @@ }, "node_modules/get-east-asian-width": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", "license": "MIT", "engines": { "node": ">=18" @@ -7330,6 +9582,8 @@ }, "node_modules/get-func-name": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true, "license": "MIT", "engines": { @@ -7338,6 +9592,8 @@ }, "node_modules/get-intrinsic": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -7360,6 +9616,8 @@ }, "node_modules/get-nonce": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", "license": "MIT", "engines": { "node": ">=6" @@ -7367,6 +9625,8 @@ }, "node_modules/get-package-type": { "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, "license": "MIT", "engines": { @@ -7375,6 +9635,8 @@ }, "node_modules/get-proto": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -7386,6 +9648,8 @@ }, "node_modules/get-stream": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, "license": "MIT", "engines": { @@ -7397,6 +9661,8 @@ }, "node_modules/get-tsconfig": { "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -7408,6 +9674,9 @@ }, "node_modules/glob": { "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "license": "ISC", "dependencies": { @@ -7427,6 +9696,8 @@ }, "node_modules/glob-parent": { "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "license": "ISC", "dependencies": { "is-glob": "^4.0.3" @@ -7437,6 +9708,8 @@ }, "node_modules/glob/node_modules/brace-expansion": { "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -7446,6 +9719,8 @@ }, "node_modules/glob/node_modules/minimatch": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", "dependencies": { @@ -7457,6 +9732,8 @@ }, "node_modules/globals": { "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7471,6 +9748,8 @@ }, "node_modules/globby": { "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "license": "MIT", "dependencies": { @@ -7490,6 +9769,8 @@ }, "node_modules/gopd": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -7500,11 +9781,15 @@ }, "node_modules/graceful-fs": { "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true, "license": "ISC" }, "node_modules/graphemer": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true, "license": "MIT" }, @@ -7532,6 +9817,8 @@ }, "node_modules/has-bigints": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", "dev": true, "license": "MIT", "engines": { @@ -7543,6 +9830,8 @@ }, "node_modules/has-flag": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "license": "MIT", "engines": { @@ -7551,6 +9840,8 @@ }, "node_modules/has-property-descriptors": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, "license": "MIT", "dependencies": { @@ -7562,6 +9853,8 @@ }, "node_modules/has-symbols": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -7572,6 +9865,8 @@ }, "node_modules/has-tostringtag": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, "license": "MIT", "dependencies": { @@ -7586,6 +9881,8 @@ }, "node_modules/hasown": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -7596,6 +9893,8 @@ }, "node_modules/hast-util-to-jsx-runtime": { "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", @@ -7621,6 +9920,8 @@ }, "node_modules/hast-util-whitespace": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" @@ -7632,6 +9933,8 @@ }, "node_modules/helmet": { "version": "7.2.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.2.0.tgz", + "integrity": "sha512-ZRiwvN089JfMXokizgqEPXsl2Guk094yExfoDXR0cBYWxtBbaSww/w+vT4WEJsBW2iTUi1GgZ6swmoug3Oy4Xw==", "license": "MIT", "engines": { "node": ">=16.0.0" @@ -7647,6 +9950,8 @@ }, "node_modules/hono": { "version": "4.11.4", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.4.tgz", + "integrity": "sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA==", "license": "MIT", "peer": true, "engines": { @@ -7655,6 +9960,8 @@ }, "node_modules/html-encoding-sniffer": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7666,11 +9973,15 @@ }, "node_modules/html-escaper": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true, "license": "MIT" }, "node_modules/html-url-attributes": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", + "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", "license": "MIT", "funding": { "type": "opencollective", @@ -7679,6 +9990,8 @@ }, "node_modules/http-errors": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "license": "MIT", "dependencies": { "depd": "~2.0.0", @@ -7697,6 +10010,8 @@ }, "node_modules/http-proxy-agent": { "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "dev": true, "license": "MIT", "dependencies": { @@ -7709,6 +10024,8 @@ }, "node_modules/https-proxy-agent": { "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "dev": true, "license": "MIT", "dependencies": { @@ -7721,6 +10038,8 @@ }, "node_modules/human-signals": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, "license": "Apache-2.0", "engines": { @@ -7729,6 +10048,8 @@ }, "node_modules/iconv-lite": { "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" @@ -7739,6 +10060,8 @@ }, "node_modules/ignore": { "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", "engines": { @@ -7747,6 +10070,8 @@ }, "node_modules/immer": { "version": "10.2.0", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz", + "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==", "license": "MIT", "funding": { "type": "opencollective", @@ -7755,6 +10080,8 @@ }, "node_modules/import-fresh": { "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7770,6 +10097,8 @@ }, "node_modules/import-local": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, "license": "MIT", "dependencies": { @@ -7788,6 +10117,8 @@ }, "node_modules/imurmurhash": { "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, "license": "MIT", "engines": { @@ -7796,6 +10127,8 @@ }, "node_modules/indent-string": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true, "license": "MIT", "engines": { @@ -7804,6 +10137,9 @@ }, "node_modules/inflight": { "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, "license": "ISC", "dependencies": { @@ -7813,14 +10149,20 @@ }, "node_modules/inherits": { "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, "node_modules/inline-style-parser": { "version": "0.2.7", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", + "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", "license": "MIT" }, "node_modules/internal-slot": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", "dev": true, "license": "MIT", "dependencies": { @@ -7834,6 +10176,8 @@ }, "node_modules/internmap": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", "license": "ISC", "engines": { "node": ">=12" @@ -7841,6 +10185,8 @@ }, "node_modules/ioredis": { "version": "5.9.2", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.9.2.tgz", + "integrity": "sha512-tAAg/72/VxOUW7RQSX1pIxJVucYKcjFjfvj60L57jrZpYCHC3XN0WCQ3sNYL4Gmvv+7GPvTAjc+KSdeNuE8oWQ==", "license": "MIT", "dependencies": { "@ioredis/commands": "1.5.0", @@ -7863,6 +10209,8 @@ }, "node_modules/ipaddr.js": { "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "license": "MIT", "engines": { "node": ">= 0.10" @@ -7870,6 +10218,8 @@ }, "node_modules/is-alphabetical": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", "license": "MIT", "funding": { "type": "github", @@ -7878,6 +10228,8 @@ }, "node_modules/is-alphanumerical": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", "license": "MIT", "dependencies": { "is-alphabetical": "^2.0.0", @@ -7890,6 +10242,8 @@ }, "node_modules/is-arguments": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", "dev": true, "license": "MIT", "dependencies": { @@ -7905,6 +10259,8 @@ }, "node_modules/is-array-buffer": { "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", "dev": true, "license": "MIT", "dependencies": { @@ -7921,11 +10277,15 @@ }, "node_modules/is-arrayish": { "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true, "license": "MIT" }, "node_modules/is-bigint": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7940,6 +10300,8 @@ }, "node_modules/is-binary-path": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" @@ -7950,6 +10312,8 @@ }, "node_modules/is-boolean-object": { "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", "dev": true, "license": "MIT", "dependencies": { @@ -7965,6 +10329,8 @@ }, "node_modules/is-callable": { "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, "license": "MIT", "engines": { @@ -7976,6 +10342,8 @@ }, "node_modules/is-core-module": { "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "license": "MIT", "dependencies": { "hasown": "^2.0.2" @@ -7989,6 +10357,8 @@ }, "node_modules/is-date-object": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "dev": true, "license": "MIT", "dependencies": { @@ -8004,6 +10374,8 @@ }, "node_modules/is-decimal": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", "license": "MIT", "funding": { "type": "github", @@ -8012,6 +10384,8 @@ }, "node_modules/is-extglob": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -8019,6 +10393,8 @@ }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, "license": "MIT", "engines": { @@ -8027,6 +10403,8 @@ }, "node_modules/is-generator-fn": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true, "license": "MIT", "engines": { @@ -8035,6 +10413,8 @@ }, "node_modules/is-glob": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -8045,6 +10425,8 @@ }, "node_modules/is-hexadecimal": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", "license": "MIT", "funding": { "type": "github", @@ -8053,6 +10435,8 @@ }, "node_modules/is-map": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", "dev": true, "license": "MIT", "engines": { @@ -8064,6 +10448,8 @@ }, "node_modules/is-number": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "license": "MIT", "engines": { "node": ">=0.12.0" @@ -8071,6 +10457,8 @@ }, "node_modules/is-number-object": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", "dev": true, "license": "MIT", "dependencies": { @@ -8086,6 +10474,8 @@ }, "node_modules/is-path-inside": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, "license": "MIT", "engines": { @@ -8094,6 +10484,8 @@ }, "node_modules/is-plain-obj": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", "license": "MIT", "engines": { "node": ">=12" @@ -8104,15 +10496,21 @@ }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true, "license": "MIT" }, "node_modules/is-promise": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "license": "MIT" }, "node_modules/is-regex": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "dev": true, "license": "MIT", "dependencies": { @@ -8130,6 +10528,8 @@ }, "node_modules/is-set": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", "dev": true, "license": "MIT", "engines": { @@ -8141,6 +10541,8 @@ }, "node_modules/is-shared-array-buffer": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", "dev": true, "license": "MIT", "dependencies": { @@ -8155,6 +10557,8 @@ }, "node_modules/is-stream": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, "license": "MIT", "engines": { @@ -8166,6 +10570,8 @@ }, "node_modules/is-string": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", "dev": true, "license": "MIT", "dependencies": { @@ -8181,6 +10587,8 @@ }, "node_modules/is-symbol": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", "dev": true, "license": "MIT", "dependencies": { @@ -8197,6 +10605,8 @@ }, "node_modules/is-weakmap": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", "dev": true, "license": "MIT", "engines": { @@ -8208,6 +10618,8 @@ }, "node_modules/is-weakset": { "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8223,14 +10635,20 @@ }, "node_modules/isarray": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -8239,6 +10657,8 @@ }, "node_modules/istanbul-lib-instrument": { "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -8254,6 +10674,8 @@ }, "node_modules/istanbul-lib-report": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -8267,6 +10689,8 @@ }, "node_modules/istanbul-lib-source-maps": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -8280,6 +10704,8 @@ }, "node_modules/istanbul-reports": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -8292,6 +10718,8 @@ }, "node_modules/jest": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, "license": "MIT", "dependencies": { @@ -8317,6 +10745,8 @@ }, "node_modules/jest-changed-files": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", "dev": true, "license": "MIT", "dependencies": { @@ -8328,8 +10758,28 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-changed-files/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/jest-circus": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", "dev": true, "license": "MIT", "dependencies": { @@ -8360,6 +10810,8 @@ }, "node_modules/jest-circus/node_modules/ansi-styles": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", "engines": { @@ -8369,8 +10821,81 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/jest-circus/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/jest-circus/node_modules/pretty-format": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8384,11 +10909,15 @@ }, "node_modules/jest-circus/node_modules/react-is": { "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true, "license": "MIT" }, "node_modules/jest-cli": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", "dev": true, "license": "MIT", "dependencies": { @@ -8419,8 +10948,28 @@ } } }, + "node_modules/jest-cli/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/jest-config": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8465,6 +11014,8 @@ }, "node_modules/jest-config/node_modules/ansi-styles": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", "engines": { @@ -8474,8 +11025,28 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/jest-config/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/jest-config/node_modules/pretty-format": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8489,25 +11060,51 @@ }, "node_modules/jest-config/node_modules/react-is": { "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true, "license": "MIT" }, "node_modules/jest-diff": { - "version": "29.7.0", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", + "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" + "@jest/diff-sequences": "30.0.1", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.2.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "node_modules/jest-diff/node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-diff/node_modules/@sinclair/typebox": { + "version": "0.34.47", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.47.tgz", + "integrity": "sha512-ZGIBQ+XDvO5JQku9wmwtabcVTHJsgSWAHYtVuM9pBNNR5E88v6Jcj/llpmsjivig5X8A8HHOb4/mbEKPS5EvAw==", + "dev": true, + "license": "MIT" + }, "node_modules/jest-diff/node_modules/ansi-styles": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", "engines": { @@ -8518,25 +11115,31 @@ } }, "node_modules/jest-diff/node_modules/pretty-format": { - "version": "29.7.0", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-diff/node_modules/react-is": { "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true, "license": "MIT" }, "node_modules/jest-docblock": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", "dev": true, "license": "MIT", "dependencies": { @@ -8548,6 +11151,8 @@ }, "node_modules/jest-each": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8563,6 +11168,8 @@ }, "node_modules/jest-each/node_modules/ansi-styles": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", "engines": { @@ -8572,8 +11179,28 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/jest-each/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/jest-each/node_modules/pretty-format": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8587,11 +11214,15 @@ }, "node_modules/jest-each/node_modules/react-is": { "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true, "license": "MIT" }, "node_modules/jest-environment-node": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", "dev": true, "license": "MIT", "dependencies": { @@ -8606,8 +11237,43 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-environment-node/node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/jest-get-type": { "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", "dev": true, "license": "MIT", "engines": { @@ -8616,6 +11282,8 @@ }, "node_modules/jest-haste-map": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", "dev": true, "license": "MIT", "dependencies": { @@ -8638,8 +11306,28 @@ "fsevents": "^2.3.2" } }, + "node_modules/jest-haste-map/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/jest-leak-detector": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", "dev": true, "license": "MIT", "dependencies": { @@ -8652,6 +11340,8 @@ }, "node_modules/jest-leak-detector/node_modules/ansi-styles": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", "engines": { @@ -8663,6 +11353,8 @@ }, "node_modules/jest-leak-detector/node_modules/pretty-format": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8676,25 +11368,51 @@ }, "node_modules/jest-leak-detector/node_modules/react-is": { "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true, "license": "MIT" }, "node_modules/jest-matcher-utils": { - "version": "29.7.0", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", + "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "jest-diff": "30.2.0", + "pretty-format": "30.2.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "node_modules/jest-matcher-utils/node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/@sinclair/typebox": { + "version": "0.34.47", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.47.tgz", + "integrity": "sha512-ZGIBQ+XDvO5JQku9wmwtabcVTHJsgSWAHYtVuM9pBNNR5E88v6Jcj/llpmsjivig5X8A8HHOb4/mbEKPS5EvAw==", + "dev": true, + "license": "MIT" + }, "node_modules/jest-matcher-utils/node_modules/ansi-styles": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", "engines": { @@ -8705,44 +11423,91 @@ } }, "node_modules/jest-matcher-utils/node_modules/pretty-format": { - "version": "29.7.0", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-matcher-utils/node_modules/react-is": { "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true, "license": "MIT" }, "node_modules/jest-message-util": { - "version": "29.7.0", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", + "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.6.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.2.0", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "micromatch": "^4.0.8", + "pretty-format": "30.2.0", "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "stack-utils": "^2.0.6" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "node_modules/jest-message-util/node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-message-util/node_modules/@jest/types": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", + "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/pattern": "30.0.1", + "@jest/schemas": "30.0.5", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-message-util/node_modules/@sinclair/typebox": { + "version": "0.34.47", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.47.tgz", + "integrity": "sha512-ZGIBQ+XDvO5JQku9wmwtabcVTHJsgSWAHYtVuM9pBNNR5E88v6Jcj/llpmsjivig5X8A8HHOb4/mbEKPS5EvAw==", + "dev": true, + "license": "MIT" + }, "node_modules/jest-message-util/node_modules/ansi-styles": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", "engines": { @@ -8753,38 +11518,85 @@ } }, "node_modules/jest-message-util/node_modules/pretty-format": { - "version": "29.7.0", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-message-util/node_modules/react-is": { "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true, "license": "MIT" }, "node_modules/jest-mock": { - "version": "29.7.0", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz", + "integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "^29.6.3", + "@jest/types": "30.2.0", "@types/node": "*", - "jest-util": "^29.7.0" + "jest-util": "30.2.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "node_modules/jest-mock/node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-mock/node_modules/@jest/types": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", + "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/pattern": "30.0.1", + "@jest/schemas": "30.0.5", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-mock/node_modules/@sinclair/typebox": { + "version": "0.34.47", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.47.tgz", + "integrity": "sha512-ZGIBQ+XDvO5JQku9wmwtabcVTHJsgSWAHYtVuM9pBNNR5E88v6Jcj/llpmsjivig5X8A8HHOb4/mbEKPS5EvAw==", + "dev": true, + "license": "MIT" + }, "node_modules/jest-pnp-resolver": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "dev": true, "license": "MIT", "engines": { @@ -8801,6 +11613,8 @@ }, "node_modules/jest-regex-util": { "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", "dev": true, "license": "MIT", "engines": { @@ -8809,6 +11623,8 @@ }, "node_modules/jest-resolve": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", "dev": true, "license": "MIT", "dependencies": { @@ -8828,6 +11644,8 @@ }, "node_modules/jest-resolve-dependencies": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", "dev": true, "license": "MIT", "dependencies": { @@ -8838,8 +11656,28 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-resolve/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/jest-runner": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8869,8 +11707,84 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-runner/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, "node_modules/jest-runtime": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8901,8 +11815,99 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-runtime/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, "node_modules/jest-snapshot": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", "dev": true, "license": "MIT", "dependencies": { @@ -8931,8 +11936,23 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-snapshot/node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/jest-snapshot/node_modules/ansi-styles": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", "engines": { @@ -8942,26 +11962,80 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-snapshot/node_modules/pretty-format": { + "node_modules/jest-snapshot/node_modules/expect": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-snapshot/node_modules/react-is": { - "version": "18.3.1", - "dev": true, - "license": "MIT" - }, - "node_modules/jest-util": { + "node_modules/jest-snapshot/node_modules/jest-diff": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dev": true, "license": "MIT", "dependencies": { @@ -8976,8 +12050,118 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-snapshot/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-util": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-util/node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-util/node_modules/@jest/types": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", + "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/pattern": "30.0.1", + "@jest/schemas": "30.0.5", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-util/node_modules/@sinclair/typebox": { + "version": "0.34.47", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.47.tgz", + "integrity": "sha512-ZGIBQ+XDvO5JQku9wmwtabcVTHJsgSWAHYtVuM9pBNNR5E88v6Jcj/llpmsjivig5X8A8HHOb4/mbEKPS5EvAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-util/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-util/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/jest-validate": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", "dev": true, "license": "MIT", "dependencies": { @@ -8994,6 +12178,8 @@ }, "node_modules/jest-validate/node_modules/ansi-styles": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", "engines": { @@ -9005,6 +12191,8 @@ }, "node_modules/jest-validate/node_modules/camelcase": { "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, "license": "MIT", "engines": { @@ -9016,6 +12204,8 @@ }, "node_modules/jest-validate/node_modules/pretty-format": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9029,11 +12219,15 @@ }, "node_modules/jest-validate/node_modules/react-is": { "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true, "license": "MIT" }, "node_modules/jest-watcher": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", "dev": true, "license": "MIT", "dependencies": { @@ -9050,8 +12244,28 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-watcher/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/jest-worker": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", "dev": true, "license": "MIT", "dependencies": { @@ -9064,8 +12278,28 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-worker/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/jest-worker/node_modules/supports-color": { "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "license": "MIT", "dependencies": { @@ -9080,6 +12314,8 @@ }, "node_modules/jiti": { "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "license": "MIT", "bin": { "jiti": "bin/jiti.js" @@ -9087,6 +12323,8 @@ }, "node_modules/jose": { "version": "6.1.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz", + "integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" @@ -9094,10 +12332,14 @@ }, "node_modules/js-tokens": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { @@ -9109,6 +12351,8 @@ }, "node_modules/jsdom": { "version": "24.1.3", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-24.1.3.tgz", + "integrity": "sha512-MyL55p3Ut3cXbeBEG7Hcv0mVM8pp8PBNWxRqchZnSfAiES1v1mRnMeFfaHWIPULpwsYfvO+ZmMZz5tGCnjzDUQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9148,6 +12392,8 @@ }, "node_modules/jsesc": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "dev": true, "license": "MIT", "bin": { @@ -9159,33 +12405,47 @@ }, "node_modules/json-buffer": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true, "license": "MIT" }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true, "license": "MIT" }, "node_modules/json-schema-traverse": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "license": "MIT" }, "node_modules/json-schema-typed": { "version": "8.0.2", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", "license": "BSD-2-Clause" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true, "license": "MIT" }, "node_modules/json-stringify-pretty-compact": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-4.0.0.tgz", + "integrity": "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==", "license": "MIT" }, "node_modules/json5": { "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "license": "MIT", "bin": { @@ -9197,6 +12457,8 @@ }, "node_modules/jsonwebtoken": { "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", "license": "MIT", "dependencies": { "jws": "^4.0.1", @@ -9217,6 +12479,8 @@ }, "node_modules/jwa": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", "license": "MIT", "dependencies": { "buffer-equal-constant-time": "^1.0.1", @@ -9226,6 +12490,8 @@ }, "node_modules/jws": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", "license": "MIT", "dependencies": { "jwa": "^2.0.1", @@ -9234,6 +12500,8 @@ }, "node_modules/keyv": { "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, "license": "MIT", "dependencies": { @@ -9242,6 +12510,8 @@ }, "node_modules/kleur": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true, "license": "MIT", "engines": { @@ -9250,6 +12520,8 @@ }, "node_modules/leven": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "dev": true, "license": "MIT", "engines": { @@ -9258,6 +12530,8 @@ }, "node_modules/levn": { "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9270,6 +12544,8 @@ }, "node_modules/lilconfig": { "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", "license": "MIT", "engines": { "node": ">=14" @@ -9280,10 +12556,14 @@ }, "node_modules/lines-and-columns": { "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "license": "MIT" }, "node_modules/local-pkg": { "version": "0.5.1", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.1.tgz", + "integrity": "sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9299,6 +12579,8 @@ }, "node_modules/locate-path": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "license": "MIT", "dependencies": { @@ -9313,34 +12595,50 @@ }, "node_modules/lodash.defaults": { "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", "license": "MIT" }, "node_modules/lodash.includes": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", "license": "MIT" }, "node_modules/lodash.isarguments": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==", "license": "MIT" }, "node_modules/lodash.isboolean": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", "license": "MIT" }, "node_modules/lodash.isinteger": { "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", "license": "MIT" }, "node_modules/lodash.isnumber": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", "license": "MIT" }, "node_modules/lodash.isplainobject": { "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", "license": "MIT" }, "node_modules/lodash.isstring": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", "license": "MIT" }, "node_modules/lodash.memoize": { @@ -9352,15 +12650,21 @@ }, "node_modules/lodash.merge": { "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true, "license": "MIT" }, "node_modules/lodash.once": { "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", "license": "MIT" }, "node_modules/longest-streak": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", "license": "MIT", "funding": { "type": "github", @@ -9369,6 +12673,8 @@ }, "node_modules/loose-envify": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" @@ -9379,6 +12685,8 @@ }, "node_modules/loupe": { "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", "dev": true, "license": "MIT", "dependencies": { @@ -9387,6 +12695,8 @@ }, "node_modules/lru-cache": { "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, "license": "ISC", "dependencies": { @@ -9395,6 +12705,8 @@ }, "node_modules/lucide-react": { "version": "0.562.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.562.0.tgz", + "integrity": "sha512-82hOAu7y0dbVuFfmO4bYF1XEwYk/mEbM5E+b1jgci/udUBEE/R7LF5Ip0CCEmXe8AybRM8L+04eP+LGZeDvkiw==", "license": "ISC", "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" @@ -9402,6 +12714,8 @@ }, "node_modules/lz-string": { "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, "license": "MIT", "bin": { @@ -9410,6 +12724,8 @@ }, "node_modules/magic-string": { "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9418,6 +12734,8 @@ }, "node_modules/make-dir": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, "license": "MIT", "dependencies": { @@ -9432,11 +12750,15 @@ }, "node_modules/make-error": { "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true, "license": "ISC" }, "node_modules/makeerror": { "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -9445,6 +12767,8 @@ }, "node_modules/math-intrinsics": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -9452,6 +12776,8 @@ }, "node_modules/mdast-util-from-markdown": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", + "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -9474,6 +12800,8 @@ }, "node_modules/mdast-util-mdx-expression": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", @@ -9490,6 +12818,8 @@ }, "node_modules/mdast-util-mdx-jsx": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", @@ -9512,6 +12842,8 @@ }, "node_modules/mdast-util-mdxjs-esm": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", @@ -9528,6 +12860,8 @@ }, "node_modules/mdast-util-phrasing": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -9540,6 +12874,8 @@ }, "node_modules/mdast-util-to-hast": { "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -9559,6 +12895,8 @@ }, "node_modules/mdast-util-to-markdown": { "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -9578,6 +12916,8 @@ }, "node_modules/mdast-util-to-string": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0" @@ -9589,6 +12929,8 @@ }, "node_modules/media-typer": { "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -9596,10 +12938,14 @@ }, "node_modules/memory-pager": { "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", "license": "MIT" }, "node_modules/merge-descriptors": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -9607,11 +12953,15 @@ }, "node_modules/merge-stream": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true, "license": "MIT" }, "node_modules/merge2": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "license": "MIT", "engines": { "node": ">= 8" @@ -9619,6 +12969,8 @@ }, "node_modules/methods": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -9626,6 +12978,8 @@ }, "node_modules/micromark": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", "funding": [ { "type": "GitHub Sponsors", @@ -9659,6 +13013,8 @@ }, "node_modules/micromark-core-commonmark": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", "funding": [ { "type": "GitHub Sponsors", @@ -9691,6 +13047,8 @@ }, "node_modules/micromark-factory-destination": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", "funding": [ { "type": "GitHub Sponsors", @@ -9710,6 +13068,8 @@ }, "node_modules/micromark-factory-label": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", "funding": [ { "type": "GitHub Sponsors", @@ -9730,6 +13090,8 @@ }, "node_modules/micromark-factory-space": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", "funding": [ { "type": "GitHub Sponsors", @@ -9748,6 +13110,8 @@ }, "node_modules/micromark-factory-title": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", "funding": [ { "type": "GitHub Sponsors", @@ -9768,6 +13132,8 @@ }, "node_modules/micromark-factory-whitespace": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", "funding": [ { "type": "GitHub Sponsors", @@ -9788,6 +13154,8 @@ }, "node_modules/micromark-util-character": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { "type": "GitHub Sponsors", @@ -9806,6 +13174,8 @@ }, "node_modules/micromark-util-chunked": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", "funding": [ { "type": "GitHub Sponsors", @@ -9823,6 +13193,8 @@ }, "node_modules/micromark-util-classify-character": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", "funding": [ { "type": "GitHub Sponsors", @@ -9842,6 +13214,8 @@ }, "node_modules/micromark-util-combine-extensions": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", "funding": [ { "type": "GitHub Sponsors", @@ -9860,6 +13234,8 @@ }, "node_modules/micromark-util-decode-numeric-character-reference": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", "funding": [ { "type": "GitHub Sponsors", @@ -9877,6 +13253,8 @@ }, "node_modules/micromark-util-decode-string": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", "funding": [ { "type": "GitHub Sponsors", @@ -9897,6 +13275,8 @@ }, "node_modules/micromark-util-encode": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", "funding": [ { "type": "GitHub Sponsors", @@ -9911,6 +13291,8 @@ }, "node_modules/micromark-util-html-tag-name": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", "funding": [ { "type": "GitHub Sponsors", @@ -9925,6 +13307,8 @@ }, "node_modules/micromark-util-normalize-identifier": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", "funding": [ { "type": "GitHub Sponsors", @@ -9942,6 +13326,8 @@ }, "node_modules/micromark-util-resolve-all": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", "funding": [ { "type": "GitHub Sponsors", @@ -9959,6 +13345,8 @@ }, "node_modules/micromark-util-sanitize-uri": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", "funding": [ { "type": "GitHub Sponsors", @@ -9978,6 +13366,8 @@ }, "node_modules/micromark-util-subtokenize": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", "funding": [ { "type": "GitHub Sponsors", @@ -9998,6 +13388,8 @@ }, "node_modules/micromark-util-symbol": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -10012,6 +13404,8 @@ }, "node_modules/micromark-util-types": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", "funding": [ { "type": "GitHub Sponsors", @@ -10026,6 +13420,8 @@ }, "node_modules/micromatch": { "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -10037,6 +13433,8 @@ }, "node_modules/mime": { "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "license": "MIT", "bin": { "mime": "cli.js" @@ -10047,6 +13445,8 @@ }, "node_modules/mime-db": { "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -10054,6 +13454,8 @@ }, "node_modules/mime-types": { "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "license": "MIT", "dependencies": { "mime-db": "1.52.0" @@ -10064,6 +13466,8 @@ }, "node_modules/mime-types/node_modules/mime-db": { "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -10071,6 +13475,8 @@ }, "node_modules/mimic-fn": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, "license": "MIT", "engines": { @@ -10079,6 +13485,8 @@ }, "node_modules/min-indent": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true, "license": "MIT", "engines": { @@ -10087,6 +13495,8 @@ }, "node_modules/minimatch": { "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "license": "ISC", "dependencies": { @@ -10101,6 +13511,8 @@ }, "node_modules/minimist": { "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, "license": "MIT", "funding": { @@ -10109,6 +13521,8 @@ }, "node_modules/mkdirp": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, "license": "MIT", "bin": { @@ -10120,6 +13534,8 @@ }, "node_modules/mlly": { "version": "1.8.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", + "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", "dev": true, "license": "MIT", "dependencies": { @@ -10131,11 +13547,15 @@ }, "node_modules/mlly/node_modules/pathe": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true, "license": "MIT" }, "node_modules/mongodb": { "version": "6.21.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.21.0.tgz", + "integrity": "sha512-URyb/VXMjJ4da46OeSXg+puO39XH9DeQpWCslifrRn9JWugy0D+DvvBvkm2WxmHe61O/H19JM66p1z7RHVkZ6A==", "license": "Apache-2.0", "dependencies": { "@mongodb-js/saslprep": "^1.3.0", @@ -10180,6 +13600,8 @@ }, "node_modules/mongodb-connection-string-url": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.2.tgz", + "integrity": "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==", "license": "Apache-2.0", "dependencies": { "@types/whatwg-url": "^11.0.2", @@ -10188,6 +13610,8 @@ }, "node_modules/morgan": { "version": "1.10.1", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.1.tgz", + "integrity": "sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==", "license": "MIT", "dependencies": { "basic-auth": "~2.0.1", @@ -10202,6 +13626,8 @@ }, "node_modules/morgan/node_modules/debug": { "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -10209,10 +13635,14 @@ }, "node_modules/morgan/node_modules/ms": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, "node_modules/morgan/node_modules/on-finished": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", "license": "MIT", "dependencies": { "ee-first": "1.1.1" @@ -10223,10 +13653,14 @@ }, "node_modules/ms": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, "node_modules/mysql": { "version": "2.18.1", + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", + "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", "license": "MIT", "dependencies": { "bignumber.js": "9.0.0", @@ -10240,10 +13674,14 @@ }, "node_modules/mysql/node_modules/safe-buffer": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "license": "MIT" }, "node_modules/mz": { "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", "license": "MIT", "dependencies": { "any-promise": "^1.0.0", @@ -10253,6 +13691,8 @@ }, "node_modules/nanoid": { "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "funding": [ { "type": "github", @@ -10269,11 +13709,15 @@ }, "node_modules/natural-compare": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true, "license": "MIT" }, "node_modules/negotiator": { "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -10288,6 +13732,8 @@ }, "node_modules/node-addon-api": { "version": "8.5.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz", + "integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==", "license": "MIT", "engines": { "node": "^18 || ^20 || >= 21" @@ -10295,6 +13741,8 @@ }, "node_modules/node-gyp-build": { "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", "license": "MIT", "bin": { "node-gyp-build": "bin.js", @@ -10304,16 +13752,22 @@ }, "node_modules/node-int64": { "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", "dev": true, "license": "MIT" }, "node_modules/node-releases": { "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", "dev": true, "license": "MIT" }, "node_modules/nodemailer": { "version": "6.10.1", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.10.1.tgz", + "integrity": "sha512-Z+iLaBGVaSjbIzQ4pX6XV41HrooLsQ10ZWPUehGmuantvzWoDVBnmsdUcOIDM1t+yPor5pDhVlDESgOMEGxhHA==", "license": "MIT-0", "engines": { "node": ">=6.0.0" @@ -10321,6 +13775,8 @@ }, "node_modules/normalize-path": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -10328,10 +13784,14 @@ }, "node_modules/notepack.io": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/notepack.io/-/notepack.io-3.0.1.tgz", + "integrity": "sha512-TKC/8zH5pXIAMVQio2TvVDTtPRX+DJPHDqjRbxogtFiByHyzKmy96RA0JtCQJ+WouyyL4A10xomQzgbUT+1jCg==", "license": "MIT" }, "node_modules/npm-run-path": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "license": "MIT", "dependencies": { @@ -10343,11 +13803,15 @@ }, "node_modules/nwsapi": { "version": "2.2.23", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.23.tgz", + "integrity": "sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==", "dev": true, "license": "MIT" }, "node_modules/object-assign": { "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -10355,6 +13819,8 @@ }, "node_modules/object-hash": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", "license": "MIT", "engines": { "node": ">= 6" @@ -10362,6 +13828,8 @@ }, "node_modules/object-inspect": { "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -10372,6 +13840,8 @@ }, "node_modules/object-is": { "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", "dev": true, "license": "MIT", "dependencies": { @@ -10387,6 +13857,8 @@ }, "node_modules/object-keys": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true, "license": "MIT", "engines": { @@ -10395,6 +13867,8 @@ }, "node_modules/object.assign": { "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", "dev": true, "license": "MIT", "dependencies": { @@ -10414,6 +13888,8 @@ }, "node_modules/on-finished": { "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "license": "MIT", "dependencies": { "ee-first": "1.1.1" @@ -10424,6 +13900,8 @@ }, "node_modules/on-headers": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -10431,6 +13909,8 @@ }, "node_modules/once": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "license": "ISC", "dependencies": { "wrappy": "1" @@ -10438,6 +13918,8 @@ }, "node_modules/onetime": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, "license": "MIT", "dependencies": { @@ -10452,6 +13934,8 @@ }, "node_modules/optionator": { "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "license": "MIT", "dependencies": { @@ -10468,6 +13952,8 @@ }, "node_modules/p-limit": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "license": "MIT", "dependencies": { @@ -10482,6 +13968,8 @@ }, "node_modules/p-locate": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "license": "MIT", "dependencies": { @@ -10496,6 +13984,8 @@ }, "node_modules/p-try": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, "license": "MIT", "engines": { @@ -10504,6 +13994,8 @@ }, "node_modules/parent-module": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "license": "MIT", "dependencies": { @@ -10515,6 +14007,8 @@ }, "node_modules/parse-entities": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", "license": "MIT", "dependencies": { "@types/unist": "^2.0.0", @@ -10532,10 +14026,14 @@ }, "node_modules/parse-entities/node_modules/@types/unist": { "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", "license": "MIT" }, "node_modules/parse-json": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "license": "MIT", "dependencies": { @@ -10553,6 +14051,8 @@ }, "node_modules/parse5": { "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", "dev": true, "license": "MIT", "dependencies": { @@ -10564,6 +14064,8 @@ }, "node_modules/parseurl": { "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -10571,6 +14073,8 @@ }, "node_modules/passport": { "version": "0.7.0", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz", + "integrity": "sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==", "license": "MIT", "dependencies": { "passport-strategy": "1.x.x", @@ -10587,6 +14091,8 @@ }, "node_modules/passport-jwt": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.1.tgz", + "integrity": "sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==", "license": "MIT", "dependencies": { "jsonwebtoken": "^9.0.0", @@ -10595,12 +14101,16 @@ }, "node_modules/passport-strategy": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==", "engines": { "node": ">= 0.4.0" } }, "node_modules/path-exists": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, "license": "MIT", "engines": { @@ -10609,6 +14119,8 @@ }, "node_modules/path-is-absolute": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, "license": "MIT", "engines": { @@ -10617,6 +14129,8 @@ }, "node_modules/path-key": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "license": "MIT", "engines": { "node": ">=8" @@ -10624,14 +14138,20 @@ }, "node_modules/path-parse": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "license": "MIT" }, "node_modules/path-to-regexp": { "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", "license": "MIT" }, "node_modules/path-type": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, "license": "MIT", "engines": { @@ -10640,11 +14160,15 @@ }, "node_modules/pathe": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", "dev": true, "license": "MIT" }, "node_modules/pathval": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", "dev": true, "license": "MIT", "engines": { @@ -10652,10 +14176,14 @@ } }, "node_modules/pause": { - "version": "0.0.1" + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" }, "node_modules/pg": { "version": "8.17.2", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.17.2.tgz", + "integrity": "sha512-vjbKdiBJRqzcYw1fNU5KuHyYvdJ1qpcQg1CeBrHFqV1pWgHeVR6j/+kX0E1AAXfyuLUGY1ICrN2ELKA/z2HWzw==", "license": "MIT", "dependencies": { "pg-connection-string": "^2.10.1", @@ -10681,15 +14209,21 @@ }, "node_modules/pg-cloudflare": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.3.0.tgz", + "integrity": "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==", "license": "MIT", "optional": true }, "node_modules/pg-connection-string": { "version": "2.10.1", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.10.1.tgz", + "integrity": "sha512-iNzslsoeSH2/gmDDKiyMqF64DATUCWj3YJ0wP14kqcsf2TUklwimd+66yYojKwZCA7h2yRNLGug71hCBA2a4sw==", "license": "MIT" }, "node_modules/pg-int8": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", "license": "ISC", "engines": { "node": ">=4.0.0" @@ -10697,6 +14231,8 @@ }, "node_modules/pg-pool": { "version": "3.11.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.11.0.tgz", + "integrity": "sha512-MJYfvHwtGp870aeusDh+hg9apvOe2zmpZJpyt+BMtzUWlVqbhFmMK6bOBXLBUPd7iRtIF9fZplDc7KrPN3PN7w==", "license": "MIT", "peerDependencies": { "pg": ">=8.0" @@ -10704,10 +14240,14 @@ }, "node_modules/pg-protocol": { "version": "1.11.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.11.0.tgz", + "integrity": "sha512-pfsxk2M9M3BuGgDOfuy37VNRRX3jmKgMjcvAcWqNDpZSf4cUmv8HSOl5ViRQFsfARFn0KuUQTgLxVMbNq5NW3g==", "license": "MIT" }, "node_modules/pg-types": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", "license": "MIT", "dependencies": { "pg-int8": "1.0.1", @@ -10722,6 +14262,8 @@ }, "node_modules/pgpass": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", "license": "MIT", "dependencies": { "split2": "^4.1.0" @@ -10729,10 +14271,14 @@ }, "node_modules/picocolors": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "license": "MIT", "engines": { "node": ">=8.6" @@ -10743,6 +14289,8 @@ }, "node_modules/pify": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -10750,6 +14298,8 @@ }, "node_modules/pirates": { "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", "license": "MIT", "engines": { "node": ">= 6" @@ -10757,6 +14307,8 @@ }, "node_modules/pkce-challenge": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", "license": "MIT", "engines": { "node": ">=16.20.0" @@ -10764,6 +14316,8 @@ }, "node_modules/pkg-dir": { "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, "license": "MIT", "dependencies": { @@ -10775,6 +14329,8 @@ }, "node_modules/pkg-dir/node_modules/find-up": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "license": "MIT", "dependencies": { @@ -10787,6 +14343,8 @@ }, "node_modules/pkg-dir/node_modules/locate-path": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "license": "MIT", "dependencies": { @@ -10798,6 +14356,8 @@ }, "node_modules/pkg-dir/node_modules/p-limit": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "license": "MIT", "dependencies": { @@ -10812,6 +14372,8 @@ }, "node_modules/pkg-dir/node_modules/p-locate": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "license": "MIT", "dependencies": { @@ -10823,6 +14385,8 @@ }, "node_modules/pkg-types": { "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", "dev": true, "license": "MIT", "dependencies": { @@ -10833,11 +14397,15 @@ }, "node_modules/pkg-types/node_modules/pathe": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true, "license": "MIT" }, "node_modules/possible-typed-array-names": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", "dev": true, "license": "MIT", "engines": { @@ -10846,6 +14414,8 @@ }, "node_modules/postcss": { "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "funding": [ { "type": "opencollective", @@ -10872,6 +14442,8 @@ }, "node_modules/postcss-import": { "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", "license": "MIT", "dependencies": { "postcss-value-parser": "^4.0.0", @@ -10887,6 +14459,8 @@ }, "node_modules/postcss-js": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", "funding": [ { "type": "opencollective", @@ -10910,6 +14484,8 @@ }, "node_modules/postcss-load-config": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", "funding": [ { "type": "opencollective", @@ -10950,6 +14526,8 @@ }, "node_modules/postcss-nested": { "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", "funding": [ { "type": "opencollective", @@ -10973,6 +14551,8 @@ }, "node_modules/postcss-selector-parser": { "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -10984,10 +14564,14 @@ }, "node_modules/postcss-value-parser": { "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "license": "MIT" }, "node_modules/postgres-array": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", "license": "MIT", "engines": { "node": ">=4" @@ -10995,6 +14579,8 @@ }, "node_modules/postgres-bytea": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", + "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -11002,6 +14588,8 @@ }, "node_modules/postgres-date": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -11009,6 +14597,8 @@ }, "node_modules/postgres-interval": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", "license": "MIT", "dependencies": { "xtend": "^4.0.0" @@ -11019,6 +14609,8 @@ }, "node_modules/prelude-ls": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, "license": "MIT", "engines": { @@ -11027,6 +14619,8 @@ }, "node_modules/pretty-format": { "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11040,6 +14634,8 @@ }, "node_modules/pretty-format/node_modules/ansi-styles": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", "engines": { @@ -11051,15 +14647,21 @@ }, "node_modules/pretty-format/node_modules/react-is": { "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true, "license": "MIT" }, "node_modules/process-nextick-args": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "license": "MIT" }, "node_modules/prompts": { "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "dev": true, "license": "MIT", "dependencies": { @@ -11072,6 +14674,8 @@ }, "node_modules/property-information": { "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", "license": "MIT", "funding": { "type": "github", @@ -11080,6 +14684,8 @@ }, "node_modules/proxy-addr": { "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "license": "MIT", "dependencies": { "forwarded": "0.2.0", @@ -11091,6 +14697,8 @@ }, "node_modules/psl": { "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", "dev": true, "license": "MIT", "dependencies": { @@ -11102,6 +14710,8 @@ }, "node_modules/punycode": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "license": "MIT", "engines": { "node": ">=6" @@ -11109,6 +14719,8 @@ }, "node_modules/pure-rand": { "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", "dev": true, "funding": [ { @@ -11124,6 +14736,8 @@ }, "node_modules/qs": { "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" @@ -11137,11 +14751,15 @@ }, "node_modules/querystringify": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", "dev": true, "license": "MIT" }, "node_modules/queue-microtask": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "funding": [ { "type": "github", @@ -11160,6 +14778,8 @@ }, "node_modules/range-parser": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -11167,6 +14787,8 @@ }, "node_modules/raw-body": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "license": "MIT", "dependencies": { "bytes": "~3.1.2", @@ -11180,6 +14802,8 @@ }, "node_modules/raw-body/node_modules/iconv-lite": { "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -11194,6 +14818,8 @@ }, "node_modules/react": { "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" @@ -11204,6 +14830,8 @@ }, "node_modules/react-day-picker": { "version": "9.13.0", + "resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-9.13.0.tgz", + "integrity": "sha512-euzj5Hlq+lOHqI53NiuNhCP8HWgsPf/bBAVijR50hNaY1XwjKjShAnIe8jm8RD2W9IJUvihDIZ+KrmqfFzNhFQ==", "license": "MIT", "dependencies": { "@date-fns/tz": "^1.4.1", @@ -11223,6 +14851,8 @@ }, "node_modules/react-dom": { "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", "dependencies": { "loose-envify": "^1.1.0", @@ -11234,6 +14864,8 @@ }, "node_modules/react-hook-form": { "version": "7.71.1", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.71.1.tgz", + "integrity": "sha512-9SUJKCGKo8HUSsCO+y0CtqkqI5nNuaDqTxyqPsZPqIwudpj4rCrAz/jZV+jn57bx5gtZKOh3neQu94DXMc+w5w==", "license": "MIT", "engines": { "node": ">=18.0.0" @@ -11248,11 +14880,15 @@ }, "node_modules/react-is": { "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.3.tgz", + "integrity": "sha512-qJNJfu81ByyabuG7hPFEbXqNcWSU3+eVus+KJs+0ncpGfMyYdvSmxiJxbWR65lYi1I+/0HBcliO029gc4F+PnA==", "license": "MIT", "peer": true }, "node_modules/react-markdown": { "version": "10.1.0", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz", + "integrity": "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -11278,6 +14914,8 @@ }, "node_modules/react-redux": { "version": "9.2.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", + "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", "license": "MIT", "dependencies": { "@types/use-sync-external-store": "^0.0.6", @@ -11299,6 +14937,8 @@ }, "node_modules/react-refresh": { "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", "dev": true, "license": "MIT", "engines": { @@ -11307,6 +14947,8 @@ }, "node_modules/react-remove-scroll": { "version": "2.7.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", "license": "MIT", "dependencies": { "react-remove-scroll-bar": "^2.3.7", @@ -11330,6 +14972,8 @@ }, "node_modules/react-remove-scroll-bar": { "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", "license": "MIT", "dependencies": { "react-style-singleton": "^2.2.2", @@ -11350,6 +14994,8 @@ }, "node_modules/react-router": { "version": "6.30.3", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.3.tgz", + "integrity": "sha512-XRnlbKMTmktBkjCLE8/XcZFlnHvr2Ltdr1eJX4idL55/9BbORzyZEaIkBFDhFGCEWBBItsVrDxwx3gnisMitdw==", "license": "MIT", "dependencies": { "@remix-run/router": "1.23.2" @@ -11363,6 +15009,8 @@ }, "node_modules/react-router-dom": { "version": "6.30.3", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.3.tgz", + "integrity": "sha512-pxPcv1AczD4vso7G4Z3TKcvlxK7g7TNt3/FNGMhfqyntocvYKj+GCatfigGDjbLozC4baguJ0ReCigoDJXb0ag==", "license": "MIT", "dependencies": { "@remix-run/router": "1.23.2", @@ -11378,6 +15026,8 @@ }, "node_modules/react-style-singleton": { "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", "license": "MIT", "dependencies": { "get-nonce": "^1.0.0", @@ -11398,6 +15048,8 @@ }, "node_modules/react-vega": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/react-vega/-/react-vega-8.0.0.tgz", + "integrity": "sha512-euye4Gec2ScnUK1zbSA2tzZXUwBmbba8bfbzaRVhdEJTGQfaD78bSgqrccrl9b2fKZS1TZXR0NADEHVe6nxvBg==", "dependencies": { "fast-deep-equal": "^3.1.3" }, @@ -11409,6 +15061,8 @@ }, "node_modules/read-cache": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", "license": "MIT", "dependencies": { "pify": "^2.3.0" @@ -11416,6 +15070,8 @@ }, "node_modules/readable-stream": { "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", @@ -11429,10 +15085,14 @@ }, "node_modules/readable-stream/node_modules/safe-buffer": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "license": "MIT" }, "node_modules/readdirp": { "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "license": "MIT", "dependencies": { "picomatch": "^2.2.1" @@ -11442,7 +15102,9 @@ } }, "node_modules/recharts": { - "version": "3.6.0", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-3.7.0.tgz", + "integrity": "sha512-l2VCsy3XXeraxIID9fx23eCb6iCBsxUQDnE8tWm6DFdszVAO7WVY/ChAD9wVit01y6B2PMupYiMmQwhgPHc9Ew==", "license": "MIT", "workspaces": [ "www" @@ -11471,6 +15133,8 @@ }, "node_modules/redent": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", "dev": true, "license": "MIT", "dependencies": { @@ -11483,6 +15147,8 @@ }, "node_modules/redis-errors": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", "license": "MIT", "engines": { "node": ">=4" @@ -11490,6 +15156,8 @@ }, "node_modules/redis-parser": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", "license": "MIT", "dependencies": { "redis-errors": "^1.0.0" @@ -11500,10 +15168,14 @@ }, "node_modules/redux": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", "license": "MIT" }, "node_modules/redux-thunk": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", "license": "MIT", "peerDependencies": { "redux": "^5.0.0" @@ -11511,6 +15183,8 @@ }, "node_modules/regexp.prototype.flags": { "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", "dev": true, "license": "MIT", "dependencies": { @@ -11530,6 +15204,8 @@ }, "node_modules/remark-parse": { "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -11544,6 +15220,8 @@ }, "node_modules/remark-rehype": { "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -11559,6 +15237,8 @@ }, "node_modules/require-directory": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, "license": "MIT", "engines": { @@ -11567,6 +15247,8 @@ }, "node_modules/require-from-string": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -11574,15 +15256,21 @@ }, "node_modules/requires-port": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true, "license": "MIT" }, "node_modules/reselect": { "version": "5.1.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", "license": "MIT" }, "node_modules/resolve": { "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "license": "MIT", "dependencies": { "is-core-module": "^2.16.1", @@ -11601,6 +15289,8 @@ }, "node_modules/resolve-cwd": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, "license": "MIT", "dependencies": { @@ -11612,6 +15302,8 @@ }, "node_modules/resolve-cwd/node_modules/resolve-from": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, "license": "MIT", "engines": { @@ -11620,6 +15312,8 @@ }, "node_modules/resolve-from": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, "license": "MIT", "engines": { @@ -11628,6 +15322,8 @@ }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", "devOptional": true, "license": "MIT", "funding": { @@ -11636,6 +15332,8 @@ }, "node_modules/resolve.exports": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", "dev": true, "license": "MIT", "engines": { @@ -11644,6 +15342,8 @@ }, "node_modules/reusify": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -11652,6 +15352,9 @@ }, "node_modules/rimraf": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", "dependencies": { @@ -11666,10 +15369,14 @@ }, "node_modules/robust-predicates": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", "license": "Unlicense" }, "node_modules/rollup": { - "version": "4.55.2", + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.55.3.tgz", + "integrity": "sha512-y9yUpfQvetAjiDLtNMf1hL9NXchIJgWt6zIKeoB+tCd3npX08Eqfzg60V9DhIGVMtQ0AlMkFw5xa+AQ37zxnAA==", "dev": true, "license": "MIT", "dependencies": { @@ -11683,36 +15390,38 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.55.2", - "@rollup/rollup-android-arm64": "4.55.2", - "@rollup/rollup-darwin-arm64": "4.55.2", - "@rollup/rollup-darwin-x64": "4.55.2", - "@rollup/rollup-freebsd-arm64": "4.55.2", - "@rollup/rollup-freebsd-x64": "4.55.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.55.2", - "@rollup/rollup-linux-arm-musleabihf": "4.55.2", - "@rollup/rollup-linux-arm64-gnu": "4.55.2", - "@rollup/rollup-linux-arm64-musl": "4.55.2", - "@rollup/rollup-linux-loong64-gnu": "4.55.2", - "@rollup/rollup-linux-loong64-musl": "4.55.2", - "@rollup/rollup-linux-ppc64-gnu": "4.55.2", - "@rollup/rollup-linux-ppc64-musl": "4.55.2", - "@rollup/rollup-linux-riscv64-gnu": "4.55.2", - "@rollup/rollup-linux-riscv64-musl": "4.55.2", - "@rollup/rollup-linux-s390x-gnu": "4.55.2", - "@rollup/rollup-linux-x64-gnu": "4.55.2", - "@rollup/rollup-linux-x64-musl": "4.55.2", - "@rollup/rollup-openbsd-x64": "4.55.2", - "@rollup/rollup-openharmony-arm64": "4.55.2", - "@rollup/rollup-win32-arm64-msvc": "4.55.2", - "@rollup/rollup-win32-ia32-msvc": "4.55.2", - "@rollup/rollup-win32-x64-gnu": "4.55.2", - "@rollup/rollup-win32-x64-msvc": "4.55.2", + "@rollup/rollup-android-arm-eabi": "4.55.3", + "@rollup/rollup-android-arm64": "4.55.3", + "@rollup/rollup-darwin-arm64": "4.55.3", + "@rollup/rollup-darwin-x64": "4.55.3", + "@rollup/rollup-freebsd-arm64": "4.55.3", + "@rollup/rollup-freebsd-x64": "4.55.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.55.3", + "@rollup/rollup-linux-arm-musleabihf": "4.55.3", + "@rollup/rollup-linux-arm64-gnu": "4.55.3", + "@rollup/rollup-linux-arm64-musl": "4.55.3", + "@rollup/rollup-linux-loong64-gnu": "4.55.3", + "@rollup/rollup-linux-loong64-musl": "4.55.3", + "@rollup/rollup-linux-ppc64-gnu": "4.55.3", + "@rollup/rollup-linux-ppc64-musl": "4.55.3", + "@rollup/rollup-linux-riscv64-gnu": "4.55.3", + "@rollup/rollup-linux-riscv64-musl": "4.55.3", + "@rollup/rollup-linux-s390x-gnu": "4.55.3", + "@rollup/rollup-linux-x64-gnu": "4.55.3", + "@rollup/rollup-linux-x64-musl": "4.55.3", + "@rollup/rollup-openbsd-x64": "4.55.3", + "@rollup/rollup-openharmony-arm64": "4.55.3", + "@rollup/rollup-win32-arm64-msvc": "4.55.3", + "@rollup/rollup-win32-ia32-msvc": "4.55.3", + "@rollup/rollup-win32-x64-gnu": "4.55.3", + "@rollup/rollup-win32-x64-msvc": "4.55.3", "fsevents": "~2.3.2" } }, "node_modules/router": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", "license": "MIT", "dependencies": { "debug": "^4.4.0", @@ -11727,6 +15436,8 @@ }, "node_modules/router/node_modules/debug": { "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -11742,6 +15453,8 @@ }, "node_modules/router/node_modules/path-to-regexp": { "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", "license": "MIT", "funding": { "type": "opencollective", @@ -11750,11 +15463,15 @@ }, "node_modules/rrweb-cssom": { "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", + "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", "dev": true, "license": "MIT" }, "node_modules/run-parallel": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "funding": [ { "type": "github", @@ -11776,10 +15493,14 @@ }, "node_modules/rw": { "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", "license": "BSD-3-Clause" }, "node_modules/safe-buffer": { "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "funding": [ { "type": "github", @@ -11798,6 +15519,8 @@ }, "node_modules/safe-regex-test": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", "dev": true, "license": "MIT", "dependencies": { @@ -11814,10 +15537,14 @@ }, "node_modules/safer-buffer": { "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, "node_modules/saxes": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", "dev": true, "license": "ISC", "dependencies": { @@ -11829,6 +15556,8 @@ }, "node_modules/scheduler": { "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" @@ -11836,6 +15565,8 @@ }, "node_modules/semver": { "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -11846,6 +15577,8 @@ }, "node_modules/send": { "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", "license": "MIT", "dependencies": { "debug": "2.6.9", @@ -11868,6 +15601,8 @@ }, "node_modules/send/node_modules/debug": { "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -11875,10 +15610,14 @@ }, "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, "node_modules/serve-static": { "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", "license": "MIT", "dependencies": { "encodeurl": "~2.0.0", @@ -11892,6 +15631,8 @@ }, "node_modules/set-function-length": { "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, "license": "MIT", "dependencies": { @@ -11908,6 +15649,8 @@ }, "node_modules/set-function-name": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11922,10 +15665,14 @@ }, "node_modules/setprototypeof": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, "node_modules/shebang-command": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -11936,6 +15683,8 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "license": "MIT", "engines": { "node": ">=8" @@ -11943,6 +15692,8 @@ }, "node_modules/side-channel": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -11960,6 +15711,8 @@ }, "node_modules/side-channel-list": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -11974,6 +15727,8 @@ }, "node_modules/side-channel-map": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -11990,6 +15745,8 @@ }, "node_modules/side-channel-weakmap": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -12007,21 +15764,29 @@ }, "node_modules/siginfo": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", "dev": true, "license": "ISC" }, "node_modules/signal-exit": { "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true, "license": "ISC" }, "node_modules/sisteransi": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", "dev": true, "license": "MIT" }, "node_modules/slash": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, "license": "MIT", "engines": { @@ -12030,6 +15795,8 @@ }, "node_modules/socket.io": { "version": "4.8.3", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.3.tgz", + "integrity": "sha512-2Dd78bqzzjE6KPkD5fHZmDAKRNe3J15q+YHDrIsy9WEkqttc7GY+kT9OBLSMaPbQaEd0x1BjcmtMtXkfpc+T5A==", "license": "MIT", "dependencies": { "accepts": "~1.3.4", @@ -12046,6 +15813,8 @@ }, "node_modules/socket.io-adapter": { "version": "2.5.6", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.6.tgz", + "integrity": "sha512-DkkO/dz7MGln0dHn5bmN3pPy+JmywNICWrJqVWiVOyvXjWQFIv9c2h24JrQLLFJ2aQVQf/Cvl1vblnd4r2apLQ==", "license": "MIT", "dependencies": { "debug": "~4.4.1", @@ -12054,6 +15823,8 @@ }, "node_modules/socket.io-adapter/node_modules/debug": { "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -12069,6 +15840,8 @@ }, "node_modules/socket.io-adapter/node_modules/ws": { "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -12088,6 +15861,8 @@ }, "node_modules/socket.io-client": { "version": "4.8.3", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.3.tgz", + "integrity": "sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g==", "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", @@ -12101,6 +15876,8 @@ }, "node_modules/socket.io-client/node_modules/debug": { "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -12116,6 +15893,8 @@ }, "node_modules/socket.io-parser": { "version": "4.2.5", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.5.tgz", + "integrity": "sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ==", "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", @@ -12127,6 +15906,8 @@ }, "node_modules/socket.io-parser/node_modules/debug": { "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -12142,6 +15923,8 @@ }, "node_modules/socket.io/node_modules/debug": { "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -12157,6 +15940,8 @@ }, "node_modules/source-map": { "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -12165,6 +15950,8 @@ }, "node_modules/source-map-js": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -12172,6 +15959,8 @@ }, "node_modules/source-map-support": { "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, "license": "MIT", "dependencies": { @@ -12181,6 +15970,8 @@ }, "node_modules/space-separated-tokens": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", "license": "MIT", "funding": { "type": "github", @@ -12189,6 +15980,8 @@ }, "node_modules/sparse-bitfield": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", "license": "MIT", "dependencies": { "memory-pager": "^1.0.2" @@ -12196,6 +15989,8 @@ }, "node_modules/split2": { "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", "license": "ISC", "engines": { "node": ">= 10.x" @@ -12203,11 +15998,15 @@ }, "node_modules/sprintf-js": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true, "license": "BSD-3-Clause" }, "node_modules/sqlstring": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", + "integrity": "sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -12215,6 +16014,8 @@ }, "node_modules/stack-utils": { "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", "dev": true, "license": "MIT", "dependencies": { @@ -12226,6 +16027,8 @@ }, "node_modules/stack-utils/node_modules/escape-string-regexp": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, "license": "MIT", "engines": { @@ -12234,15 +16037,21 @@ }, "node_modules/stackback": { "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", "dev": true, "license": "MIT" }, "node_modules/standard-as-callback": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==", "license": "MIT" }, "node_modules/statuses": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -12250,11 +16059,15 @@ }, "node_modules/std-env": { "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", "dev": true, "license": "MIT" }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", "dev": true, "license": "MIT", "dependencies": { @@ -12267,6 +16080,8 @@ }, "node_modules/string_decoder": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" @@ -12274,10 +16089,14 @@ }, "node_modules/string_decoder/node_modules/safe-buffer": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "license": "MIT" }, "node_modules/string-length": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", "dev": true, "license": "MIT", "dependencies": { @@ -12290,6 +16109,8 @@ }, "node_modules/string-width": { "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", "dependencies": { @@ -12303,6 +16124,8 @@ }, "node_modules/stringify-entities": { "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", "license": "MIT", "dependencies": { "character-entities-html4": "^2.0.0", @@ -12315,6 +16138,8 @@ }, "node_modules/strip-ansi": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", "dependencies": { @@ -12326,6 +16151,8 @@ }, "node_modules/strip-bom": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, "license": "MIT", "engines": { @@ -12334,6 +16161,8 @@ }, "node_modules/strip-final-newline": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, "license": "MIT", "engines": { @@ -12342,6 +16171,8 @@ }, "node_modules/strip-indent": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", "dev": true, "license": "MIT", "dependencies": { @@ -12353,6 +16184,8 @@ }, "node_modules/strip-json-comments": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, "license": "MIT", "engines": { @@ -12364,6 +16197,8 @@ }, "node_modules/strip-literal": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.1.1.tgz", + "integrity": "sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==", "dev": true, "license": "MIT", "dependencies": { @@ -12375,11 +16210,15 @@ }, "node_modules/strip-literal/node_modules/js-tokens": { "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", "dev": true, "license": "MIT" }, "node_modules/style-to-js": { "version": "1.1.21", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", + "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==", "license": "MIT", "dependencies": { "style-to-object": "1.0.14" @@ -12387,6 +16226,8 @@ }, "node_modules/style-to-object": { "version": "1.0.14", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz", + "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==", "license": "MIT", "dependencies": { "inline-style-parser": "0.2.7" @@ -12394,6 +16235,8 @@ }, "node_modules/sucrase": { "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", @@ -12473,6 +16316,8 @@ }, "node_modules/supports-color": { "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "license": "MIT", "dependencies": { @@ -12484,6 +16329,8 @@ }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -12494,11 +16341,15 @@ }, "node_modules/symbol-tree": { "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true, "license": "MIT" }, "node_modules/tailwind-merge": { "version": "3.4.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.4.0.tgz", + "integrity": "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==", "license": "MIT", "funding": { "type": "github", @@ -12507,6 +16358,8 @@ }, "node_modules/tailwindcss": { "version": "3.4.19", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", + "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", @@ -12542,6 +16395,8 @@ }, "node_modules/tailwindcss-animate": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", + "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==", "license": "MIT", "peerDependencies": { "tailwindcss": ">=3.0.0 || insiders" @@ -12549,6 +16404,8 @@ }, "node_modules/test-exclude": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, "license": "ISC", "dependencies": { @@ -12562,6 +16419,8 @@ }, "node_modules/test-exclude/node_modules/brace-expansion": { "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -12571,6 +16430,8 @@ }, "node_modules/test-exclude/node_modules/minimatch": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", "dependencies": { @@ -12582,11 +16443,15 @@ }, "node_modules/text-table": { "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true, "license": "MIT" }, "node_modules/thenify": { "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", "license": "MIT", "dependencies": { "any-promise": "^1.0.0" @@ -12594,6 +16459,8 @@ }, "node_modules/thenify-all": { "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", "license": "MIT", "dependencies": { "thenify": ">= 3.1.0 < 4" @@ -12604,15 +16471,21 @@ }, "node_modules/tiny-invariant": { "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", "license": "MIT" }, "node_modules/tinybench": { "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", "dev": true, "license": "MIT" }, "node_modules/tinyglobby": { "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "license": "MIT", "dependencies": { "fdir": "^6.5.0", @@ -12627,6 +16500,8 @@ }, "node_modules/tinyglobby/node_modules/fdir": { "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "license": "MIT", "engines": { "node": ">=12.0.0" @@ -12642,6 +16517,8 @@ }, "node_modules/tinyglobby/node_modules/picomatch": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", "engines": { "node": ">=12" @@ -12652,6 +16529,8 @@ }, "node_modules/tinypool": { "version": "0.8.4", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.4.tgz", + "integrity": "sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==", "dev": true, "license": "MIT", "engines": { @@ -12660,6 +16539,8 @@ }, "node_modules/tinyspy": { "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", + "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", "dev": true, "license": "MIT", "engines": { @@ -12668,11 +16549,15 @@ }, "node_modules/tmpl": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", "dev": true, "license": "BSD-3-Clause" }, "node_modules/to-regex-range": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -12683,6 +16568,8 @@ }, "node_modules/toidentifier": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "license": "MIT", "engines": { "node": ">=0.6" @@ -12690,6 +16577,8 @@ }, "node_modules/topojson-client": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/topojson-client/-/topojson-client-3.1.0.tgz", + "integrity": "sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==", "license": "ISC", "dependencies": { "commander": "2" @@ -12702,10 +16591,14 @@ }, "node_modules/topojson-client/node_modules/commander": { "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "license": "MIT" }, "node_modules/tough-cookie": { "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -12720,6 +16613,8 @@ }, "node_modules/tr46": { "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", "license": "MIT", "dependencies": { "punycode": "^2.3.1" @@ -12730,6 +16625,8 @@ }, "node_modules/tree-kill": { "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true, "license": "MIT", "bin": { @@ -12738,6 +16635,8 @@ }, "node_modules/trim-lines": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", "license": "MIT", "funding": { "type": "github", @@ -12746,6 +16645,8 @@ }, "node_modules/trough": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", "license": "MIT", "funding": { "type": "github", @@ -12754,6 +16655,8 @@ }, "node_modules/ts-api-utils": { "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", "dev": true, "license": "MIT", "engines": { @@ -12765,6 +16668,8 @@ }, "node_modules/ts-interface-checker": { "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", "license": "Apache-2.0" }, "node_modules/ts-jest": { @@ -12835,6 +16740,8 @@ }, "node_modules/ts-node": { "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "license": "MIT", "dependencies": { @@ -12877,6 +16784,8 @@ }, "node_modules/ts-node-dev": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-2.0.0.tgz", + "integrity": "sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==", "dev": true, "license": "MIT", "dependencies": { @@ -12910,6 +16819,9 @@ }, "node_modules/ts-node-dev/node_modules/rimraf": { "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", "dependencies": { @@ -12921,11 +16833,15 @@ }, "node_modules/ts-node/node_modules/arg": { "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true, "license": "MIT" }, "node_modules/tsconfig": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", + "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", "dev": true, "license": "MIT", "dependencies": { @@ -12937,6 +16853,8 @@ }, "node_modules/tsconfig/node_modules/strip-bom": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, "license": "MIT", "engines": { @@ -12945,6 +16863,8 @@ }, "node_modules/tsconfig/node_modules/strip-json-comments": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "dev": true, "license": "MIT", "engines": { @@ -12953,10 +16873,14 @@ }, "node_modules/tslib": { "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, "node_modules/tsx": { "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -12975,6 +16899,8 @@ }, "node_modules/type-check": { "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "license": "MIT", "dependencies": { @@ -12986,6 +16912,8 @@ }, "node_modules/type-detect": { "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true, "license": "MIT", "engines": { @@ -12994,6 +16922,8 @@ }, "node_modules/type-fest": { "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { @@ -13005,6 +16935,8 @@ }, "node_modules/type-is": { "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "license": "MIT", "dependencies": { "media-typer": "0.3.0", @@ -13016,6 +16948,8 @@ }, "node_modules/typescript": { "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -13028,6 +16962,8 @@ }, "node_modules/ufo": { "version": "1.6.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", + "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", "dev": true, "license": "MIT" }, @@ -13047,6 +16983,8 @@ }, "node_modules/uid2": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/uid2/-/uid2-1.0.0.tgz", + "integrity": "sha512-+I6aJUv63YAcY9n4mQreLUt0d4lvwkkopDNmpomkAUz0fAkEMV9pRWxN0EjhW1YfRhcuyHg2v3mwddCDW1+LFQ==", "license": "MIT", "engines": { "node": ">= 4.0.0" @@ -13054,10 +16992,14 @@ }, "node_modules/undici-types": { "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "license": "MIT" }, "node_modules/unified": { "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -13075,6 +17017,8 @@ }, "node_modules/unist-util-is": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" @@ -13086,6 +17030,8 @@ }, "node_modules/unist-util-position": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" @@ -13097,6 +17043,8 @@ }, "node_modules/unist-util-stringify-position": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" @@ -13108,6 +17056,8 @@ }, "node_modules/unist-util-visit": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -13121,6 +17071,8 @@ }, "node_modules/unist-util-visit-parents": { "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -13133,6 +17085,8 @@ }, "node_modules/universalify": { "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", "dev": true, "license": "MIT", "engines": { @@ -13141,6 +17095,8 @@ }, "node_modules/unpipe": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -13148,6 +17104,8 @@ }, "node_modules/update-browserslist-db": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dev": true, "funding": [ { @@ -13177,6 +17135,8 @@ }, "node_modules/uri-js": { "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -13185,6 +17145,8 @@ }, "node_modules/url-parse": { "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "dev": true, "license": "MIT", "dependencies": { @@ -13194,6 +17156,8 @@ }, "node_modules/use-callback-ref": { "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", "license": "MIT", "dependencies": { "tslib": "^2.0.0" @@ -13213,6 +17177,8 @@ }, "node_modules/use-sidecar": { "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", "license": "MIT", "dependencies": { "detect-node-es": "^1.1.0", @@ -13233,6 +17199,8 @@ }, "node_modules/use-sync-external-store": { "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", "license": "MIT", "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" @@ -13240,10 +17208,14 @@ }, "node_modules/util-deprecate": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, "node_modules/utils-merge": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "license": "MIT", "engines": { "node": ">= 0.4.0" @@ -13251,11 +17223,15 @@ }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true, "license": "MIT" }, "node_modules/v8-to-istanbul": { "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "dev": true, "license": "ISC", "dependencies": { @@ -13269,6 +17245,8 @@ }, "node_modules/vary": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -13276,6 +17254,8 @@ }, "node_modules/vega": { "version": "6.2.0", + "resolved": "https://registry.npmjs.org/vega/-/vega-6.2.0.tgz", + "integrity": "sha512-BIwalIcEGysJdQDjeVUmMWB3e50jPDNAMfLJscjEvpunU9bSt7X1OYnQxkg3uBwuRRI4nWfFZO9uIW910nLeGw==", "license": "BSD-3-Clause", "dependencies": { "vega-crossfilter": "~5.1.0", @@ -13312,10 +17292,14 @@ }, "node_modules/vega-canvas": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vega-canvas/-/vega-canvas-2.0.0.tgz", + "integrity": "sha512-9x+4TTw/USYST5nx4yN272sy9WcqSRjAR0tkQYZJ4cQIeon7uVsnohvoPQK1JZu7K1QXGUqzj08z0u/UegBVMA==", "license": "BSD-3-Clause" }, "node_modules/vega-crossfilter": { "version": "5.1.0", + "resolved": "https://registry.npmjs.org/vega-crossfilter/-/vega-crossfilter-5.1.0.tgz", + "integrity": "sha512-EmVhfP3p6AM7o/lPan/QAoqjblI19BxWUlvl2TSs0xjQd8KbaYYbS4Ixt3cmEvl0QjRdBMF6CdJJ/cy9DTS4Fw==", "license": "BSD-3-Clause", "dependencies": { "d3-array": "^3.2.4", @@ -13325,6 +17309,8 @@ }, "node_modules/vega-dataflow": { "version": "6.1.0", + "resolved": "https://registry.npmjs.org/vega-dataflow/-/vega-dataflow-6.1.0.tgz", + "integrity": "sha512-JxumGlODtFbzoQ4c/jQK8Tb/68ih0lrexlCozcMfTAwQ12XhTqCvlafh7MAKKTMBizjOfaQTHm4Jkyb1H5CfyQ==", "license": "BSD-3-Clause", "dependencies": { "vega-format": "^2.1.0", @@ -13334,6 +17320,8 @@ }, "node_modules/vega-embed": { "version": "7.1.0", + "resolved": "https://registry.npmjs.org/vega-embed/-/vega-embed-7.1.0.tgz", + "integrity": "sha512-ZmEIn5XJrQt7fSh2lwtSdXG/9uf3yIqZnvXFEwBJRppiBgrEWZcZbj6VK3xn8sNTFQ+sQDXW5sl/6kmbAW3s5A==", "license": "BSD-3-Clause", "dependencies": { "fast-json-patch": "^3.1.1", @@ -13355,6 +17343,8 @@ }, "node_modules/vega-encode": { "version": "5.1.0", + "resolved": "https://registry.npmjs.org/vega-encode/-/vega-encode-5.1.0.tgz", + "integrity": "sha512-q26oI7B+MBQYcTQcr5/c1AMsX3FvjZLQOBi7yI0vV+GEn93fElDgvhQiYrgeYSD4Exi/jBPeUXuN6p4bLz16kA==", "license": "BSD-3-Clause", "dependencies": { "d3-array": "^3.2.4", @@ -13366,10 +17356,14 @@ }, "node_modules/vega-event-selector": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/vega-event-selector/-/vega-event-selector-4.0.0.tgz", + "integrity": "sha512-CcWF4m4KL/al1Oa5qSzZ5R776q8lRxCj3IafCHs5xipoEHrkgu1BWa7F/IH5HrDNXeIDnqOpSV1pFsAWRak4gQ==", "license": "BSD-3-Clause" }, "node_modules/vega-expression": { "version": "6.1.0", + "resolved": "https://registry.npmjs.org/vega-expression/-/vega-expression-6.1.0.tgz", + "integrity": "sha512-hHgNx/fQ1Vn1u6vHSamH7lRMsOa/yQeHGGcWVmh8fZafLdwdhCM91kZD9p7+AleNpgwiwzfGogtpATFaMmDFYg==", "license": "BSD-3-Clause", "dependencies": { "@types/estree": "^1.0.8", @@ -13378,6 +17372,8 @@ }, "node_modules/vega-force": { "version": "5.1.0", + "resolved": "https://registry.npmjs.org/vega-force/-/vega-force-5.1.0.tgz", + "integrity": "sha512-wdnchOSeXpF9Xx8Yp0s6Do9F7YkFeOn/E/nENtsI7NOcyHpICJ5+UkgjUo9QaQ/Yu+dIDU+sP/4NXsUtq6SMaQ==", "license": "BSD-3-Clause", "dependencies": { "d3-force": "^3.0.0", @@ -13387,6 +17383,8 @@ }, "node_modules/vega-format": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/vega-format/-/vega-format-2.1.0.tgz", + "integrity": "sha512-i9Ht33IgqG36+S1gFDpAiKvXCPz+q+1vDhDGKK8YsgMxGOG4PzinKakI66xd7SdV4q97FgpR7odAXqtDN2wKqw==", "license": "BSD-3-Clause", "dependencies": { "d3-array": "^3.2.4", @@ -13398,6 +17396,8 @@ }, "node_modules/vega-functions": { "version": "6.1.1", + "resolved": "https://registry.npmjs.org/vega-functions/-/vega-functions-6.1.1.tgz", + "integrity": "sha512-Due6jP0y0FfsGMTrHnzUGnEwXPu7VwE+9relfo+LjL/tRPYnnKqwWvzt7n9JkeBuZqjkgYjMzm/WucNn6Hkw5A==", "license": "BSD-3-Clause", "dependencies": { "d3-array": "^3.2.4", @@ -13415,6 +17415,8 @@ }, "node_modules/vega-geo": { "version": "5.1.0", + "resolved": "https://registry.npmjs.org/vega-geo/-/vega-geo-5.1.0.tgz", + "integrity": "sha512-H8aBBHfthc3rzDbz/Th18+Nvp00J73q3uXGAPDQqizioDm/CoXCK8cX4pMePydBY9S6ikBiGJrLKFDa80wI20g==", "license": "BSD-3-Clause", "dependencies": { "d3-array": "^3.2.4", @@ -13429,6 +17431,8 @@ }, "node_modules/vega-hierarchy": { "version": "5.1.0", + "resolved": "https://registry.npmjs.org/vega-hierarchy/-/vega-hierarchy-5.1.0.tgz", + "integrity": "sha512-rZlU8QJNETlB6o73lGCPybZtw2fBBsRIRuFE77aCLFHdGsh6wIifhplVarqE9icBqjUHRRUOmcEYfzwVIPr65g==", "license": "BSD-3-Clause", "dependencies": { "d3-hierarchy": "^3.1.2", @@ -13438,6 +17442,8 @@ }, "node_modules/vega-interpreter": { "version": "2.2.1", + "resolved": "https://registry.npmjs.org/vega-interpreter/-/vega-interpreter-2.2.1.tgz", + "integrity": "sha512-o+4ZEme2mdFLewlpF76dwPWW2VkZ3TAF3DMcq75/NzA5KPvnN4wnlCM8At2FVawbaHRyGdVkJSS5ROF5KwpHPQ==", "license": "BSD-3-Clause", "dependencies": { "vega-util": "^2.1.0" @@ -13445,6 +17451,8 @@ }, "node_modules/vega-label": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/vega-label/-/vega-label-2.1.0.tgz", + "integrity": "sha512-/hgf+zoA3FViDBehrQT42Lta3t8In6YwtMnwjYlh72zNn1p3c7E3YUBwqmAqTM1x+tudgzMRGLYig+bX1ewZxQ==", "license": "BSD-3-Clause", "dependencies": { "vega-canvas": "^2.0.0", @@ -13455,6 +17463,8 @@ }, "node_modules/vega-lite": { "version": "6.4.2", + "resolved": "https://registry.npmjs.org/vega-lite/-/vega-lite-6.4.2.tgz", + "integrity": "sha512-Mv2PaRIpijz256LM0NdOJd9Md8cqyrXina54xW6Qp865YfY502zlXGUst+W/XznVwISGfatt0yLZuDqCUbBDuw==", "license": "BSD-3-Clause", "dependencies": { "json-stringify-pretty-compact": "~4.0.0", @@ -13482,6 +17492,8 @@ }, "node_modules/vega-lite/node_modules/ansi-regex": { "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "license": "MIT", "engines": { "node": ">=12" @@ -13492,6 +17504,8 @@ }, "node_modules/vega-lite/node_modules/ansi-styles": { "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "license": "MIT", "engines": { "node": ">=12" @@ -13502,6 +17516,8 @@ }, "node_modules/vega-lite/node_modules/cliui": { "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", "license": "ISC", "dependencies": { "string-width": "^7.2.0", @@ -13514,10 +17530,14 @@ }, "node_modules/vega-lite/node_modules/emoji-regex": { "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", "license": "MIT" }, "node_modules/vega-lite/node_modules/string-width": { "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "license": "MIT", "dependencies": { "emoji-regex": "^10.3.0", @@ -13533,6 +17553,8 @@ }, "node_modules/vega-lite/node_modules/strip-ansi": { "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -13546,6 +17568,8 @@ }, "node_modules/vega-lite/node_modules/wrap-ansi": { "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", @@ -13561,6 +17585,8 @@ }, "node_modules/vega-lite/node_modules/yargs": { "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", "license": "MIT", "dependencies": { "cliui": "^9.0.1", @@ -13576,6 +17602,8 @@ }, "node_modules/vega-lite/node_modules/yargs-parser": { "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", "license": "ISC", "engines": { "node": "^20.19.0 || ^22.12.0 || >=23" @@ -13583,6 +17611,8 @@ }, "node_modules/vega-loader": { "version": "5.1.0", + "resolved": "https://registry.npmjs.org/vega-loader/-/vega-loader-5.1.0.tgz", + "integrity": "sha512-GaY3BdSPbPNdtrBz8SYUBNmNd8mdPc3mtdZfdkFazQ0RD9m+Toz5oR8fKnTamNSk9fRTJX0Lp3uEqxrAlQVreg==", "license": "BSD-3-Clause", "dependencies": { "d3-dsv": "^3.0.1", @@ -13593,6 +17623,8 @@ }, "node_modules/vega-parser": { "version": "7.1.0", + "resolved": "https://registry.npmjs.org/vega-parser/-/vega-parser-7.1.0.tgz", + "integrity": "sha512-g0lrYxtmYVW8G6yXpIS4J3Uxt9OUSkc0bLu5afoYDo4rZmoOOdll3x3ebActp5LHPW+usZIE+p5nukRS2vEc7Q==", "license": "BSD-3-Clause", "dependencies": { "vega-dataflow": "^6.1.0", @@ -13604,6 +17636,8 @@ }, "node_modules/vega-projection": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/vega-projection/-/vega-projection-2.1.0.tgz", + "integrity": "sha512-EjRjVSoMR5ibrU7q8LaOQKP327NcOAM1+eZ+NO4ANvvAutwmbNVTmfA1VpPH+AD0AlBYc39ND/wnRk7SieDiXA==", "license": "BSD-3-Clause", "dependencies": { "d3-geo": "^3.1.1", @@ -13613,6 +17647,8 @@ }, "node_modules/vega-regression": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/vega-regression/-/vega-regression-2.1.0.tgz", + "integrity": "sha512-HzC7MuoEwG1rIxRaNTqgcaYF03z/ZxYkQR2D5BN0N45kLnHY1HJXiEcZkcffTsqXdspLjn47yLi44UoCwF5fxQ==", "license": "BSD-3-Clause", "dependencies": { "d3-array": "^3.2.4", @@ -13623,6 +17659,8 @@ }, "node_modules/vega-runtime": { "version": "7.1.0", + "resolved": "https://registry.npmjs.org/vega-runtime/-/vega-runtime-7.1.0.tgz", + "integrity": "sha512-mItI+WHimyEcZlZrQ/zYR3LwHVeyHCWwp7MKaBjkU8EwkSxEEGVceyGUY9X2YuJLiOgkLz/6juYDbMv60pfwYA==", "license": "BSD-3-Clause", "dependencies": { "vega-dataflow": "^6.1.0", @@ -13631,6 +17669,8 @@ }, "node_modules/vega-scale": { "version": "8.1.0", + "resolved": "https://registry.npmjs.org/vega-scale/-/vega-scale-8.1.0.tgz", + "integrity": "sha512-VEgDuEcOec8+C8+FzLcnAmcXrv2gAJKqQifCdQhkgnsLa978vYUgVfCut/mBSMMHbH8wlUV1D0fKZTjRukA1+A==", "license": "BSD-3-Clause", "dependencies": { "d3-array": "^3.2.4", @@ -13643,6 +17683,8 @@ }, "node_modules/vega-scenegraph": { "version": "5.1.0", + "resolved": "https://registry.npmjs.org/vega-scenegraph/-/vega-scenegraph-5.1.0.tgz", + "integrity": "sha512-4gA89CFIxkZX+4Nvl8SZF2MBOqnlj9J5zgdPh/HPx+JOwtzSlUqIhxFpFj7GWYfwzr/PyZnguBLPihPw1Og/cA==", "license": "BSD-3-Clause", "dependencies": { "d3-path": "^3.1.0", @@ -13655,10 +17697,14 @@ }, "node_modules/vega-schema-url-parser": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/vega-schema-url-parser/-/vega-schema-url-parser-3.0.2.tgz", + "integrity": "sha512-xAnR7KAvNPYewI3O0l5QGdT8Tv0+GCZQjqfP39cW/hbe/b3aYMAQ39vm8O2wfXUHzm04xTe7nolcsx8WQNVLRQ==", "license": "BSD-3-Clause" }, "node_modules/vega-selections": { "version": "6.1.2", + "resolved": "https://registry.npmjs.org/vega-selections/-/vega-selections-6.1.2.tgz", + "integrity": "sha512-xJ+V4qdd46nk2RBdwIRrQm2iSTMHdlu/omhLz1pqRL3jZDrkqNBXimrisci2kIKpH2WBpA1YVagwuZEKBmF2Qw==", "license": "BSD-3-Clause", "dependencies": { "d3-array": "3.2.4", @@ -13668,6 +17714,8 @@ }, "node_modules/vega-statistics": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vega-statistics/-/vega-statistics-2.0.0.tgz", + "integrity": "sha512-dGPfDXnBlgXbZF3oxtkb8JfeRXd5TYHx25Z/tIoaa9jWua4Vf/AoW2wwh8J1qmMy8J03/29aowkp1yk4DOPazQ==", "license": "BSD-3-Clause", "dependencies": { "d3-array": "^3.2.4" @@ -13675,6 +17723,8 @@ }, "node_modules/vega-themes": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/vega-themes/-/vega-themes-3.0.0.tgz", + "integrity": "sha512-1iFiI3BNmW9FrsLnDLx0ZKEddsCitRY3XmUAwp6qmp+p+IXyJYc9pfjlVj9E6KXBPfm4cQyU++s0smKNiWzO4g==", "license": "BSD-3-Clause", "funding": { "url": "https://app.hubspot.com/payments/GyPC972GD9Rt" @@ -13686,6 +17736,8 @@ }, "node_modules/vega-time": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vega-time/-/vega-time-3.1.0.tgz", + "integrity": "sha512-G93mWzPwNa6UYQRkr8Ujur9uqxbBDjDT/WpXjbDY0yygdSkRT+zXF+Sb4gjhW0nPaqdiwkn0R6kZcSPMj1bMNA==", "license": "BSD-3-Clause", "dependencies": { "d3-array": "^3.2.4", @@ -13695,6 +17747,8 @@ }, "node_modules/vega-tooltip": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/vega-tooltip/-/vega-tooltip-1.0.0.tgz", + "integrity": "sha512-P1R0JP29v0qnTuwzCQ0SPJlkjAzr6qeyj+H4VgUFSykHmHc1OBxda//XBaFDl/bZgIscEMvjKSjZpXd84x3aZQ==", "license": "BSD-3-Clause", "dependencies": { "vega-util": "^2.0.0" @@ -13705,6 +17759,8 @@ }, "node_modules/vega-transforms": { "version": "5.1.0", + "resolved": "https://registry.npmjs.org/vega-transforms/-/vega-transforms-5.1.0.tgz", + "integrity": "sha512-mj/sO2tSuzzpiXX8JSl4DDlhEmVwM/46MTAzTNQUQzJPMI/n4ChCjr/SdEbfEyzlD4DPm1bjohZGjLc010yuMg==", "license": "BSD-3-Clause", "dependencies": { "d3-array": "^3.2.4", @@ -13716,6 +17772,8 @@ }, "node_modules/vega-typings": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/vega-typings/-/vega-typings-2.1.0.tgz", + "integrity": "sha512-zdis4Fg4gv37yEvTTSZEVMNhp8hwyEl7GZ4X4HHddRVRKxWFsbyKvZx/YW5Z9Ox4sjxVA2qHzEbod4Fdx+SEJA==", "license": "BSD-3-Clause", "dependencies": { "@types/geojson": "7946.0.16", @@ -13726,10 +17784,14 @@ }, "node_modules/vega-util": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/vega-util/-/vega-util-2.1.0.tgz", + "integrity": "sha512-PGfp0m0QCufDmcxKJCWQy4Ov23FoF8DSXmoJwSezi3itQaa2hbxK0+xwsTMP2vy4PR16Pu25HMzgMwXVW1+33w==", "license": "BSD-3-Clause" }, "node_modules/vega-view": { "version": "6.1.0", + "resolved": "https://registry.npmjs.org/vega-view/-/vega-view-6.1.0.tgz", + "integrity": "sha512-hmHDm/zC65lb23mb9Tr9Gx0wkxP0TMS31LpMPYxIZpvInxvUn7TYitkOtz1elr63k2YZrgmF7ztdGyQ4iCQ5fQ==", "license": "BSD-3-Clause", "dependencies": { "d3-array": "^3.2.4", @@ -13744,6 +17806,8 @@ }, "node_modules/vega-view-transforms": { "version": "5.1.0", + "resolved": "https://registry.npmjs.org/vega-view-transforms/-/vega-view-transforms-5.1.0.tgz", + "integrity": "sha512-fpigh/xn/32t+An1ShoY3MLeGzNdlbAp2+HvFKzPpmpMTZqJEWkk/J/wHU7Swyc28Ta7W1z3fO+8dZkOYO5TWQ==", "license": "BSD-3-Clause", "dependencies": { "vega-dataflow": "^6.1.0", @@ -13753,6 +17817,8 @@ }, "node_modules/vega-voronoi": { "version": "5.1.0", + "resolved": "https://registry.npmjs.org/vega-voronoi/-/vega-voronoi-5.1.0.tgz", + "integrity": "sha512-uKdsoR9x60mz7eYtVG+NhlkdQXeVdMr6jHNAHxs+W+i6kawkUp5S9jp1xf1FmW/uZvtO1eqinHQNwATcDRsiUg==", "license": "BSD-3-Clause", "dependencies": { "d3-delaunay": "^6.0.4", @@ -13762,6 +17828,8 @@ }, "node_modules/vega-wordcloud": { "version": "5.1.0", + "resolved": "https://registry.npmjs.org/vega-wordcloud/-/vega-wordcloud-5.1.0.tgz", + "integrity": "sha512-sSdNmT8y2D7xXhM2h76dKyaYn3PA4eV49WUUkfYfqHz/vpcu10GSAoFxLhQQTkbZXR+q5ZB63tFUow9W2IFo6g==", "license": "BSD-3-Clause", "dependencies": { "vega-canvas": "^2.0.0", @@ -13773,6 +17841,8 @@ }, "node_modules/vfile": { "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -13785,6 +17855,8 @@ }, "node_modules/vfile-message": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -13797,6 +17869,8 @@ }, "node_modules/victory-vendor": { "version": "37.3.6", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz", + "integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==", "license": "MIT AND ISC", "dependencies": { "@types/d3-array": "^3.0.3", @@ -13817,6 +17891,8 @@ }, "node_modules/vite": { "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "dev": true, "license": "MIT", "dependencies": { @@ -13875,6 +17951,8 @@ }, "node_modules/vite-node": { "version": "1.6.1", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.1.tgz", + "integrity": "sha512-YAXkfvGtuTzwWbDSACdJSg4A4DZiAqckWe90Zapc/sEX3XvHcw1NdurM/6od8J207tSDqNbSsgdCacBgvJKFuA==", "dev": true, "license": "MIT", "dependencies": { @@ -13894,8 +17972,384 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/vite/node_modules/@esbuild/win32-x64": { "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", "cpu": [ "x64" ], @@ -13911,6 +18365,8 @@ }, "node_modules/vite/node_modules/esbuild": { "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -13948,6 +18404,8 @@ }, "node_modules/vitest": { "version": "1.6.1", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.1.tgz", + "integrity": "sha512-Ljb1cnSJSivGN0LqXd/zmDbWEM0RNNg2t1QW/XUhYl/qPqyu7CsqeWtqQXHVaJsecLPuDoak2oJcZN2QoRIOag==", "dev": true, "license": "MIT", "dependencies": { @@ -14012,6 +18470,8 @@ }, "node_modules/vitest/node_modules/execa": { "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", "dev": true, "license": "MIT", "dependencies": { @@ -14034,6 +18494,8 @@ }, "node_modules/vitest/node_modules/get-stream": { "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", "dev": true, "license": "MIT", "engines": { @@ -14045,6 +18507,8 @@ }, "node_modules/vitest/node_modules/human-signals": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -14053,6 +18517,8 @@ }, "node_modules/vitest/node_modules/is-stream": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", "dev": true, "license": "MIT", "engines": { @@ -14064,6 +18530,8 @@ }, "node_modules/vitest/node_modules/mimic-fn": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", "dev": true, "license": "MIT", "engines": { @@ -14075,6 +18543,8 @@ }, "node_modules/vitest/node_modules/npm-run-path": { "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", "dev": true, "license": "MIT", "dependencies": { @@ -14089,6 +18559,8 @@ }, "node_modules/vitest/node_modules/onetime": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", "dev": true, "license": "MIT", "dependencies": { @@ -14103,6 +18575,8 @@ }, "node_modules/vitest/node_modules/path-key": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", "dev": true, "license": "MIT", "engines": { @@ -14114,6 +18588,8 @@ }, "node_modules/vitest/node_modules/signal-exit": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, "license": "ISC", "engines": { @@ -14125,6 +18601,8 @@ }, "node_modules/vitest/node_modules/strip-final-newline": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "dev": true, "license": "MIT", "engines": { @@ -14136,6 +18614,8 @@ }, "node_modules/w3c-xmlserializer": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", "dev": true, "license": "MIT", "dependencies": { @@ -14147,6 +18627,8 @@ }, "node_modules/walker": { "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -14155,6 +18637,8 @@ }, "node_modules/webidl-conversions": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -14162,6 +18646,9 @@ }, "node_modules/whatwg-encoding": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", "dev": true, "license": "MIT", "dependencies": { @@ -14173,6 +18660,8 @@ }, "node_modules/whatwg-encoding/node_modules/iconv-lite": { "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, "license": "MIT", "dependencies": { @@ -14184,6 +18673,8 @@ }, "node_modules/whatwg-mimetype": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", "dev": true, "license": "MIT", "engines": { @@ -14192,6 +18683,8 @@ }, "node_modules/whatwg-url": { "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", "license": "MIT", "dependencies": { "tr46": "^5.1.0", @@ -14203,6 +18696,8 @@ }, "node_modules/which": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -14216,6 +18711,8 @@ }, "node_modules/which-boxed-primitive": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", "dev": true, "license": "MIT", "dependencies": { @@ -14234,6 +18731,8 @@ }, "node_modules/which-collection": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "dev": true, "license": "MIT", "dependencies": { @@ -14251,6 +18750,8 @@ }, "node_modules/which-typed-array": { "version": "1.1.20", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", + "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", "dev": true, "license": "MIT", "dependencies": { @@ -14271,6 +18772,8 @@ }, "node_modules/why-is-node-running": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, "license": "MIT", "dependencies": { @@ -14286,6 +18789,8 @@ }, "node_modules/word-wrap": { "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "license": "MIT", "engines": { @@ -14301,6 +18806,8 @@ }, "node_modules/wrap-ansi": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "license": "MIT", "dependencies": { @@ -14317,10 +18824,14 @@ }, "node_modules/wrappy": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, "node_modules/write-file-atomic": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", "dev": true, "license": "ISC", "dependencies": { @@ -14333,6 +18844,8 @@ }, "node_modules/ws": { "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", "dev": true, "license": "MIT", "engines": { @@ -14353,6 +18866,8 @@ }, "node_modules/xml-name-validator": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", "dev": true, "license": "Apache-2.0", "engines": { @@ -14361,17 +18876,23 @@ }, "node_modules/xmlchars": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true, "license": "MIT" }, "node_modules/xmlhttprequest-ssl": { "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz", + "integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==", "engines": { "node": ">=0.4.0" } }, "node_modules/xtend": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "license": "MIT", "engines": { "node": ">=0.4" @@ -14379,6 +18900,8 @@ }, "node_modules/y18n": { "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "license": "ISC", "engines": { "node": ">=10" @@ -14386,11 +18909,15 @@ }, "node_modules/yallist": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true, "license": "ISC" }, "node_modules/yaml": { "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", "devOptional": true, "license": "ISC", "bin": { @@ -14405,6 +18932,8 @@ }, "node_modules/yargs": { "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "license": "MIT", "dependencies": { @@ -14422,6 +18951,8 @@ }, "node_modules/yargs-parser": { "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, "license": "ISC", "engines": { @@ -14430,6 +18961,8 @@ }, "node_modules/yn": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true, "license": "MIT", "engines": { @@ -14438,6 +18971,8 @@ }, "node_modules/yocto-queue": { "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, "license": "MIT", "engines": { @@ -14449,6 +18984,8 @@ }, "node_modules/zod": { "version": "4.3.5", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.5.tgz", + "integrity": "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -14456,6 +18993,8 @@ }, "node_modules/zod-to-json-schema": { "version": "3.25.1", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", + "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", "license": "ISC", "peerDependencies": { "zod": "^3.25 || ^4" @@ -14463,6 +19002,8 @@ }, "node_modules/zustand": { "version": "5.0.10", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.10.tgz", + "integrity": "sha512-U1AiltS1O9hSy3rul+Ub82ut2fqIAefiSuwECWt6jlMVUGejvf+5omLcRBSzqbRagSM3hQZbtzdeRc6QVScXTg==", "license": "MIT", "engines": { "node": ">=12.20.0" @@ -14490,6 +19031,8 @@ }, "node_modules/zwitch": { "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", "license": "MIT", "funding": { "type": "github", From dfded8f625720f96e41034cff2bb93871113c9fc Mon Sep 17 00:00:00 2001 From: Richard T Date: Wed, 21 Jan 2026 16:46:12 -0800 Subject: [PATCH 15/27] fix: Updated CostTrendChart.tsx and TokenUsageChart.tsx to handle tooltip labels safely, resolving the build failures. --- .../src/components/agent-control/charts/CostTrendChart.tsx | 5 +++-- .../src/components/agent-control/charts/TokenUsageChart.tsx | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/honeycomb/src/components/agent-control/charts/CostTrendChart.tsx b/honeycomb/src/components/agent-control/charts/CostTrendChart.tsx index 3911b9d6..133ff3c2 100644 --- a/honeycomb/src/components/agent-control/charts/CostTrendChart.tsx +++ b/honeycomb/src/components/agent-control/charts/CostTrendChart.tsx @@ -35,8 +35,9 @@ export function CostTrendChart({ maximumFractionDigits: 0, }).format(value) - const formatDate = (dateStr: string) => { - const date = new Date(dateStr) + const formatDate = (label: any) => { + if (typeof label !== 'string') return String(label || '') + const date = new Date(label) return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' }) } diff --git a/honeycomb/src/components/agent-control/charts/TokenUsageChart.tsx b/honeycomb/src/components/agent-control/charts/TokenUsageChart.tsx index 13c58c12..ae5c9f72 100644 --- a/honeycomb/src/components/agent-control/charts/TokenUsageChart.tsx +++ b/honeycomb/src/components/agent-control/charts/TokenUsageChart.tsx @@ -31,8 +31,9 @@ export function TokenUsageChart({ return value.toString() } - const formatDate = (dateStr: string) => { - const date = new Date(dateStr) + const formatDate = (label: any) => { + if (typeof label !== 'string') return String(label || '') + const date = new Date(label) return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' }) } From 8263835fce41320462a84a9cb5e2b062bb4bdb20 Mon Sep 17 00:00:00 2001 From: Richard T Date: Wed, 21 Jan 2026 16:49:13 -0800 Subject: [PATCH 16/27] fix: update `formatDate` label parameter type from `any` to `ReactNode` in chart components. --- .../src/components/agent-control/charts/CostTrendChart.tsx | 3 ++- .../src/components/agent-control/charts/TokenUsageChart.tsx | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/honeycomb/src/components/agent-control/charts/CostTrendChart.tsx b/honeycomb/src/components/agent-control/charts/CostTrendChart.tsx index 133ff3c2..f7318503 100644 --- a/honeycomb/src/components/agent-control/charts/CostTrendChart.tsx +++ b/honeycomb/src/components/agent-control/charts/CostTrendChart.tsx @@ -8,6 +8,7 @@ import { ResponsiveContainer, ReferenceLine, } from 'recharts' +import { ReactNode } from 'react' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import type { CostTrendData } from '@/types/agentControl' @@ -35,7 +36,7 @@ export function CostTrendChart({ maximumFractionDigits: 0, }).format(value) - const formatDate = (label: any) => { + const formatDate = (label: ReactNode) => { if (typeof label !== 'string') return String(label || '') const date = new Date(label) return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' }) diff --git a/honeycomb/src/components/agent-control/charts/TokenUsageChart.tsx b/honeycomb/src/components/agent-control/charts/TokenUsageChart.tsx index ae5c9f72..f2bcd824 100644 --- a/honeycomb/src/components/agent-control/charts/TokenUsageChart.tsx +++ b/honeycomb/src/components/agent-control/charts/TokenUsageChart.tsx @@ -8,6 +8,7 @@ import { ResponsiveContainer, Legend, } from 'recharts' +import { ReactNode } from 'react' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import type { TokenUsageData } from '@/types/agentControl' @@ -31,7 +32,7 @@ export function TokenUsageChart({ return value.toString() } - const formatDate = (label: any) => { + const formatDate = (label: ReactNode) => { if (typeof label !== 'string') return String(label || '') const date = new Date(label) return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' }) From 1c0eb2db61d94dbf2ae1f2a39197645394f6a231 Mon Sep 17 00:00:00 2001 From: Richard T Date: Wed, 21 Jan 2026 17:03:53 -0800 Subject: [PATCH 17/27] chore: Add `.dockerignore` files to exclude development artifacts and include `@types/node` dev dependency. --- hive/.dockerignore | 9 +++++++++ honeycomb/.dockerignore | 9 +++++++++ honeycomb/package.json | 3 ++- 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 hive/.dockerignore create mode 100644 honeycomb/.dockerignore diff --git a/hive/.dockerignore b/hive/.dockerignore new file mode 100644 index 00000000..982246ac --- /dev/null +++ b/hive/.dockerignore @@ -0,0 +1,9 @@ +node_modules +dist +.env +.env.* +*.log +.DS_Store +.git +.vscode +.idea diff --git a/honeycomb/.dockerignore b/honeycomb/.dockerignore new file mode 100644 index 00000000..982246ac --- /dev/null +++ b/honeycomb/.dockerignore @@ -0,0 +1,9 @@ +node_modules +dist +.env +.env.* +*.log +.DS_Store +.git +.vscode +.idea diff --git a/honeycomb/package.json b/honeycomb/package.json index c17f572e..d160ba35 100644 --- a/honeycomb/package.json +++ b/honeycomb/package.json @@ -58,6 +58,7 @@ "@typescript-eslint/eslint-plugin": "^6.14.0", "@typescript-eslint/parser": "^6.14.0", "@vitejs/plugin-react": "^4.2.1", + "@types/node": "^20.10.0", "autoprefixer": "^10.4.23", "eslint": "^8.55.0", "eslint-plugin-react-hooks": "^4.6.0", @@ -69,4 +70,4 @@ "vite": "^5.0.8", "vitest": "^1.1.0" } -} +} \ No newline at end of file From 406ad7924cbc4a7ffbffe9683286a59c3af7cc37 Mon Sep 17 00:00:00 2001 From: Richard T Date: Wed, 21 Jan 2026 19:19:48 -0800 Subject: [PATCH 18/27] refactor: Remove file read and write tools and update the workspace directory to use the user's home directory. --- aden-tools/src/aden_tools/tools/__init__.py | 6 -- .../aden_tools/tools/file_read_tool/README.md | 28 ------ .../tools/file_read_tool/__init__.py | 4 - .../tools/file_read_tool/file_read_tool.py | 75 -------------- .../tools/file_system_toolkits/security.py | 3 +- .../tools/file_write_tool/README.md | 29 ------ .../tools/file_write_tool/__init__.py | 4 - .../tools/file_write_tool/file_write_tool.py | 83 ---------------- aden-tools/tests/tools/test_file_read_tool.py | 96 ------------------ .../tests/tools/test_file_write_tool.py | 99 ------------------- 10 files changed, 2 insertions(+), 425 deletions(-) delete mode 100644 aden-tools/src/aden_tools/tools/file_read_tool/README.md delete mode 100644 aden-tools/src/aden_tools/tools/file_read_tool/__init__.py delete mode 100644 aden-tools/src/aden_tools/tools/file_read_tool/file_read_tool.py delete mode 100644 aden-tools/src/aden_tools/tools/file_write_tool/README.md delete mode 100644 aden-tools/src/aden_tools/tools/file_write_tool/__init__.py delete mode 100644 aden-tools/src/aden_tools/tools/file_write_tool/file_write_tool.py delete mode 100644 aden-tools/tests/tools/test_file_read_tool.py delete mode 100644 aden-tools/tests/tools/test_file_write_tool.py diff --git a/aden-tools/src/aden_tools/tools/__init__.py b/aden-tools/src/aden_tools/tools/__init__.py index feae94ae..387fccf7 100644 --- a/aden-tools/src/aden_tools/tools/__init__.py +++ b/aden-tools/src/aden_tools/tools/__init__.py @@ -14,8 +14,6 @@ from fastmcp import FastMCP # Import register_tools from each tool module from .example_tool import register_tools as register_example -from .file_read_tool import register_tools as register_file_read -from .file_write_tool import register_tools as register_file_write from .web_search_tool import register_tools as register_web_search from .web_scrape_tool import register_tools as register_web_scrape from .pdf_read_tool import register_tools as register_pdf_read @@ -42,8 +40,6 @@ def register_all_tools(mcp: FastMCP) -> List[str]: List of registered tool names """ register_example(mcp) - register_file_read(mcp) - register_file_write(mcp) register_web_search(mcp) register_web_scrape(mcp) register_pdf_read(mcp) @@ -60,8 +56,6 @@ def register_all_tools(mcp: FastMCP) -> List[str]: return [ "example_tool", - "file_read", - "file_write", "web_search", "web_scrape", "pdf_read", diff --git a/aden-tools/src/aden_tools/tools/file_read_tool/README.md b/aden-tools/src/aden_tools/tools/file_read_tool/README.md deleted file mode 100644 index 7ee31712..00000000 --- a/aden-tools/src/aden_tools/tools/file_read_tool/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# File Read Tool - -Read contents of local files with encoding support. - -## Description - -Use for reading configs, data files, source code, logs, or any text file. Returns file content along with path, name, size, and encoding metadata. - -## Arguments - -| Argument | Type | Required | Default | Description | -|----------|------|----------|---------|-------------| -| `file_path` | str | Yes | - | Path to the file to read (absolute or relative) | -| `encoding` | str | No | `utf-8` | File encoding (utf-8, latin-1, etc.) | -| `max_size` | int | No | `10000000` | Maximum file size to read in bytes (default 10MB) | - -## Environment Variables - -This tool does not require any environment variables. - -## Error Handling - -Returns error dicts for common issues: -- `File not found: ` - File does not exist -- `Not a file: ` - Path points to a directory -- `File too large: bytes (max: )` - File exceeds max_size limit -- `Failed to decode file with encoding ''` - Wrong encoding specified -- `Permission denied: ` - No read access to file diff --git a/aden-tools/src/aden_tools/tools/file_read_tool/__init__.py b/aden-tools/src/aden_tools/tools/file_read_tool/__init__.py deleted file mode 100644 index a02fc205..00000000 --- a/aden-tools/src/aden_tools/tools/file_read_tool/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -"""File Read Tool - Read contents of local files.""" -from .file_read_tool import register_tools - -__all__ = ["register_tools"] diff --git a/aden-tools/src/aden_tools/tools/file_read_tool/file_read_tool.py b/aden-tools/src/aden_tools/tools/file_read_tool/file_read_tool.py deleted file mode 100644 index 0d2ce90b..00000000 --- a/aden-tools/src/aden_tools/tools/file_read_tool/file_read_tool.py +++ /dev/null @@ -1,75 +0,0 @@ -""" -File Read Tool - Read contents of local files. - -Supports reading text files with various encodings. -Returns file content along with metadata. -""" -from __future__ import annotations - -from pathlib import Path - -from fastmcp import FastMCP - - -def register_tools(mcp: FastMCP) -> None: - """Register file read tools with the MCP server.""" - - @mcp.tool() - def file_read( - file_path: str, - encoding: str = "utf-8", - max_size: int = 10_000_000, - ) -> dict: - """ - Read the contents of a local file. - - Use for reading configs, data files, source code, logs, or any text file. - Returns file content along with path, name, size, and encoding. - - Args: - file_path: Path to the file to read (absolute or relative) - encoding: File encoding (utf-8, latin-1, etc.) - max_size: Maximum file size to read in bytes (default 10MB) - - Returns: - Dict with file content and metadata, or error dict - """ - try: - path = Path(file_path).resolve() - - # Check if file exists - if not path.exists(): - return {"error": f"File not found: {file_path}"} - - # Check if it's a file (not directory) - if not path.is_file(): - return {"error": f"Not a file: {file_path}"} - - # Check file size - file_size = path.stat().st_size - if max_size > 0 and file_size > max_size: - return { - "error": f"File too large: {file_size} bytes (max: {max_size})", - "file_size": file_size, - } - - # Read the file - content = path.read_text(encoding=encoding) - - return { - "path": str(path), - "name": path.name, - "content": content, - "size": len(content), - "encoding": encoding, - } - - except UnicodeDecodeError as e: - return { - "error": f"Failed to decode file with encoding '{encoding}': {str(e)}", - "suggestion": "Try a different encoding like 'latin-1' or 'cp1252'", - } - except PermissionError: - return {"error": f"Permission denied: {file_path}"} - except Exception as e: - return {"error": f"Failed to read file: {str(e)}"} diff --git a/aden-tools/src/aden_tools/tools/file_system_toolkits/security.py b/aden-tools/src/aden_tools/tools/file_system_toolkits/security.py index 11d7b2e5..7d68be62 100644 --- a/aden-tools/src/aden_tools/tools/file_system_toolkits/security.py +++ b/aden-tools/src/aden_tools/tools/file_system_toolkits/security.py @@ -1,6 +1,7 @@ import os -WORKSPACES_DIR = os.path.abspath(os.path.join(os.getcwd(), "workdir/workspaces")) +# Use user home directory for workspaces +WORKSPACES_DIR = os.path.expanduser("~/.hive/workdir/workspaces") def get_secure_path(path: str, workspace_id: str, agent_id: str, session_id: str) -> str: """Resolve and verify a path within a 3-layer sandbox (workspace/agent/session).""" diff --git a/aden-tools/src/aden_tools/tools/file_write_tool/README.md b/aden-tools/src/aden_tools/tools/file_write_tool/README.md deleted file mode 100644 index 9a692be4..00000000 --- a/aden-tools/src/aden_tools/tools/file_write_tool/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# File Write Tool - -Write content to local files with encoding support. - -## Description - -Can create new files or overwrite/append to existing ones. Use for saving data, creating configs, writing reports, or exporting results. Optionally creates parent directories if they don't exist. - -## Arguments - -| Argument | Type | Required | Default | Description | -|----------|------|----------|---------|-------------| -| `file_path` | str | Yes | - | Path to the file to write (absolute or relative) | -| `content` | str | Yes | - | Content to write to the file | -| `encoding` | str | No | `utf-8` | File encoding (utf-8, latin-1, etc.) | -| `mode` | str | No | `write` | Write mode - 'write' (overwrite) or 'append' | -| `create_dirs` | bool | No | `True` | Create parent directories if they don't exist | - -## Environment Variables - -This tool does not require any environment variables. - -## Error Handling - -Returns error dicts for common issues: -- `Parent directory does not exist: ` - Parent dir missing and create_dirs=False -- `Invalid mode: . Use 'write' or 'append'.` - Invalid mode specified -- `Permission denied: ` - No write access to file/directory -- `OS error writing file: ` - Filesystem error diff --git a/aden-tools/src/aden_tools/tools/file_write_tool/__init__.py b/aden-tools/src/aden_tools/tools/file_write_tool/__init__.py deleted file mode 100644 index 15380945..00000000 --- a/aden-tools/src/aden_tools/tools/file_write_tool/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -"""File Write Tool - Create or update local files.""" -from .file_write_tool import register_tools - -__all__ = ["register_tools"] diff --git a/aden-tools/src/aden_tools/tools/file_write_tool/file_write_tool.py b/aden-tools/src/aden_tools/tools/file_write_tool/file_write_tool.py deleted file mode 100644 index cb3c5f07..00000000 --- a/aden-tools/src/aden_tools/tools/file_write_tool/file_write_tool.py +++ /dev/null @@ -1,83 +0,0 @@ -""" -File Write Tool - Create or update local files. - -Supports writing text files with various encodings. -Can create directories if they don't exist. -""" -from __future__ import annotations - -from pathlib import Path - -from fastmcp import FastMCP - - -def register_tools(mcp: FastMCP) -> None: - """Register file write tools with the MCP server.""" - - @mcp.tool() - def file_write( - file_path: str, - content: str, - encoding: str = "utf-8", - mode: str = "write", - create_dirs: bool = True, - ) -> dict: - """ - Write content to a local file. - - Can create new files or overwrite/append to existing ones. - Use for saving data, creating configs, writing reports, or exporting results. - - Args: - file_path: Path to the file to write (absolute or relative) - content: Content to write to the file - encoding: File encoding (utf-8, latin-1, etc.) - mode: Write mode - 'write' (overwrite) or 'append' - create_dirs: Create parent directories if they don't exist - - Returns: - Dict with write result or error dict - """ - try: - path = Path(file_path).resolve() - - # Create parent directories if requested - if create_dirs: - path.parent.mkdir(parents=True, exist_ok=True) - elif not path.parent.exists(): - return {"error": f"Parent directory does not exist: {path.parent}"} - - # Determine write mode - if mode == "append": - write_mode = "a" - elif mode == "write": - write_mode = "w" - else: - return {"error": f"Invalid mode: {mode}. Use 'write' or 'append'."} - - # Check if we're overwriting - existed = path.exists() - previous_size = path.stat().st_size if existed else 0 - - # Write the file - with open(path, write_mode, encoding=encoding) as f: - f.write(content) - - new_size = path.stat().st_size - - return { - "path": str(path), - "name": path.name, - "bytes_written": len(content.encode(encoding)), - "total_size": new_size, - "mode": mode, - "created": not existed, - "previous_size": previous_size if existed else None, - } - - except PermissionError: - return {"error": f"Permission denied: {file_path}"} - except OSError as e: - return {"error": f"OS error writing file: {str(e)}"} - except Exception as e: - return {"error": f"Failed to write file: {str(e)}"} diff --git a/aden-tools/tests/tools/test_file_read_tool.py b/aden-tools/tests/tools/test_file_read_tool.py deleted file mode 100644 index c9902584..00000000 --- a/aden-tools/tests/tools/test_file_read_tool.py +++ /dev/null @@ -1,96 +0,0 @@ -"""Tests for file_read tool (FastMCP).""" -import pytest -from pathlib import Path - -from fastmcp import FastMCP -from aden_tools.tools.file_read_tool import register_tools - - -@pytest.fixture -def file_read_fn(mcp: FastMCP): - """Register and return the file_read tool function.""" - register_tools(mcp) - # Access the registered tool's function directly - return mcp._tool_manager._tools["file_read"].fn - - -class TestFileReadTool: - """Tests for file_read tool.""" - - def test_read_existing_file(self, file_read_fn, sample_text_file: Path): - """Reading an existing file returns content and metadata.""" - result = file_read_fn(file_path=str(sample_text_file)) - - assert "error" not in result - assert result["content"] == "Hello, World!\nLine 2\nLine 3" - assert result["name"] == "test.txt" - assert result["encoding"] == "utf-8" - assert "size" in result - - def test_read_file_not_found(self, file_read_fn, tmp_path: Path): - """Reading a non-existent file returns an error dict.""" - missing_file = tmp_path / "does_not_exist.txt" - - result = file_read_fn(file_path=str(missing_file)) - - assert "error" in result - assert "not found" in result["error"].lower() - - def test_read_directory_returns_error(self, file_read_fn, tmp_path: Path): - """Reading a directory (not a file) returns an error.""" - result = file_read_fn(file_path=str(tmp_path)) - - assert "error" in result - assert "not a file" in result["error"].lower() - - def test_read_file_too_large(self, file_read_fn, tmp_path: Path): - """Reading a file exceeding max_size returns an error.""" - large_file = tmp_path / "large.txt" - large_file.write_text("x" * 1000) - - result = file_read_fn(file_path=str(large_file), max_size=100) - - assert "error" in result - assert "too large" in result["error"].lower() - assert "file_size" in result - - def test_read_with_no_size_limit(self, file_read_fn, tmp_path: Path): - """Reading with max_size=0 allows any file size.""" - large_file = tmp_path / "large.txt" - content = "x" * 100_000 - large_file.write_text(content) - - # max_size=0 means no limit in the implementation - result = file_read_fn(file_path=str(large_file), max_size=0) - - assert "error" not in result - assert result["content"] == content - - def test_read_with_different_encoding(self, file_read_fn, tmp_path: Path): - """Reading with a specific encoding works.""" - latin_file = tmp_path / "latin.txt" - # Write bytes directly with latin-1 encoding - latin_file.write_bytes("café".encode("latin-1")) - - result = file_read_fn(file_path=str(latin_file), encoding="latin-1") - - assert "error" not in result - assert result["content"] == "café" - assert result["encoding"] == "latin-1" - - def test_read_with_wrong_encoding_returns_error(self, file_read_fn, tmp_path: Path): - """Reading with wrong encoding returns helpful error.""" - # Create a file with bytes that aren't valid UTF-8 - binary_file = tmp_path / "binary.txt" - binary_file.write_bytes(b"\xff\xfe") - - result = file_read_fn(file_path=str(binary_file), encoding="utf-8") - - assert "error" in result - assert "suggestion" in result - - def test_returns_absolute_path(self, file_read_fn, sample_text_file: Path): - """Result includes the absolute path.""" - result = file_read_fn(file_path=str(sample_text_file)) - - assert result["path"] == str(sample_text_file.resolve()) diff --git a/aden-tools/tests/tools/test_file_write_tool.py b/aden-tools/tests/tools/test_file_write_tool.py deleted file mode 100644 index ed2a3d37..00000000 --- a/aden-tools/tests/tools/test_file_write_tool.py +++ /dev/null @@ -1,99 +0,0 @@ -"""Tests for file_write tool (FastMCP).""" -import pytest -from pathlib import Path - -from fastmcp import FastMCP -from aden_tools.tools.file_write_tool import register_tools - - -@pytest.fixture -def file_write_fn(mcp: FastMCP): - """Register and return the file_write tool function.""" - register_tools(mcp) - return mcp._tool_manager._tools["file_write"].fn - - -class TestFileWriteTool: - """Tests for file_write tool.""" - - def test_write_creates_new_file(self, file_write_fn, tmp_path: Path): - """Writing to a new file creates it with content.""" - new_file = tmp_path / "new.txt" - - result = file_write_fn(file_path=str(new_file), content="Hello, World!") - - assert "error" not in result - assert result["created"] is True - assert result["name"] == "new.txt" - assert new_file.read_text() == "Hello, World!" - - def test_write_overwrites_existing(self, file_write_fn, tmp_path: Path): - """Writing to existing file overwrites by default.""" - existing = tmp_path / "existing.txt" - existing.write_text("old content") - - result = file_write_fn(file_path=str(existing), content="new content") - - assert "error" not in result - assert result["created"] is False - assert result["previous_size"] is not None - assert existing.read_text() == "new content" - - def test_write_appends_to_existing(self, file_write_fn, tmp_path: Path): - """Writing with mode='append' adds to existing content.""" - existing = tmp_path / "existing.txt" - existing.write_text("line1\n") - - result = file_write_fn(file_path=str(existing), content="line2\n", mode="append") - - assert "error" not in result - assert result["mode"] == "append" - assert existing.read_text() == "line1\nline2\n" - - def test_write_creates_parent_dirs(self, file_write_fn, tmp_path: Path): - """Writing with create_dirs=True creates missing directories.""" - deep_path = tmp_path / "nested" / "dirs" / "file.txt" - - result = file_write_fn(file_path=str(deep_path), content="content", create_dirs=True) - - assert "error" not in result - assert deep_path.exists() - assert deep_path.read_text() == "content" - - def test_write_fails_without_parent_dir(self, file_write_fn, tmp_path: Path): - """Writing with create_dirs=False fails if parent doesn't exist.""" - missing_dir = tmp_path / "missing" / "file.txt" - - result = file_write_fn(file_path=str(missing_dir), content="content", create_dirs=False) - - assert "error" in result - assert "parent directory" in result["error"].lower() - - def test_write_invalid_mode(self, file_write_fn, tmp_path: Path): - """Writing with invalid mode returns error.""" - result = file_write_fn( - file_path=str(tmp_path / "test.txt"), - content="content", - mode="invalid" - ) - - assert "error" in result - assert "invalid mode" in result["error"].lower() - - def test_write_returns_bytes_written(self, file_write_fn, tmp_path: Path): - """Result includes accurate bytes_written count.""" - content = "Hello, World!" - - result = file_write_fn(file_path=str(tmp_path / "test.txt"), content=content) - - assert result["bytes_written"] == len(content.encode("utf-8")) - - def test_write_with_encoding(self, file_write_fn, tmp_path: Path): - """Writing with specific encoding works.""" - file_path = tmp_path / "latin.txt" - - result = file_write_fn(file_path=str(file_path), content="café", encoding="latin-1") - - assert "error" not in result - # Verify it was written with latin-1 encoding - assert file_path.read_bytes() == "café".encode("latin-1") From 7fbbe63955845e0fee31e9af9bc2aed6f45a998e Mon Sep 17 00:00:00 2001 From: Samkit Shah Date: Wed, 21 Jan 2026 23:09:47 -0600 Subject: [PATCH 19/27] fix(docker): enable dev build with production target alias The Dockerfile.dev files lacked the 'production' stage alias that docker-compose.yml expects, causing build failures. Added 'AS production' to enable proper dev builds with hot reload. Fixes #26 --- hive/Dockerfile.dev | 3 ++- honeycomb/Dockerfile.dev | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/hive/Dockerfile.dev b/hive/Dockerfile.dev index 0c77b34e..f98f5b76 100644 --- a/hive/Dockerfile.dev +++ b/hive/Dockerfile.dev @@ -1,5 +1,6 @@ # Development Dockerfile with hot reload -FROM node:20-alpine +# The 'production' alias allows this to work with docker-compose.yml target +FROM node:20-alpine AS production ARG NPM_TOKEN diff --git a/honeycomb/Dockerfile.dev b/honeycomb/Dockerfile.dev index 7bec8d10..282a0d69 100644 --- a/honeycomb/Dockerfile.dev +++ b/honeycomb/Dockerfile.dev @@ -1,5 +1,6 @@ # Development Dockerfile with hot reload -FROM node:20-alpine +# The 'production' alias allows this to work with docker-compose.yml target +FROM node:20-alpine AS production WORKDIR /app From 11ed2398dc0d7853c9403e8b23351d5d14973aef Mon Sep 17 00:00:00 2001 From: Vincent Jiang Date: Wed, 21 Jan 2026 21:29:04 -0800 Subject: [PATCH 20/27] new languages on readme --- README.es.md | 243 ++++++++++++++++++++++++++++++++++++++++++++++++ README.ja.md | 243 ++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 9 ++ README.pt.md | 243 ++++++++++++++++++++++++++++++++++++++++++++++++ README.ru.md | 243 ++++++++++++++++++++++++++++++++++++++++++++++++ README.zh-CN.md | 243 ++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 1224 insertions(+) create mode 100644 README.es.md create mode 100644 README.ja.md create mode 100644 README.pt.md create mode 100644 README.ru.md create mode 100644 README.zh-CN.md diff --git a/README.es.md b/README.es.md new file mode 100644 index 00000000..e16893a9 --- /dev/null +++ b/README.es.md @@ -0,0 +1,243 @@ +

+ Hive Banner +

+ +
+ +[![Apache 2.0 License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/adenhq/hive/blob/main/LICENSE) +[![Y Combinator](https://img.shields.io/badge/Y%20Combinator-Aden-orange)](https://www.ycombinator.com/companies/aden) +[![Docker Pulls](https://img.shields.io/docker/pulls/adenhq/hive?logo=Docker&labelColor=%23528bff)](https://hub.docker.com/u/adenhq) +[![Discord](https://img.shields.io/discord/1172610340073242735?logo=discord&labelColor=%235462eb&logoColor=%23f5f5f5&color=%235462eb)](https://discord.com/invite/MXE49hrKDk) +[![Twitter Follow](https://img.shields.io/twitter/follow/teamaden?logo=X&color=%23f5f5f5)](https://x.com/aden_hq) +[![LinkedIn](https://custom-icon-badges.demolab.com/badge/LinkedIn-0A66C2?logo=linkedin-white&logoColor=fff)](https://www.linkedin.com/company/teamaden/) + +

+ AI Agents + Multi-Agent + Goal-Driven + HITL + Production +

+

+ OpenAI + Anthropic + Gemini + MCP +

+ +## Descripción General + +Construye agentes de IA confiables y auto-mejorables sin codificar flujos de trabajo. Define tu objetivo a través de una conversación con un agente de codificación, y el framework genera un grafo de nodos con código de conexión creado dinámicamente. Cuando algo falla, el framework captura los datos del error, evoluciona el agente a través del agente de codificación y lo vuelve a desplegar. Los nodos de intervención humana integrados, la gestión de credenciales y el monitoreo en tiempo real te dan control sin sacrificar la adaptabilidad. + +Visita [adenhq.com](https://adenhq.com) para documentación completa, ejemplos y guías. + +## ¿Qué es Aden? + +

+ Aden Architecture +

+ +Aden es una plataforma para construir, desplegar, operar y adaptar agentes de IA: + +- **Construir** - Un Agente de Codificación genera Agentes de Trabajo especializados (Ventas, Marketing, Operaciones) a partir de objetivos en lenguaje natural +- **Desplegar** - Despliegue headless con integración CI/CD y gestión completa del ciclo de vida de API +- **Operar** - Monitoreo en tiempo real, observabilidad y guardarraíles de ejecución mantienen los agentes confiables +- **Adaptar** - Evaluación continua, supervisión y adaptación aseguran que los agentes mejoren con el tiempo +- **Infraestructura** - Memoria compartida, integraciones LLM, herramientas y habilidades impulsan cada agente + +## Enlaces Rápidos + +- **[Documentación](https://docs.adenhq.com/)** - Guías completas y referencia de API +- **[Guía de Auto-Hospedaje](https://docs.adenhq.com/getting-started/quickstart)** - Despliega Hive en tu infraestructura +- **[Registro de Cambios](https://github.com/adenhq/hive/releases)** - Últimas actualizaciones y versiones +- **[Reportar Problemas](https://github.com/adenhq/hive/issues)** - Reportes de bugs y solicitudes de funciones + +## Inicio Rápido + +### Prerrequisitos + +- [Docker](https://docs.docker.com/get-docker/) (v20.10+) +- [Docker Compose](https://docs.docker.com/compose/install/) (v2.0+) + +### Instalación + +```bash +# Clonar el repositorio +git clone https://github.com/adenhq/hive.git +cd hive + +# Copiar y configurar +cp config.yaml.example config.yaml + +# Ejecutar configuración e iniciar servicios +npm run setup +docker compose up +``` + +**Acceder a la aplicación:** + +- Panel de Control: http://localhost:3000 +- API: http://localhost:4000 +- Salud: http://localhost:4000/health + +## Características + +- **Desarrollo Orientado a Objetivos** - Define objetivos en lenguaje natural; el agente de codificación genera el grafo de agentes y el código de conexión para lograrlos +- **Agentes Auto-Adaptables** - El framework captura fallos, actualiza objetivos y actualiza el grafo de agentes +- **Conexiones de Nodos Dinámicas** - Sin aristas predefinidas; el código de conexión es generado por cualquier LLM capaz basado en tus objetivos +- **Nodos Envueltos en SDK** - Cada nodo obtiene memoria compartida, memoria RLM local, monitoreo, herramientas y acceso LLM de serie +- **Humano en el Bucle** - Nodos de intervención que pausan la ejecución para entrada humana con tiempos de espera y escalación configurables +- **Observabilidad en Tiempo Real** - Streaming WebSocket para monitoreo en vivo de ejecución de agentes, decisiones y comunicación entre nodos +- **Control de Costos y Presupuesto** - Establece límites de gasto, limitadores y políticas de degradación automática de modelos +- **Listo para Producción** - Auto-hospedable, construido para escala y confiabilidad + +## Por Qué Aden + +Los frameworks de agentes tradicionales requieren que diseñes manualmente flujos de trabajo, definas interacciones de agentes y manejes fallos de forma reactiva. Aden invierte este paradigma—**describes resultados, y el sistema se construye solo**. + +### La Ventaja de Aden + +| Frameworks Tradicionales | Aden | +|--------------------------|------| +| Codificar flujos de trabajo de agentes | Describir objetivos en lenguaje natural | +| Definición manual de grafos | Grafos de agentes auto-generados | +| Manejo reactivo de errores | Auto-evolución proactiva | +| Configuraciones de herramientas estáticas | Nodos dinámicos envueltos en SDK | +| Configuración de monitoreo separada | Observabilidad en tiempo real integrada | +| Gestión de presupuesto DIY | Controles de costos y degradación integrados | + +### Cómo Funciona + +1. **Define Tu Objetivo** → Describe lo que quieres lograr en español simple +2. **El Agente de Codificación Genera** → Crea el grafo de agentes, código de conexión y casos de prueba +3. **Los Trabajadores Ejecutan** → Los nodos envueltos en SDK se ejecutan con observabilidad completa y acceso a herramientas +4. **El Plano de Control Monitorea** → Métricas en tiempo real, aplicación de presupuesto, gestión de políticas +5. **Auto-Mejora** → En caso de fallo, el sistema evoluciona el grafo y lo vuelve a desplegar automáticamente + +## Estructura del Proyecto + +``` +hive/ +├── honeycomb/ # Frontend (React + TypeScript + Vite) +├── hive/ # Backend (Node.js + TypeScript + Express) +├── docs/ # Documentación +├── scripts/ # Scripts de construcción y utilidades +├── config.yaml.example # Plantilla de configuración +└── docker-compose.yml # Orquestación de contenedores +``` + +## Desarrollo + +### Desarrollo Local con Recarga en Caliente + +```bash +# Copiar sobrescrituras de desarrollo +cp docker-compose.override.yml.example docker-compose.override.yml + +# Iniciar con recarga en caliente habilitada +docker compose up +``` + +### Ejecutar Sin Docker + +```bash +# Instalar dependencias +npm install + +# Generar archivos de entorno +npm run generate:env + +# Iniciar frontend (en honeycomb/) +cd honeycomb && npm run dev + +# Iniciar backend (en hive/) +cd hive && npm run dev +``` + +## Documentación + +- **[Guía del Desarrollador](DEVELOPER.md)** - Guía completa para desarrolladores +- [Primeros Pasos](docs/getting-started.md) - Instrucciones de configuración rápida +- [Guía de Configuración](docs/configuration.md) - Todas las opciones de configuración +- [Visión General de Arquitectura](docs/architecture.md) - Diseño y estructura del sistema + +## Hoja de Ruta + +El Framework de Agentes Aden tiene como objetivo ayudar a los desarrolladores a construir agentes auto-adaptativos orientados a resultados. Encuentra nuestra hoja de ruta aquí: + +[ROADMAP.md](ROADMAP.md) + +## Comunidad y Soporte + +Usamos [Discord](https://discord.com/invite/MXE49hrKDk) para soporte, solicitudes de funciones y discusiones de la comunidad. + +- Discord - [Únete a nuestra comunidad](https://discord.com/invite/MXE49hrKDk) +- Twitter/X - [@adenhq](https://x.com/aden_hq) +- LinkedIn - [Página de la Empresa](https://www.linkedin.com/company/teamaden/) + +## Contribuir + +¡Damos la bienvenida a las contribuciones! Por favor consulta [CONTRIBUTING.md](CONTRIBUTING.md) para las directrices. + +1. Haz fork del repositorio +2. Crea tu rama de funcionalidad (`git checkout -b feature/amazing-feature`) +3. Haz commit de tus cambios (`git commit -m 'Add amazing feature'`) +4. Haz push a la rama (`git push origin feature/amazing-feature`) +5. Abre un Pull Request + +## Únete a Nuestro Equipo + +**¡Estamos contratando!** Únete a nosotros en roles de ingeniería, investigación y comercialización. + +[Ver Posiciones Abiertas](https://jobs.adenhq.com/a8cec478-cdbc-473c-bbd4-f4b7027ec193/applicant) + +## Seguridad + +Para preocupaciones de seguridad, por favor consulta [SECURITY.md](SECURITY.md). + +## Licencia + +Este proyecto está licenciado bajo la Licencia Apache 2.0 - consulta el archivo [LICENSE](LICENSE) para más detalles. + +## Preguntas Frecuentes (FAQ) + +**P: ¿Aden depende de LangChain u otros frameworks de agentes?** + +No. Aden está construido desde cero sin dependencias de LangChain, CrewAI u otros frameworks de agentes. El framework está diseñado para ser ligero y flexible, generando grafos de agentes dinámicamente en lugar de depender de componentes predefinidos. + +**P: ¿Qué proveedores de LLM soporta Aden?** + +Aden soporta OpenAI (GPT-4, GPT-4o), Anthropic (modelos Claude) y Google Gemini de serie. La arquitectura es agnóstica al proveedor a través de la abstracción del SDK, con integración de LiteLLM en la hoja de ruta para soporte expandido de modelos. + +**P: ¿Aden es de código abierto?** + +Sí, Aden es completamente de código abierto bajo la Licencia Apache 2.0. Fomentamos activamente las contribuciones y colaboración de la comunidad. + +**P: ¿Qué opciones de despliegue soporta Aden?** + +Aden soporta despliegue con Docker Compose de serie, con configuraciones tanto de producción como de desarrollo. Los despliegues auto-hospedados funcionan en cualquier infraestructura que soporte Docker. Las opciones de despliegue en la nube y configuraciones listas para Kubernetes están en la hoja de ruta. + +**P: ¿Puede Aden manejar casos de uso complejos a escala de producción?** + +Sí. Aden está explícitamente diseñado para entornos de producción con características como recuperación automática de fallos, observabilidad en tiempo real, controles de costos y soporte de escalado horizontal. El framework maneja tanto automatizaciones simples como flujos de trabajo complejos multi-agente. + +**P: ¿Aden soporta flujos de trabajo con humano en el bucle?** + +Sí, Aden soporta completamente flujos de trabajo con humano en el bucle a través de nodos de intervención que pausan la ejecución para entrada humana. Estos incluyen tiempos de espera configurables y políticas de escalación, permitiendo colaboración fluida entre expertos humanos y agentes de IA. + +**P: ¿Cómo puedo contribuir a Aden?** + +¡Las contribuciones son bienvenidas! Haz fork del repositorio, crea tu rama de funcionalidad, implementa tus cambios y envía un pull request. Consulta [CONTRIBUTING.md](CONTRIBUTING.md) para directrices detalladas. + +--- + +

+ Hecho con 🔥 Pasión en San Francisco +

diff --git a/README.ja.md b/README.ja.md new file mode 100644 index 00000000..b09b8f78 --- /dev/null +++ b/README.ja.md @@ -0,0 +1,243 @@ +

+ Hive Banner +

+ +

+ English | + 简体中文 | + Español | + Português | + 日本語 | + Русский +

+ +[![Apache 2.0 License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/adenhq/hive/blob/main/LICENSE) +[![Y Combinator](https://img.shields.io/badge/Y%20Combinator-Aden-orange)](https://www.ycombinator.com/companies/aden) +[![Docker Pulls](https://img.shields.io/docker/pulls/adenhq/hive?logo=Docker&labelColor=%23528bff)](https://hub.docker.com/u/adenhq) +[![Discord](https://img.shields.io/discord/1172610340073242735?logo=discord&labelColor=%235462eb&logoColor=%23f5f5f5&color=%235462eb)](https://discord.com/invite/MXE49hrKDk) +[![Twitter Follow](https://img.shields.io/twitter/follow/teamaden?logo=X&color=%23f5f5f5)](https://x.com/aden_hq) +[![LinkedIn](https://custom-icon-badges.demolab.com/badge/LinkedIn-0A66C2?logo=linkedin-white&logoColor=fff)](https://www.linkedin.com/company/teamaden/) + +

+ AI Agents + Multi-Agent + Goal-Driven + HITL + Production +

+

+ OpenAI + Anthropic + Gemini + MCP +

+ +## 概要 + +ワークフローをハードコーディングせずに、信頼性の高い自己改善型AIエージェントを構築できます。コーディングエージェントとの会話を通じて目標を定義すると、フレームワークが動的に作成された接続コードを持つノードグラフを生成します。問題が発生すると、フレームワークは障害データをキャプチャし、コーディングエージェントを通じてエージェントを進化させ、再デプロイします。組み込みのヒューマンインザループノード、認証情報管理、リアルタイムモニタリングにより、適応性を損なうことなく制御を維持できます。 + +完全なドキュメント、例、ガイドについては [adenhq.com](https://adenhq.com) をご覧ください。 + +## Adenとは + +

+ Aden Architecture +

+ +Adenは、AIエージェントの構築、デプロイ、運用、適応のためのプラットフォームです: + +- **構築** - コーディングエージェントが自然言語の目標から専門的なワーカーエージェント(セールス、マーケティング、オペレーション)を生成 +- **デプロイ** - CI/CD統合と完全なAPIライフサイクル管理を備えたヘッドレスデプロイメント +- **運用** - リアルタイムモニタリング、可観測性、ランタイムガードレールがエージェントの信頼性を維持 +- **適応** - 継続的な評価、監督、適応により、エージェントは時間とともに改善 +- **インフラ** - 共有メモリ、LLM統合、ツール、スキルがすべてのエージェントを支援 + +## クイックリンク + +- **[ドキュメント](https://docs.adenhq.com/)** - 完全なガイドとAPIリファレンス +- **[セルフホスティングガイド](https://docs.adenhq.com/getting-started/quickstart)** - インフラストラクチャへのHiveデプロイ +- **[変更履歴](https://github.com/adenhq/hive/releases)** - 最新の更新とリリース +- **[問題を報告](https://github.com/adenhq/hive/issues)** - バグレポートと機能リクエスト + +## クイックスタート + +### 前提条件 + +- [Docker](https://docs.docker.com/get-docker/) (v20.10+) +- [Docker Compose](https://docs.docker.com/compose/install/) (v2.0+) + +### インストール + +```bash +# リポジトリをクローン +git clone https://github.com/adenhq/hive.git +cd hive + +# コピーして設定 +cp config.yaml.example config.yaml + +# セットアップを実行してサービスを開始 +npm run setup +docker compose up +``` + +**アプリケーションにアクセス:** + +- ダッシュボード:http://localhost:3000 +- API:http://localhost:4000 +- ヘルスチェック:http://localhost:4000/health + +## 機能 + +- **目標駆動開発** - 自然言語で目標を定義;コーディングエージェントがそれを達成するためのエージェントグラフと接続コードを生成 +- **自己適応エージェント** - フレームワークが障害をキャプチャし、目標を更新し、エージェントグラフを更新 +- **動的ノード接続** - 事前定義されたエッジなし;接続コードは目標に基づいて任意の対応LLMによって生成 +- **SDKラップノード** - すべてのノードが共有メモリ、ローカルRLMメモリ、モニタリング、ツール、LLMアクセスを標準装備 +- **ヒューマンインザループ** - 設定可能なタイムアウトとエスカレーションを備えた、人間の入力のために実行を一時停止する介入ノード +- **リアルタイム可観測性** - エージェント実行、決定、ノード間通信のライブモニタリングのためのWebSocketストリーミング +- **コストと予算管理** - 支出制限、スロットル、自動モデル劣化ポリシーを設定 +- **本番環境対応** - セルフホスト可能、スケールと信頼性のために構築 + +## なぜAdenか + +従来のエージェントフレームワークでは、ワークフローを手動で設計し、エージェントの相互作用を定義し、障害を事後的に処理する必要があります。Adenはこのパラダイムを逆転させます—**結果を記述すれば、システムが自ら構築します**。 + +### Adenの優位性 + +| 従来のフレームワーク | Aden | +|----------------------|------| +| エージェントワークフローをハードコード | 自然言語で目標を記述 | +| 手動でグラフを定義 | 自動生成されるエージェントグラフ | +| 事後的なエラー処理 | プロアクティブな自己進化 | +| 静的なツール設定 | 動的なSDKラップノード | +| 別途モニタリング設定 | 組み込みのリアルタイム可観測性 | +| DIY予算管理 | 統合されたコスト制御と劣化 | + +### 仕組み + +1. **目標を定義** → 達成したいことを平易な言葉で記述 +2. **コーディングエージェントが生成** → エージェントグラフ、接続コード、テストケースを作成 +3. **ワーカーが実行** → SDKラップノードが完全な可観測性とツールアクセスで実行 +4. **コントロールプレーンが監視** → リアルタイムメトリクス、予算執行、ポリシー管理 +5. **自己改善** → 障害時、システムがグラフを進化させ自動的に再デプロイ + +## プロジェクト構造 + +``` +hive/ +├── honeycomb/ # フロントエンド (React + TypeScript + Vite) +├── hive/ # バックエンド (Node.js + TypeScript + Express) +├── docs/ # ドキュメント +├── scripts/ # ビルドとユーティリティスクリプト +├── config.yaml.example # 設定テンプレート +└── docker-compose.yml # コンテナオーケストレーション +``` + +## 開発 + +### ホットリロードでのローカル開発 + +```bash +# 開発用オーバーライドをコピー +cp docker-compose.override.yml.example docker-compose.override.yml + +# ホットリロードを有効にして開始 +docker compose up +``` + +### Dockerなしで実行 + +```bash +# 依存関係をインストール +npm install + +# 環境ファイルを生成 +npm run generate:env + +# フロントエンドを開始(honeycomb/内) +cd honeycomb && npm run dev + +# バックエンドを開始(hive/内) +cd hive && npm run dev +``` + +## ドキュメント + +- **[開発者ガイド](DEVELOPER.md)** - 開発者向け総合ガイド +- [はじめに](docs/getting-started.md) - クイックセットアップ手順 +- [設定ガイド](docs/configuration.md) - すべての設定オプション +- [アーキテクチャ概要](docs/architecture.md) - システム設計と構造 + +## ロードマップ + +Adenエージェントフレームワークは、開発者が結果志向で自己適応するエージェントを構築できるよう支援することを目指しています。ロードマップはこちらをご覧ください: + +[ROADMAP.md](ROADMAP.md) + +## コミュニティとサポート + +サポート、機能リクエスト、コミュニティディスカッションには[Discord](https://discord.com/invite/MXE49hrKDk)を使用しています。 + +- Discord - [コミュニティに参加](https://discord.com/invite/MXE49hrKDk) +- Twitter/X - [@adenhq](https://x.com/aden_hq) +- LinkedIn - [会社ページ](https://www.linkedin.com/company/teamaden/) + +## 貢献 + +貢献を歓迎します!ガイドラインについては[CONTRIBUTING.md](CONTRIBUTING.md)をご覧ください。 + +1. リポジトリをフォーク +2. 機能ブランチを作成 (`git checkout -b feature/amazing-feature`) +3. 変更をコミット (`git commit -m 'Add amazing feature'`) +4. ブランチにプッシュ (`git push origin feature/amazing-feature`) +5. プルリクエストを開く + +## チームに参加 + +**採用中です!** エンジニアリング、リサーチ、マーケティングの役職で私たちに参加してください。 + +[オープンポジションを見る](https://jobs.adenhq.com/a8cec478-cdbc-473c-bbd4-f4b7027ec193/applicant) + +## セキュリティ + +セキュリティに関する懸念については、[SECURITY.md](SECURITY.md)をご覧ください。 + +## ライセンス + +このプロジェクトはApache License 2.0の下でライセンスされています - 詳細は[LICENSE](LICENSE)ファイルをご覧ください。 + +## よくある質問 (FAQ) + +**Q: AdenはLangChainや他のエージェントフレームワークに依存していますか?** + +いいえ。AdenはLangChain、CrewAI、その他のエージェントフレームワークに依存せずにゼロから構築されています。フレームワークは軽量で柔軟に設計されており、事前定義されたコンポーネントに依存するのではなく、エージェントグラフを動的に生成します。 + +**Q: AdenはどのLLMプロバイダーをサポートしていますか?** + +AdenはOpenAI(GPT-4、GPT-4o)、Anthropic(Claudeモデル)、Google Geminiを標準でサポートしています。アーキテクチャはSDK抽象化によりプロバイダー非依存であり、拡張モデルサポートのためのLiteLLM統合がロードマップにあります。 + +**Q: Adenはオープンソースですか?** + +はい、AdenはApache License 2.0の下で完全にオープンソースです。コミュニティの貢献とコラボレーションを積極的に奨励しています。 + +**Q: Adenはどのデプロイオプションをサポートしていますか?** + +Adenは本番環境と開発環境の両方の設定でDocker Composeデプロイを標準でサポートしています。セルフホストデプロイはDockerをサポートする任意のインフラストラクチャで動作します。クラウドデプロイオプションとKubernetes対応設定はロードマップにあります。 + +**Q: Adenは複雑な本番規模のユースケースを処理できますか?** + +はい。Adenは自動障害回復、リアルタイム可観測性、コスト制御、水平スケーリングサポートなどの機能を備え、本番環境向けに明示的に設計されています。フレームワークは単純な自動化から複雑なマルチエージェントワークフローまで処理できます。 + +**Q: Adenはヒューマンインザループワークフローをサポートしていますか?** + +はい、Adenは人間の入力のために実行を一時停止する介入ノードを通じて、ヒューマンインザループワークフローを完全にサポートしています。設定可能なタイムアウトとエスカレーションポリシーが含まれており、人間の専門家とAIエージェントのシームレスなコラボレーションを可能にします。 + +**Q: Adenに貢献するにはどうすればよいですか?** + +貢献を歓迎します!リポジトリをフォークし、機能ブランチを作成し、変更を実装して、プルリクエストを送信してください。詳細なガイドラインについては[CONTRIBUTING.md](CONTRIBUTING.md)をご覧ください。 + +--- + +

+ サンフランシスコで 🔥 情熱を込めて作成 +

diff --git a/README.md b/README.md index 36721b25..2514f7de 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,15 @@ Hive Banner

+

+ English | + 简体中文 | + Español | + Português | + 日本語 | + Русский +

+ [![Apache 2.0 License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/adenhq/hive/blob/main/LICENSE) [![Y Combinator](https://img.shields.io/badge/Y%20Combinator-Aden-orange)](https://www.ycombinator.com/companies/aden) [![Docker Pulls](https://img.shields.io/docker/pulls/adenhq/hive?logo=Docker&labelColor=%23528bff)](https://hub.docker.com/u/adenhq) diff --git a/README.pt.md b/README.pt.md new file mode 100644 index 00000000..18c4a8e1 --- /dev/null +++ b/README.pt.md @@ -0,0 +1,243 @@ +

+ Hive Banner +

+ +

+ English | + 简体中文 | + Español | + Português | + 日本語 | + Русский +

+ +[![Apache 2.0 License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/adenhq/hive/blob/main/LICENSE) +[![Y Combinator](https://img.shields.io/badge/Y%20Combinator-Aden-orange)](https://www.ycombinator.com/companies/aden) +[![Docker Pulls](https://img.shields.io/docker/pulls/adenhq/hive?logo=Docker&labelColor=%23528bff)](https://hub.docker.com/u/adenhq) +[![Discord](https://img.shields.io/discord/1172610340073242735?logo=discord&labelColor=%235462eb&logoColor=%23f5f5f5&color=%235462eb)](https://discord.com/invite/MXE49hrKDk) +[![Twitter Follow](https://img.shields.io/twitter/follow/teamaden?logo=X&color=%23f5f5f5)](https://x.com/aden_hq) +[![LinkedIn](https://custom-icon-badges.demolab.com/badge/LinkedIn-0A66C2?logo=linkedin-white&logoColor=fff)](https://www.linkedin.com/company/teamaden/) + +

+ AI Agents + Multi-Agent + Goal-Driven + HITL + Production +

+

+ OpenAI + Anthropic + Gemini + MCP +

+ +## Visão Geral + +Construa agentes de IA confiáveis e auto-aperfeiçoáveis sem codificar fluxos de trabalho. Defina seu objetivo através de uma conversa com um agente de codificação, e o framework gera um grafo de nós com código de conexão criado dinamicamente. Quando algo quebra, o framework captura dados de falha, evolui o agente através do agente de codificação e reimplanta. Nós de intervenção humana integrados, gerenciamento de credenciais e monitoramento em tempo real dão a você controle sem sacrificar a adaptabilidade. + +Visite [adenhq.com](https://adenhq.com) para documentação completa, exemplos e guias. + +## O que é Aden + +

+ Aden Architecture +

+ +Aden é uma plataforma para construir, implantar, operar e adaptar agentes de IA: + +- **Construir** - Um Agente de Codificação gera Agentes de Trabalho especializados (Vendas, Marketing, Operações) a partir de objetivos em linguagem natural +- **Implantar** - Implantação headless com integração CI/CD e gerenciamento completo do ciclo de vida de API +- **Operar** - Monitoramento em tempo real, observabilidade e guardrails de runtime mantêm os agentes confiáveis +- **Adaptar** - Avaliação contínua, supervisão e adaptação garantem que os agentes melhorem ao longo do tempo +- **Infraestrutura** - Memória compartilhada, integrações LLM, ferramentas e habilidades alimentam cada agente + +## Links Rápidos + +- **[Documentação](https://docs.adenhq.com/)** - Guias completos e referência de API +- **[Guia de Auto-Hospedagem](https://docs.adenhq.com/getting-started/quickstart)** - Implante o Hive em sua infraestrutura +- **[Changelog](https://github.com/adenhq/hive/releases)** - Últimas atualizações e versões +- **[Reportar Problemas](https://github.com/adenhq/hive/issues)** - Relatórios de bugs e solicitações de funcionalidades + +## Início Rápido + +### Pré-requisitos + +- [Docker](https://docs.docker.com/get-docker/) (v20.10+) +- [Docker Compose](https://docs.docker.com/compose/install/) (v2.0+) + +### Instalação + +```bash +# Clonar o repositório +git clone https://github.com/adenhq/hive.git +cd hive + +# Copiar e configurar +cp config.yaml.example config.yaml + +# Executar configuração e iniciar serviços +npm run setup +docker compose up +``` + +**Acessar a aplicação:** + +- Dashboard: http://localhost:3000 +- API: http://localhost:4000 +- Health: http://localhost:4000/health + +## Funcionalidades + +- **Desenvolvimento Orientado a Objetivos** - Defina objetivos em linguagem natural; o agente de codificação gera o grafo de agentes e código de conexão para alcançá-los +- **Agentes Auto-Adaptáveis** - Framework captura falhas, atualiza objetivos e atualiza o grafo de agentes +- **Conexões de Nós Dinâmicas** - Sem arestas predefinidas; código de conexão é gerado por qualquer LLM capaz baseado em seus objetivos +- **Nós Envolvidos em SDK** - Cada nó recebe memória compartilhada, memória RLM local, monitoramento, ferramentas e acesso LLM prontos para uso +- **Humano no Loop** - Nós de intervenção que pausam a execução para entrada humana com timeouts e escalonamento configuráveis +- **Observabilidade em Tempo Real** - Streaming WebSocket para monitoramento ao vivo de execução de agentes, decisões e comunicação entre nós +- **Controle de Custo e Orçamento** - Defina limites de gastos, throttles e políticas de degradação automática de modelo +- **Pronto para Produção** - Auto-hospedável, construído para escala e confiabilidade + +## Por que Aden + +Frameworks de agentes tradicionais exigem que você projete manualmente fluxos de trabalho, defina interações de agentes e lide com falhas reativamente. Aden inverte esse paradigma—**você descreve resultados, e o sistema se constrói sozinho**. + +### A Vantagem Aden + +| Frameworks Tradicionais | Aden | +|-------------------------|------| +| Codificar fluxos de trabalho de agentes | Descrever objetivos em linguagem natural | +| Definição manual de grafos | Grafos de agentes auto-gerados | +| Tratamento reativo de erros | Auto-evolução proativa | +| Configurações de ferramentas estáticas | Nós dinâmicos envolvidos em SDK | +| Configuração de monitoramento separada | Observabilidade em tempo real integrada | +| Gerenciamento de orçamento DIY | Controles de custo e degradação integrados | + +### Como Funciona + +1. **Defina Seu Objetivo** → Descreva o que você quer alcançar em português simples +2. **Agente de Codificação Gera** → Cria o grafo de agentes, código de conexão e casos de teste +3. **Workers Executam** → Nós envolvidos em SDK executam com observabilidade completa e acesso a ferramentas +4. **Plano de Controle Monitora** → Métricas em tempo real, aplicação de orçamento, gerenciamento de políticas +5. **Auto-Aperfeiçoamento** → Em caso de falha, o sistema evolui o grafo e reimplanta automaticamente + +## Estrutura do Projeto + +``` +hive/ +├── honeycomb/ # Frontend (React + TypeScript + Vite) +├── hive/ # Backend (Node.js + TypeScript + Express) +├── docs/ # Documentação +├── scripts/ # Scripts de build e utilitários +├── config.yaml.example # Template de configuração +└── docker-compose.yml # Orquestração de containers +``` + +## Desenvolvimento + +### Desenvolvimento Local com Hot Reload + +```bash +# Copiar overrides de desenvolvimento +cp docker-compose.override.yml.example docker-compose.override.yml + +# Iniciar com hot reload habilitado +docker compose up +``` + +### Executar Sem Docker + +```bash +# Instalar dependências +npm install + +# Gerar arquivos de ambiente +npm run generate:env + +# Iniciar frontend (em honeycomb/) +cd honeycomb && npm run dev + +# Iniciar backend (em hive/) +cd hive && npm run dev +``` + +## Documentação + +- **[Guia do Desenvolvedor](DEVELOPER.md)** - Guia abrangente para desenvolvedores +- [Começando](docs/getting-started.md) - Instruções de configuração rápida +- [Guia de Configuração](docs/configuration.md) - Todas as opções de configuração +- [Visão Geral da Arquitetura](docs/architecture.md) - Design e estrutura do sistema + +## Roadmap + +O Aden Agent Framework visa ajudar desenvolvedores a construir agentes auto-adaptativos orientados a resultados. Encontre nosso roadmap aqui: + +[ROADMAP.md](ROADMAP.md) + +## Comunidade e Suporte + +Usamos [Discord](https://discord.com/invite/MXE49hrKDk) para suporte, solicitações de funcionalidades e discussões da comunidade. + +- Discord - [Junte-se à nossa comunidade](https://discord.com/invite/MXE49hrKDk) +- Twitter/X - [@adenhq](https://x.com/aden_hq) +- LinkedIn - [Página da Empresa](https://www.linkedin.com/company/teamaden/) + +## Contribuindo + +Aceitamos contribuições! Por favor, consulte [CONTRIBUTING.md](CONTRIBUTING.md) para diretrizes. + +1. Faça fork do repositório +2. Crie sua branch de funcionalidade (`git checkout -b feature/amazing-feature`) +3. Faça commit das suas alterações (`git commit -m 'Add amazing feature'`) +4. Faça push para a branch (`git push origin feature/amazing-feature`) +5. Abra um Pull Request + +## Junte-se ao Nosso Time + +**Estamos contratando!** Junte-se a nós em funções de engenharia, pesquisa e go-to-market. + +[Ver Posições Abertas](https://jobs.adenhq.com/a8cec478-cdbc-473c-bbd4-f4b7027ec193/applicant) + +## Segurança + +Para questões de segurança, por favor consulte [SECURITY.md](SECURITY.md). + +## Licença + +Este projeto está licenciado sob a Licença Apache 2.0 - veja o arquivo [LICENSE](LICENSE) para detalhes. + +## Perguntas Frequentes (FAQ) + +**P: O Aden depende do LangChain ou outros frameworks de agentes?** + +Não. O Aden é construído do zero sem dependências do LangChain, CrewAI ou outros frameworks de agentes. O framework é projetado para ser leve e flexível, gerando grafos de agentes dinamicamente em vez de depender de componentes predefinidos. + +**P: Quais provedores de LLM o Aden suporta?** + +O Aden suporta OpenAI (GPT-4, GPT-4o), Anthropic (modelos Claude) e Google Gemini prontos para uso. A arquitetura é agnóstica de provedor através da abstração do SDK, com integração LiteLLM no roadmap para suporte expandido de modelos. + +**P: O Aden é open-source?** + +Sim, o Aden é totalmente open-source sob a Licença Apache 2.0. Incentivamos ativamente contribuições e colaboração da comunidade. + +**P: Quais opções de implantação o Aden suporta?** + +O Aden suporta implantação Docker Compose pronta para uso, com configurações de produção e desenvolvimento. Implantações auto-hospedadas funcionam em qualquer infraestrutura que suporte Docker. Opções de implantação em nuvem e configurações prontas para Kubernetes estão no roadmap. + +**P: O Aden pode lidar com casos de uso complexos em escala de produção?** + +Sim. O Aden é explicitamente projetado para ambientes de produção com recursos como recuperação automática de falhas, observabilidade em tempo real, controles de custo e suporte a escalonamento horizontal. O framework lida tanto com automações simples quanto com fluxos de trabalho complexos multi-agente. + +**P: O Aden suporta fluxos de trabalho com humano no loop?** + +Sim, o Aden suporta totalmente fluxos de trabalho com humano no loop através de nós de intervenção que pausam a execução para entrada humana. Estes incluem timeouts configuráveis e políticas de escalonamento, permitindo colaboração perfeita entre especialistas humanos e agentes de IA. + +**P: Como posso contribuir para o Aden?** + +Contribuições são bem-vindas! Faça fork do repositório, crie sua branch de funcionalidade, implemente suas alterações e envie um pull request. Consulte [CONTRIBUTING.md](CONTRIBUTING.md) para diretrizes detalhadas. + +--- + +

+ Feito com 🔥 Paixão em San Francisco +

diff --git a/README.ru.md b/README.ru.md new file mode 100644 index 00000000..c5cb2c9f --- /dev/null +++ b/README.ru.md @@ -0,0 +1,243 @@ +

+ Hive Banner +

+ +

+ English | + 简体中文 | + Español | + Português | + 日本語 | + Русский +

+ +[![Apache 2.0 License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/adenhq/hive/blob/main/LICENSE) +[![Y Combinator](https://img.shields.io/badge/Y%20Combinator-Aden-orange)](https://www.ycombinator.com/companies/aden) +[![Docker Pulls](https://img.shields.io/docker/pulls/adenhq/hive?logo=Docker&labelColor=%23528bff)](https://hub.docker.com/u/adenhq) +[![Discord](https://img.shields.io/discord/1172610340073242735?logo=discord&labelColor=%235462eb&logoColor=%23f5f5f5&color=%235462eb)](https://discord.com/invite/MXE49hrKDk) +[![Twitter Follow](https://img.shields.io/twitter/follow/teamaden?logo=X&color=%23f5f5f5)](https://x.com/aden_hq) +[![LinkedIn](https://custom-icon-badges.demolab.com/badge/LinkedIn-0A66C2?logo=linkedin-white&logoColor=fff)](https://www.linkedin.com/company/teamaden/) + +

+ AI Agents + Multi-Agent + Goal-Driven + HITL + Production +

+

+ OpenAI + Anthropic + Gemini + MCP +

+ +## Обзор + +Создавайте надёжных, самосовершенствующихся ИИ-агентов без жёсткого кодирования рабочих процессов. Определите свою цель через разговор с кодирующим агентом, и фреймворк сгенерирует граф узлов с динамически созданным кодом соединений. Когда что-то ломается, фреймворк захватывает данные об ошибке, эволюционирует агента через кодирующего агента и переразвёртывает. Встроенные узлы человеческого вмешательства, управление учётными данными и мониторинг в реальном времени дают вам контроль без ущерба для адаптивности. + +Посетите [adenhq.com](https://adenhq.com) для полной документации, примеров и руководств. + +## Что такое Aden + +

+ Aden Architecture +

+ +Aden — это платформа для создания, развёртывания, эксплуатации и адаптации ИИ-агентов: + +- **Создание** - Кодирующий агент генерирует специализированных рабочих агентов (продажи, маркетинг, операции) из целей на естественном языке +- **Развёртывание** - Headless-развёртывание с интеграцией CI/CD и полным управлением жизненным циклом API +- **Эксплуатация** - Мониторинг в реальном времени, наблюдаемость и защитные барьеры времени выполнения обеспечивают надёжность агентов +- **Адаптация** - Непрерывная оценка, контроль и адаптация гарантируют улучшение агентов со временем +- **Инфраструктура** - Общая память, интеграции LLM, инструменты и навыки питают каждого агента + +## Быстрые ссылки + +- **[Документация](https://docs.adenhq.com/)** - Полные руководства и справочник API +- **[Руководство по самостоятельному хостингу](https://docs.adenhq.com/getting-started/quickstart)** - Разверните Hive в своей инфраструктуре +- **[История изменений](https://github.com/adenhq/hive/releases)** - Последние обновления и релизы +- **[Сообщить о проблеме](https://github.com/adenhq/hive/issues)** - Отчёты об ошибках и запросы функций + +## Быстрый старт + +### Предварительные требования + +- [Docker](https://docs.docker.com/get-docker/) (v20.10+) +- [Docker Compose](https://docs.docker.com/compose/install/) (v2.0+) + +### Установка + +```bash +# Клонировать репозиторий +git clone https://github.com/adenhq/hive.git +cd hive + +# Скопировать и настроить +cp config.yaml.example config.yaml + +# Запустить настройку и запустить сервисы +npm run setup +docker compose up +``` + +**Доступ к приложению:** + +- Панель управления: http://localhost:3000 +- API: http://localhost:4000 +- Проверка здоровья: http://localhost:4000/health + +## Функции + +- **Целеориентированная разработка** - Определяйте цели на естественном языке; кодирующий агент генерирует граф агентов и код соединений для их достижения +- **Самоадаптирующиеся агенты** - Фреймворк захватывает сбои, обновляет цели и обновляет граф агентов +- **Динамические соединения узлов** - Без предопределённых рёбер; код соединений генерируется любым способным LLM на основе ваших целей +- **Узлы, обёрнутые SDK** - Каждый узел получает общую память, локальную RLM-память, мониторинг, инструменты и доступ к LLM из коробки +- **Человек в контуре** - Узлы вмешательства, которые приостанавливают выполнение для человеческого ввода с настраиваемыми таймаутами и эскалацией +- **Наблюдаемость в реальном времени** - WebSocket-стриминг для живого мониторинга выполнения агентов, решений и межузловой коммуникации +- **Контроль затрат и бюджета** - Устанавливайте лимиты расходов, ограничения и политики автоматической деградации модели +- **Готовность к продакшену** - Возможность самостоятельного хостинга, создан для масштабирования и надёжности + +## Почему Aden + +Традиционные фреймворки агентов требуют ручного проектирования рабочих процессов, определения взаимодействий агентов и реактивной обработки сбоев. Aden переворачивает эту парадигму — **вы описываете результаты, и система строит себя сама**. + +### Преимущество Aden + +| Традиционные фреймворки | Aden | +|-------------------------|------| +| Жёсткое кодирование рабочих процессов | Описание целей на естественном языке | +| Ручное определение графов | Автоматически генерируемые графы агентов | +| Реактивная обработка ошибок | Проактивная самоэволюция | +| Статические конфигурации инструментов | Динамические узлы, обёрнутые SDK | +| Отдельная настройка мониторинга | Встроенная наблюдаемость в реальном времени | +| DIY управление бюджетом | Интегрированный контроль затрат и деградация | + +### Как это работает + +1. **Определите цель** → Опишите, чего хотите достичь, простым языком +2. **Кодирующий агент генерирует** → Создаёт граф агентов, код соединений и тестовые случаи +3. **Рабочие выполняют** → Узлы, обёрнутые SDK, работают с полной наблюдаемостью и доступом к инструментам +4. **Плоскость управления мониторит** → Метрики в реальном времени, применение бюджета, управление политиками +5. **Самосовершенствование** → При сбое система эволюционирует граф и автоматически переразвёртывает + +## Структура проекта + +``` +hive/ +├── honeycomb/ # Фронтенд (React + TypeScript + Vite) +├── hive/ # Бэкенд (Node.js + TypeScript + Express) +├── docs/ # Документация +├── scripts/ # Скрипты сборки и утилиты +├── config.yaml.example # Шаблон конфигурации +└── docker-compose.yml # Оркестрация контейнеров +``` + +## Разработка + +### Локальная разработка с горячей перезагрузкой + +```bash +# Скопировать переопределения для разработки +cp docker-compose.override.yml.example docker-compose.override.yml + +# Запустить с включённой горячей перезагрузкой +docker compose up +``` + +### Запуск без Docker + +```bash +# Установить зависимости +npm install + +# Сгенерировать файлы окружения +npm run generate:env + +# Запустить фронтенд (в honeycomb/) +cd honeycomb && npm run dev + +# Запустить бэкенд (в hive/) +cd hive && npm run dev +``` + +## Документация + +- **[Руководство разработчика](DEVELOPER.md)** - Полное руководство для разработчиков +- [Начало работы](docs/getting-started.md) - Инструкции по быстрой настройке +- [Руководство по конфигурации](docs/configuration.md) - Все опции конфигурации +- [Обзор архитектуры](docs/architecture.md) - Дизайн и структура системы + +## Дорожная карта + +Aden Agent Framework призван помочь разработчикам создавать самоадаптирующихся агентов, ориентированных на результат. Найдите нашу дорожную карту здесь: + +[ROADMAP.md](ROADMAP.md) + +## Сообщество и поддержка + +Мы используем [Discord](https://discord.com/invite/MXE49hrKDk) для поддержки, запросов функций и обсуждений сообщества. + +- Discord - [Присоединиться к сообществу](https://discord.com/invite/MXE49hrKDk) +- Twitter/X - [@adenhq](https://x.com/aden_hq) +- LinkedIn - [Страница компании](https://www.linkedin.com/company/teamaden/) + +## Участие в разработке + +Мы приветствуем вклад! Пожалуйста, ознакомьтесь с [CONTRIBUTING.md](CONTRIBUTING.md) для руководств. + +1. Сделайте форк репозитория +2. Создайте ветку функции (`git checkout -b feature/amazing-feature`) +3. Зафиксируйте изменения (`git commit -m 'Add amazing feature'`) +4. Отправьте в ветку (`git push origin feature/amazing-feature`) +5. Откройте Pull Request + +## Присоединяйтесь к команде + +**Мы нанимаем!** Присоединяйтесь к нам на позициях в инженерии, исследованиях и выходе на рынок. + +[Посмотреть открытые позиции](https://jobs.adenhq.com/a8cec478-cdbc-473c-bbd4-f4b7027ec193/applicant) + +## Безопасность + +По вопросам безопасности, пожалуйста, обратитесь к [SECURITY.md](SECURITY.md). + +## Лицензия + +Этот проект лицензирован под лицензией Apache 2.0 - см. файл [LICENSE](LICENSE) для деталей. + +## Часто задаваемые вопросы (FAQ) + +**В: Зависит ли Aden от LangChain или других фреймворков агентов?** + +Нет. Aden построен с нуля без зависимостей от LangChain, CrewAI или других фреймворков агентов. Фреймворк разработан лёгким и гибким, динамически генерируя графы агентов вместо того, чтобы полагаться на предопределённые компоненты. + +**В: Каких провайдеров LLM поддерживает Aden?** + +Aden поддерживает OpenAI (GPT-4, GPT-4o), Anthropic (модели Claude) и Google Gemini из коробки. Архитектура не зависит от провайдера через абстракцию SDK, с интеграцией LiteLLM в дорожной карте для расширенной поддержки моделей. + +**В: Aden с открытым исходным кодом?** + +Да, Aden полностью с открытым исходным кодом под лицензией Apache 2.0. Мы активно поощряем вклад и сотрудничество сообщества. + +**В: Какие варианты развёртывания поддерживает Aden?** + +Aden поддерживает развёртывание Docker Compose из коробки, с конфигурациями для продакшена и разработки. Самостоятельное развёртывание работает на любой инфраструктуре, поддерживающей Docker. Варианты облачного развёртывания и конфигурации, готовые для Kubernetes, находятся в дорожной карте. + +**В: Может ли Aden справиться со сложными случаями использования продакшен-масштаба?** + +Да. Aden явно разработан для продакшен-сред с такими функциями, как автоматическое восстановление после сбоев, наблюдаемость в реальном времени, контроль затрат и поддержка горизонтального масштабирования. Фреймворк справляется как с простой автоматизацией, так и со сложными многоагентными рабочими процессами. + +**В: Поддерживает ли Aden рабочие процессы с человеком в контуре?** + +Да, Aden полностью поддерживает рабочие процессы с человеком в контуре через узлы вмешательства, которые приостанавливают выполнение для человеческого ввода. Они включают настраиваемые таймауты и политики эскалации, обеспечивая бесшовное сотрудничество между экспертами-людьми и ИИ-агентами. + +**В: Как я могу внести вклад в Aden?** + +Вклады приветствуются! Сделайте форк репозитория, создайте ветку функции, реализуйте изменения и отправьте pull request. Подробные руководства см. в [CONTRIBUTING.md](CONTRIBUTING.md). + +--- + +

+ Сделано с 🔥 Страстью в Сан-Франциско +

diff --git a/README.zh-CN.md b/README.zh-CN.md new file mode 100644 index 00000000..e94250ab --- /dev/null +++ b/README.zh-CN.md @@ -0,0 +1,243 @@ +

+ Hive Banner +

+ +

+ English | + 简体中文 | + Español | + Português | + 日本語 | + Русский +

+ +[![Apache 2.0 License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/adenhq/hive/blob/main/LICENSE) +[![Y Combinator](https://img.shields.io/badge/Y%20Combinator-Aden-orange)](https://www.ycombinator.com/companies/aden) +[![Docker Pulls](https://img.shields.io/docker/pulls/adenhq/hive?logo=Docker&labelColor=%23528bff)](https://hub.docker.com/u/adenhq) +[![Discord](https://img.shields.io/discord/1172610340073242735?logo=discord&labelColor=%235462eb&logoColor=%23f5f5f5&color=%235462eb)](https://discord.com/invite/MXE49hrKDk) +[![Twitter Follow](https://img.shields.io/twitter/follow/teamaden?logo=X&color=%23f5f5f5)](https://x.com/aden_hq) +[![LinkedIn](https://custom-icon-badges.demolab.com/badge/LinkedIn-0A66C2?logo=linkedin-white&logoColor=fff)](https://www.linkedin.com/company/teamaden/) + +

+ AI Agents + Multi-Agent + Goal-Driven + HITL + Production +

+

+ OpenAI + Anthropic + Gemini + MCP +

+ +## 概述 + +构建可靠的、自我改进的 AI 智能体,无需硬编码工作流。通过与编码智能体对话来定义目标,框架会生成带有动态创建连接代码的节点图。当出现问题时,框架会捕获故障数据,通过编码智能体进化智能体,并重新部署。内置的人机协作节点、凭证管理和实时监控让您在保持适应性的同时拥有完全控制权。 + +访问 [adenhq.com](https://adenhq.com) 获取完整文档、示例和指南。 + +## 什么是 Aden + +

+ Aden Architecture +

+ +Aden 是一个用于构建、部署、运营和适应 AI 智能体的平台: + +- **构建** - 编码智能体根据自然语言目标生成专业的工作智能体(销售、营销、运营) +- **部署** - 无头部署,支持 CI/CD 集成和完整的 API 生命周期管理 +- **运营** - 实时监控、可观测性和运行时护栏确保智能体可靠运行 +- **适应** - 持续评估、监督和适应确保智能体随时间改进 +- **基础设施** - 共享内存、LLM 集成、工具和技能为每个智能体提供支持 + +## 快速链接 + +- **[文档](https://docs.adenhq.com/)** - 完整指南和 API 参考 +- **[自托管指南](https://docs.adenhq.com/getting-started/quickstart)** - 在您的基础设施上部署 Hive +- **[更新日志](https://github.com/adenhq/hive/releases)** - 最新更新和版本 +- **[报告问题](https://github.com/adenhq/hive/issues)** - Bug 报告和功能请求 + +## 快速开始 + +### 前置要求 + +- [Docker](https://docs.docker.com/get-docker/) (v20.10+) +- [Docker Compose](https://docs.docker.com/compose/install/) (v2.0+) + +### 安装 + +```bash +# 克隆仓库 +git clone https://github.com/adenhq/hive.git +cd hive + +# 复制并配置 +cp config.yaml.example config.yaml + +# 运行设置并启动服务 +npm run setup +docker compose up +``` + +**访问应用:** + +- 仪表板:http://localhost:3000 +- API:http://localhost:4000 +- 健康检查:http://localhost:4000/health + +## 功能特性 + +- **目标驱动开发** - 用自然语言定义目标;编码智能体生成智能体图和连接代码来实现它们 +- **自适应智能体** - 框架捕获故障,更新目标并更新智能体图 +- **动态节点连接** - 没有预定义边;连接代码由任何有能力的 LLM 根据您的目标生成 +- **SDK 封装节点** - 每个节点开箱即用地获得共享内存、本地 RLM 内存、监控、工具和 LLM 访问 +- **人机协作** - 干预节点暂停执行以等待人工输入,支持可配置的超时和升级 +- **实时可观测性** - WebSocket 流式传输用于实时监控智能体执行、决策和节点间通信 +- **成本与预算控制** - 设置支出限制、节流和自动模型降级策略 +- **生产就绪** - 可自托管,为规模和可靠性而构建 + +## 为什么选择 Aden + +传统智能体框架要求您手动设计工作流、定义智能体交互并被动处理故障。Aden 颠覆了这一范式——**您描述结果,系统自动构建自己**。 + +### Aden 的优势 + +| 传统框架 | Aden | +|----------|------| +| 硬编码智能体工作流 | 用自然语言描述目标 | +| 手动定义图 | 自动生成智能体图 | +| 被动错误处理 | 主动自我进化 | +| 静态工具配置 | 动态 SDK 封装节点 | +| 单独设置监控 | 内置实时可观测性 | +| DIY 预算管理 | 集成成本控制和降级 | + +### 工作原理 + +1. **定义目标** → 用简单英语描述您想要实现的目标 +2. **编码智能体生成** → 创建智能体图、连接代码和测试用例 +3. **工作节点执行** → SDK 封装节点以完全可观测性和工具访问运行 +4. **控制平面监控** → 实时指标、预算执行、策略管理 +5. **自我改进** → 失败时,系统进化图并自动重新部署 + +## 项目结构 + +``` +hive/ +├── honeycomb/ # 前端 (React + TypeScript + Vite) +├── hive/ # 后端 (Node.js + TypeScript + Express) +├── docs/ # 文档 +├── scripts/ # 构建和实用脚本 +├── config.yaml.example # 配置模板 +└── docker-compose.yml # 容器编排 +``` + +## 开发 + +### 带热重载的本地开发 + +```bash +# 复制开发覆盖配置 +cp docker-compose.override.yml.example docker-compose.override.yml + +# 启用热重载启动 +docker compose up +``` + +### 不使用 Docker 运行 + +```bash +# 安装依赖 +npm install + +# 生成环境文件 +npm run generate:env + +# 启动前端(在 honeycomb/ 目录) +cd honeycomb && npm run dev + +# 启动后端(在 hive/ 目录) +cd hive && npm run dev +``` + +## 文档 + +- **[开发者指南](DEVELOPER.md)** - 开发者综合指南 +- [入门指南](docs/getting-started.md) - 快速设置说明 +- [配置指南](docs/configuration.md) - 所有配置选项 +- [架构概述](docs/architecture.md) - 系统设计和结构 + +## 路线图 + +Aden 智能体框架旨在帮助开发者构建面向结果的、自适应的智能体。请在此查看我们的路线图: + +[ROADMAP.md](ROADMAP.md) + +## 社区与支持 + +我们使用 [Discord](https://discord.com/invite/MXE49hrKDk) 进行支持、功能请求和社区讨论。 + +- Discord - [加入我们的社区](https://discord.com/invite/MXE49hrKDk) +- Twitter/X - [@adenhq](https://x.com/aden_hq) +- LinkedIn - [公司主页](https://www.linkedin.com/company/teamaden/) + +## 贡献 + +我们欢迎贡献!请参阅 [CONTRIBUTING.md](CONTRIBUTING.md) 了解指南。 + +1. Fork 仓库 +2. 创建功能分支 (`git checkout -b feature/amazing-feature`) +3. 提交更改 (`git commit -m 'Add amazing feature'`) +4. 推送到分支 (`git push origin feature/amazing-feature`) +5. 创建 Pull Request + +## 加入我们的团队 + +**我们正在招聘!** 加入我们的工程、研究和市场推广团队。 + +[查看开放职位](https://jobs.adenhq.com/a8cec478-cdbc-473c-bbd4-f4b7027ec193/applicant) + +## 安全 + +有关安全问题,请参阅 [SECURITY.md](SECURITY.md)。 + +## 许可证 + +本项目采用 Apache License 2.0 许可证 - 详情请参阅 [LICENSE](LICENSE) 文件。 + +## 常见问题 (FAQ) + +**问:Aden 是否依赖 LangChain 或其他智能体框架?** + +不。Aden 从头开始构建,不依赖 LangChain、CrewAI 或其他智能体框架。该框架设计精简灵活,动态生成智能体图而非依赖预定义组件。 + +**问:Aden 支持哪些 LLM 提供商?** + +Aden 开箱即用支持 OpenAI(GPT-4、GPT-4o)、Anthropic(Claude 模型)和 Google Gemini。架构通过 SDK 抽象实现提供商无关,LiteLLM 集成在路线图中以扩展模型支持。 + +**问:Aden 是开源的吗?** + +是的,Aden 在 Apache License 2.0 下完全开源。我们积极鼓励社区贡献和协作。 + +**问:Aden 支持哪些部署选项?** + +Aden 开箱即用支持 Docker Compose 部署,包括生产和开发配置。自托管部署可在任何支持 Docker 的基础设施上运行。云部署选项和 Kubernetes 就绪配置在路线图中。 + +**问:Aden 能处理复杂的生产级用例吗?** + +可以。Aden 明确为生产环境设计,具有自动故障恢复、实时可观测性、成本控制和水平扩展支持等功能。该框架可处理简单自动化和复杂的多智能体工作流。 + +**问:Aden 支持人机协作工作流吗?** + +是的,Aden 通过干预节点完全支持人机协作工作流,这些节点会暂停执行以等待人工输入。包括可配置的超时和升级策略,实现人类专家与 AI 智能体的无缝协作。 + +**问:如何为 Aden 做贡献?** + +欢迎贡献!Fork 仓库,创建功能分支,实现更改,然后提交 pull request。详细指南请参阅 [CONTRIBUTING.md](CONTRIBUTING.md)。 + +--- + +

+ 用 🔥 热情打造于旧金山 +

From d0b094424da4ed26f3e450c6f2445f44971d2c54 Mon Sep 17 00:00:00 2001 From: Akaash Thawani Date: Thu, 22 Jan 2026 02:05:59 -0800 Subject: [PATCH 21/27] fix(docs): fix broken link and update file name --- docs/quizzes/{00 job-post.md => 00-job-post.md} | 0 docs/quizzes/README.md | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename docs/quizzes/{00 job-post.md => 00-job-post.md} (100%) diff --git a/docs/quizzes/00 job-post.md b/docs/quizzes/00-job-post.md similarity index 100% rename from docs/quizzes/00 job-post.md rename to docs/quizzes/00-job-post.md diff --git a/docs/quizzes/README.md b/docs/quizzes/README.md index 78542bae..1ec206e1 100644 --- a/docs/quizzes/README.md +++ b/docs/quizzes/README.md @@ -6,7 +6,7 @@ Welcome to the Aden Engineering Challenges! These quizzes are designed for stude ## 💼 We're Hiring! -**[Software Development Engineer](./job-post.md)** - Full-stack TypeScript, React, Node.js, AI agents +**[Software Development Engineer](./00-job-post.md)** - Full-stack TypeScript, React, Node.js, AI agents --- From 5c11d743cdc7f43190fbe0dcd5261a353a742dc8 Mon Sep 17 00:00:00 2001 From: Uttam Kumar Date: Thu, 22 Jan 2026 04:02:21 -0700 Subject: [PATCH 22/27] refactor(orchestrator): use LiteLLMProvider for multi-provider support Replace AnthropicProvider with LiteLLMProvider in AgentOrchestrator to enable support for multiple LLM providers (OpenAI, Anthropic, Gemini, etc). - LiteLLM auto-detects provider from model name - LiteLLM auto-detects appropriate API key from environment - Removes restrictive ANTHROPIC_API_KEY check - Matches pattern used in AgentRunner Closes #47 --- core/framework/runner/orchestrator.py | 9 ++- core/tests/test_orchestrator.py | 82 +++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 5 deletions(-) create mode 100644 core/tests/test_orchestrator.py diff --git a/core/framework/runner/orchestrator.py b/core/framework/runner/orchestrator.py index 2f322aae..3b8f438b 100644 --- a/core/framework/runner/orchestrator.py +++ b/core/framework/runner/orchestrator.py @@ -4,7 +4,6 @@ from __future__ import annotations import asyncio import json -import os from dataclasses import dataclass, field from datetime import datetime from pathlib import Path @@ -71,10 +70,10 @@ class AgentOrchestrator: self._model = model self._message_log: list[AgentMessage] = [] - # Auto-create LLM if API key available - if self._llm is None and os.environ.get("ANTHROPIC_API_KEY"): - from framework.llm.anthropic import AnthropicProvider - self._llm = AnthropicProvider(model=model) + # Auto-create LLM - LiteLLM auto-detects provider and API key from model name + if self._llm is None: + from framework.llm.litellm import LiteLLMProvider + self._llm = LiteLLMProvider(model=self._model) def register( self, diff --git a/core/tests/test_orchestrator.py b/core/tests/test_orchestrator.py new file mode 100644 index 00000000..5b4ebcb7 --- /dev/null +++ b/core/tests/test_orchestrator.py @@ -0,0 +1,82 @@ +"""Tests for AgentOrchestrator LiteLLM integration. + +Run with: + cd core + pytest tests/test_orchestrator.py -v +""" + +from unittest.mock import Mock, patch + +from framework.llm.provider import LLMProvider +from framework.llm.litellm import LiteLLMProvider +from framework.runner.orchestrator import AgentOrchestrator + + +class TestOrchestratorLLMInitialization: + """Test AgentOrchestrator LLM provider initialization.""" + + def test_auto_creates_litellm_provider_when_no_llm_passed(self): + """Test that LiteLLMProvider is auto-created when no llm is passed.""" + with patch.object(LiteLLMProvider, '__init__', return_value=None) as mock_init: + orchestrator = AgentOrchestrator() + + mock_init.assert_called_once_with(model="claude-sonnet-4-20250514") + assert orchestrator._llm is not None + + def test_uses_custom_model_parameter(self): + """Test that custom model parameter is passed to LiteLLMProvider.""" + with patch.object(LiteLLMProvider, '__init__', return_value=None) as mock_init: + orchestrator = AgentOrchestrator(model="gpt-4o") + + mock_init.assert_called_once_with(model="gpt-4o") + + def test_supports_openai_model_names(self): + """Test that OpenAI model names are supported.""" + with patch.object(LiteLLMProvider, '__init__', return_value=None) as mock_init: + orchestrator = AgentOrchestrator(model="gpt-4o-mini") + + mock_init.assert_called_once_with(model="gpt-4o-mini") + assert orchestrator._model == "gpt-4o-mini" + + def test_supports_anthropic_model_names(self): + """Test that Anthropic model names are supported.""" + with patch.object(LiteLLMProvider, '__init__', return_value=None) as mock_init: + orchestrator = AgentOrchestrator(model="claude-3-haiku-20240307") + + mock_init.assert_called_once_with(model="claude-3-haiku-20240307") + assert orchestrator._model == "claude-3-haiku-20240307" + + def test_skips_auto_creation_when_llm_passed(self): + """Test that auto-creation is skipped when llm is explicitly passed.""" + mock_llm = Mock(spec=LLMProvider) + + with patch.object(LiteLLMProvider, '__init__', return_value=None) as mock_init: + orchestrator = AgentOrchestrator(llm=mock_llm) + + mock_init.assert_not_called() + assert orchestrator._llm is mock_llm + + def test_model_attribute_stored_correctly(self): + """Test that _model attribute is stored correctly.""" + with patch.object(LiteLLMProvider, '__init__', return_value=None): + orchestrator = AgentOrchestrator(model="gemini/gemini-1.5-flash") + + assert orchestrator._model == "gemini/gemini-1.5-flash" + + +class TestOrchestratorLLMProviderType: + """Test that orchestrator uses correct LLM provider type.""" + + def test_llm_is_litellm_provider_instance(self): + """Test that auto-created _llm is a LiteLLMProvider instance.""" + orchestrator = AgentOrchestrator() + + assert isinstance(orchestrator._llm, LiteLLMProvider) + + def test_llm_implements_llm_provider_interface(self): + """Test that _llm implements LLMProvider interface.""" + orchestrator = AgentOrchestrator() + + assert isinstance(orchestrator._llm, LLMProvider) + assert hasattr(orchestrator._llm, 'complete') + assert hasattr(orchestrator._llm, 'complete_with_tools') From 9d5f36b61e43f28123c6e1d2936ba9d291cd35d2 Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 22 Jan 2026 08:10:53 -0800 Subject: [PATCH 23/27] refactor: temporarily archive tracing tools --- docker-compose.override.yml.example | 37 - docker-compose.yml | 168 -- hive/.dockerignore | 9 - hive/.env.example | 28 - hive/.eslintrc.cjs | 24 - hive/Dockerfile | 66 - hive/Dockerfile.dev | 25 - .../config/agent-frameworks.json | 24 - .../config/llm-vendors.json | 14 - .../config/sdk-languages.json | 10 - .../python/quickstart-langflow.md | 191 -- .../python/quickstart-langgraph.md | 164 -- .../python/quickstart-livekit.md | 165 -- .../templates/javascript/generic.md | 194 -- .../templates/javascript/langgraph.md | 297 --- .../templates/python/generic.md | 164 -- .../templates/python/langflow.md | 191 -- .../templates/python/langgraph.md | 164 -- .../templates/python/livekit.md | 162 -- hive/docs/api/user-authentication.md | 247 -- hive/docs/sdk-event-specification.md | 703 ------ hive/jest.config.js | 24 - hive/k8s/base/deployment.yaml | 101 - hive/k8s/base/kustomization.yaml | 6 - hive/k8s/base/service.yaml | 15 - .../overlays/production/kustomization.yaml | 21 - hive/k8s/overlays/production/namespace.yaml | 6 - .../production/patches/deployment.yaml | 27 - hive/k8s/overlays/staging/kustomization.yaml | 21 - hive/k8s/overlays/staging/namespace.yaml | 6 - .../overlays/staging/patches/deployment.yaml | 27 - hive/package.json | 67 - hive/scripts/migrate-add-agent-name.ts | 129 - hive/scripts/test-mcp-curl.sh | 61 - hive/scripts/test-mcp.ts | 176 -- hive/src/app.ts | 150 -- hive/src/config/index.ts | 134 -- hive/src/controllers/control.controller.ts | 1885 --------------- hive/src/controllers/iam.controller.ts | 154 -- hive/src/controllers/quickstart.controller.ts | 192 -- hive/src/controllers/tsdb.controller.ts | 1205 ---------- hive/src/controllers/user.controller.ts | 626 ----- hive/src/index.ts | 120 - hive/src/mcp/index.ts | 62 - hive/src/mcp/server.ts | 90 - hive/src/mcp/tools/agents.ts | 197 -- hive/src/mcp/tools/analytics.ts | 169 -- hive/src/mcp/tools/budget.ts | 335 --- hive/src/mcp/tools/policies.ts | 224 -- hive/src/mcp/transport/http.ts | 238 -- hive/src/mcp/utils/api-client.ts | 610 ----- hive/src/mcp/utils/response-helpers.ts | 65 - hive/src/mcp/utils/schema-helpers.ts | 80 - .../middleware/error-handler.middleware.ts | 44 - hive/src/routes.ts | 43 - hive/src/services/control/control_service.ts | 2067 ----------------- hive/src/services/control/control_sockets.ts | 733 ------ .../src/services/control/llm_event_batcher.ts | 349 --- hive/src/services/mongo/mongo_db.ts | 26 - .../services/quickstart/quickstart_service.ts | 227 -- .../src/services/tsdb/00-init-timescaledb.sql | 11 - hive/src/services/tsdb/analytics_service.ts | 748 ------ hive/src/services/tsdb/pricing_service.ts | 743 ------ hive/src/services/tsdb/schema.sql | 358 --- hive/src/services/tsdb/team_context.ts | 114 - hive/src/services/tsdb/tsdb_service.ts | 955 -------- hive/src/services/tsdb/users_schema.sql | 149 -- hive/src/sockets/control.socket.ts | 98 - hive/src/types/acho-inc-administration.d.ts | 123 - hive/tests/endpoints/health.test.ts | 49 - hive/tests/setup.ts | 29 - hive/tests/utils/auth-mocks.ts | 124 - hive/tests/utils/db-mocks.ts | 142 -- hive/tests/utils/index.ts | 9 - hive/tests/utils/test-app.ts | 118 - hive/tsconfig.json | 26 - hive/tsconfig.test.json | 10 - honeycomb/.dockerignore | 9 - honeycomb/.env.example | 13 - honeycomb/.eslintrc.cjs | 18 - honeycomb/Dockerfile | 36 - honeycomb/Dockerfile.dev | 20 - honeycomb/components.json | 20 - honeycomb/index.html | 17 - honeycomb/nginx.conf | 46 - honeycomb/package.json | 73 - honeycomb/postcss.config.js | 6 - honeycomb/public/favicon.svg | 4 - honeycomb/src/App.tsx | 40 - honeycomb/src/assets/aden-icon.png | Bin 2027 -> 0 bytes honeycomb/src/assets/aden-icon.svg | 5 - honeycomb/src/assets/aden-logo.svg | 15 - honeycomb/src/components/.gitkeep | 0 honeycomb/src/components/ErrorBoundary.tsx | 50 - .../agent-control/AgentControlLayout.tsx | 306 --- .../agent-control/AnalyticsPanel.tsx | 351 --- .../components/agent-control/CostControls.tsx | 279 --- .../components/agent-control/DataPanel.tsx | 521 ----- .../components/agent-control/WorkersPanel.tsx | 276 --- .../agent-control/budget/AddBudgetDialog.tsx | 184 -- .../budget/BudgetDetailPanel.tsx | 541 ----- .../agent-control/charts/CostByModelChart.tsx | 114 - .../agent-control/charts/CostTrendChart.tsx | 111 - .../agent-control/charts/LatencyChart.tsx | 70 - .../agent-control/charts/ModelUsageChart.tsx | 81 - .../agent-control/charts/TokenUsageChart.tsx | 98 - .../agent-control/charts/TopAgentsChart.tsx | 97 - .../agent-control/charts/VegaLiteChart.tsx | 78 - .../components/agent-control/charts/index.ts | 6 - .../components/agent-control/charts/specs.ts | 257 -- .../agent-control/charts/transformers.ts | 339 --- .../src/components/agent-control/index.ts | 24 - .../agent-control/shared/BudgetCard.tsx | 172 -- .../agent-control/shared/HelpDialog.tsx | 331 --- .../agent-control/shared/KpiCard.tsx | 67 - .../shared/LiveIndicator.test.tsx | 31 - .../agent-control/shared/LiveIndicator.tsx | 23 - .../agent-control/shared/NotificationBell.tsx | 137 -- .../workers/WorkerProfilePanel.tsx | 171 -- honeycomb/src/components/auth/LoginForm.tsx | 127 - .../src/components/auth/ProtectedRoute.tsx | 52 - .../src/components/auth/RegisterForm.tsx | 205 -- .../quickstart/AgentStatusIndicator.tsx | 91 - .../src/components/quickstart/CodeBlock.tsx | 63 - .../quickstart/MarkdownRenderer.tsx | 72 - .../quickstart/QuickstartToolbar.tsx | 89 - .../components/quickstart/SDKQuickstart.tsx | 229 -- honeycomb/src/components/quickstart/index.ts | 5 - .../settings/ChangePasswordDialog.tsx | 160 -- .../settings/CreateAPIKeyDialog.tsx | 165 -- .../components/settings/DeveloperSettings.tsx | 128 - .../components/settings/ProfileSettings.tsx | 387 --- .../src/components/settings/SettingsModal.tsx | 71 - honeycomb/src/components/ui/avatar.tsx | 48 - honeycomb/src/components/ui/badge.tsx | 37 - honeycomb/src/components/ui/button.tsx | 57 - honeycomb/src/components/ui/calendar.tsx | 70 - honeycomb/src/components/ui/card.tsx | 79 - .../src/components/ui/date-range-picker.tsx | 68 - honeycomb/src/components/ui/dialog.tsx | 120 - honeycomb/src/components/ui/dropdown-menu.tsx | 200 -- honeycomb/src/components/ui/input.tsx | 22 - honeycomb/src/components/ui/label.tsx | 24 - honeycomb/src/components/ui/popover.tsx | 29 - honeycomb/src/components/ui/progress.tsx | 26 - honeycomb/src/components/ui/scroll-area.tsx | 48 - honeycomb/src/components/ui/select.tsx | 158 -- honeycomb/src/components/ui/separator.tsx | 29 - honeycomb/src/components/ui/sheet.tsx | 138 -- honeycomb/src/components/ui/skeleton.tsx | 15 - honeycomb/src/components/ui/switch.tsx | 27 - honeycomb/src/components/ui/table.tsx | 117 - honeycomb/src/components/ui/tabs.tsx | 55 - honeycomb/src/components/ui/textarea.tsx | 22 - honeycomb/src/components/ui/tooltip.tsx | 30 - honeycomb/src/components/user/UserAvatar.tsx | 132 -- honeycomb/src/hooks/index.ts | 7 - honeycomb/src/hooks/queries/index.ts | 25 - honeycomb/src/hooks/queries/useAnalytics.ts | 79 - honeycomb/src/hooks/queries/useBudgets.ts | 183 -- honeycomb/src/hooks/queries/useLogs.ts | 85 - honeycomb/src/hooks/queries/useQuickstart.ts | 24 - honeycomb/src/hooks/queries/useSettings.ts | 127 - honeycomb/src/hooks/queries/useUser.ts | 184 -- honeycomb/src/hooks/useAgentStatus.ts | 177 -- honeycomb/src/hooks/useApi.ts | 44 - honeycomb/src/hooks/useControlSocket.ts | 144 -- honeycomb/src/hooks/usePersistedSettings.ts | 87 - honeycomb/src/lib/quickstart.ts | 55 - honeycomb/src/lib/user.ts | 89 - honeycomb/src/lib/utils.ts | 6 - honeycomb/src/main.tsx | 31 - honeycomb/src/pages/HomePage.tsx | 48 - honeycomb/src/pages/LoginPage.tsx | 45 - honeycomb/src/pages/NotFoundPage.tsx | 15 - honeycomb/src/pages/RegisterPage.tsx | 38 - honeycomb/src/services/agentControlApi.ts | 257 -- honeycomb/src/services/api.ts | 139 -- honeycomb/src/services/authApi.ts | 60 - honeycomb/src/services/controlApi.ts | 27 - honeycomb/src/services/orgApi.ts | 73 - honeycomb/src/services/quickstartApi.ts | 18 - honeycomb/src/services/settingsApi.ts | 25 - honeycomb/src/services/userApi.ts | 98 - honeycomb/src/stores/agentControlStore.ts | 66 - honeycomb/src/stores/notificationStore.ts | 89 - honeycomb/src/stores/settingsStore.ts | 104 - honeycomb/src/stores/userStore.ts | 122 - honeycomb/src/styles/index.css | 378 --- honeycomb/src/test/setup.ts | 23 - honeycomb/src/types/agentControl.ts | 304 --- honeycomb/src/types/auth.ts | 26 - honeycomb/src/types/index.ts | 25 - honeycomb/src/types/quickstart.ts | 64 - honeycomb/src/types/settings.ts | 38 - honeycomb/src/types/user.ts | 72 - honeycomb/src/utils/index.ts | 27 - honeycomb/src/vite-env.d.ts | 1 - honeycomb/tailwind.config.js | 91 - honeycomb/tsconfig.json | 28 - honeycomb/tsconfig.node.json | 18 - honeycomb/vite.config.ts | 34 - honeycomb/vitest.config.ts | 29 - 203 files changed, 29726 deletions(-) delete mode 100644 docker-compose.override.yml.example delete mode 100644 docker-compose.yml delete mode 100644 hive/.dockerignore delete mode 100644 hive/.env.example delete mode 100644 hive/.eslintrc.cjs delete mode 100644 hive/Dockerfile delete mode 100644 hive/Dockerfile.dev delete mode 100644 hive/docs/aden-sdk-documents/config/agent-frameworks.json delete mode 100644 hive/docs/aden-sdk-documents/config/llm-vendors.json delete mode 100644 hive/docs/aden-sdk-documents/config/sdk-languages.json delete mode 100644 hive/docs/aden-sdk-documents/python/quickstart-langflow.md delete mode 100644 hive/docs/aden-sdk-documents/python/quickstart-langgraph.md delete mode 100644 hive/docs/aden-sdk-documents/python/quickstart-livekit.md delete mode 100644 hive/docs/aden-sdk-documents/templates/javascript/generic.md delete mode 100644 hive/docs/aden-sdk-documents/templates/javascript/langgraph.md delete mode 100644 hive/docs/aden-sdk-documents/templates/python/generic.md delete mode 100644 hive/docs/aden-sdk-documents/templates/python/langflow.md delete mode 100644 hive/docs/aden-sdk-documents/templates/python/langgraph.md delete mode 100644 hive/docs/aden-sdk-documents/templates/python/livekit.md delete mode 100644 hive/docs/api/user-authentication.md delete mode 100644 hive/docs/sdk-event-specification.md delete mode 100644 hive/jest.config.js delete mode 100644 hive/k8s/base/deployment.yaml delete mode 100644 hive/k8s/base/kustomization.yaml delete mode 100644 hive/k8s/base/service.yaml delete mode 100644 hive/k8s/overlays/production/kustomization.yaml delete mode 100644 hive/k8s/overlays/production/namespace.yaml delete mode 100644 hive/k8s/overlays/production/patches/deployment.yaml delete mode 100644 hive/k8s/overlays/staging/kustomization.yaml delete mode 100644 hive/k8s/overlays/staging/namespace.yaml delete mode 100644 hive/k8s/overlays/staging/patches/deployment.yaml delete mode 100644 hive/package.json delete mode 100644 hive/scripts/migrate-add-agent-name.ts delete mode 100755 hive/scripts/test-mcp-curl.sh delete mode 100644 hive/scripts/test-mcp.ts delete mode 100644 hive/src/app.ts delete mode 100644 hive/src/config/index.ts delete mode 100644 hive/src/controllers/control.controller.ts delete mode 100644 hive/src/controllers/iam.controller.ts delete mode 100644 hive/src/controllers/quickstart.controller.ts delete mode 100644 hive/src/controllers/tsdb.controller.ts delete mode 100644 hive/src/controllers/user.controller.ts delete mode 100644 hive/src/index.ts delete mode 100644 hive/src/mcp/index.ts delete mode 100644 hive/src/mcp/server.ts delete mode 100644 hive/src/mcp/tools/agents.ts delete mode 100644 hive/src/mcp/tools/analytics.ts delete mode 100644 hive/src/mcp/tools/budget.ts delete mode 100644 hive/src/mcp/tools/policies.ts delete mode 100644 hive/src/mcp/transport/http.ts delete mode 100644 hive/src/mcp/utils/api-client.ts delete mode 100644 hive/src/mcp/utils/response-helpers.ts delete mode 100644 hive/src/mcp/utils/schema-helpers.ts delete mode 100644 hive/src/middleware/error-handler.middleware.ts delete mode 100644 hive/src/routes.ts delete mode 100644 hive/src/services/control/control_service.ts delete mode 100644 hive/src/services/control/control_sockets.ts delete mode 100644 hive/src/services/control/llm_event_batcher.ts delete mode 100644 hive/src/services/mongo/mongo_db.ts delete mode 100644 hive/src/services/quickstart/quickstart_service.ts delete mode 100644 hive/src/services/tsdb/00-init-timescaledb.sql delete mode 100644 hive/src/services/tsdb/analytics_service.ts delete mode 100644 hive/src/services/tsdb/pricing_service.ts delete mode 100644 hive/src/services/tsdb/schema.sql delete mode 100644 hive/src/services/tsdb/team_context.ts delete mode 100644 hive/src/services/tsdb/tsdb_service.ts delete mode 100644 hive/src/services/tsdb/users_schema.sql delete mode 100644 hive/src/sockets/control.socket.ts delete mode 100644 hive/src/types/acho-inc-administration.d.ts delete mode 100644 hive/tests/endpoints/health.test.ts delete mode 100644 hive/tests/setup.ts delete mode 100644 hive/tests/utils/auth-mocks.ts delete mode 100644 hive/tests/utils/db-mocks.ts delete mode 100644 hive/tests/utils/index.ts delete mode 100644 hive/tests/utils/test-app.ts delete mode 100644 hive/tsconfig.json delete mode 100644 hive/tsconfig.test.json delete mode 100644 honeycomb/.dockerignore delete mode 100644 honeycomb/.env.example delete mode 100644 honeycomb/.eslintrc.cjs delete mode 100644 honeycomb/Dockerfile delete mode 100644 honeycomb/Dockerfile.dev delete mode 100644 honeycomb/components.json delete mode 100644 honeycomb/index.html delete mode 100644 honeycomb/nginx.conf delete mode 100644 honeycomb/package.json delete mode 100644 honeycomb/postcss.config.js delete mode 100644 honeycomb/public/favicon.svg delete mode 100644 honeycomb/src/App.tsx delete mode 100644 honeycomb/src/assets/aden-icon.png delete mode 100644 honeycomb/src/assets/aden-icon.svg delete mode 100644 honeycomb/src/assets/aden-logo.svg delete mode 100644 honeycomb/src/components/.gitkeep delete mode 100644 honeycomb/src/components/ErrorBoundary.tsx delete mode 100644 honeycomb/src/components/agent-control/AgentControlLayout.tsx delete mode 100644 honeycomb/src/components/agent-control/AnalyticsPanel.tsx delete mode 100644 honeycomb/src/components/agent-control/CostControls.tsx delete mode 100644 honeycomb/src/components/agent-control/DataPanel.tsx delete mode 100644 honeycomb/src/components/agent-control/WorkersPanel.tsx delete mode 100644 honeycomb/src/components/agent-control/budget/AddBudgetDialog.tsx delete mode 100644 honeycomb/src/components/agent-control/budget/BudgetDetailPanel.tsx delete mode 100644 honeycomb/src/components/agent-control/charts/CostByModelChart.tsx delete mode 100644 honeycomb/src/components/agent-control/charts/CostTrendChart.tsx delete mode 100644 honeycomb/src/components/agent-control/charts/LatencyChart.tsx delete mode 100644 honeycomb/src/components/agent-control/charts/ModelUsageChart.tsx delete mode 100644 honeycomb/src/components/agent-control/charts/TokenUsageChart.tsx delete mode 100644 honeycomb/src/components/agent-control/charts/TopAgentsChart.tsx delete mode 100644 honeycomb/src/components/agent-control/charts/VegaLiteChart.tsx delete mode 100644 honeycomb/src/components/agent-control/charts/index.ts delete mode 100644 honeycomb/src/components/agent-control/charts/specs.ts delete mode 100644 honeycomb/src/components/agent-control/charts/transformers.ts delete mode 100644 honeycomb/src/components/agent-control/index.ts delete mode 100644 honeycomb/src/components/agent-control/shared/BudgetCard.tsx delete mode 100644 honeycomb/src/components/agent-control/shared/HelpDialog.tsx delete mode 100644 honeycomb/src/components/agent-control/shared/KpiCard.tsx delete mode 100644 honeycomb/src/components/agent-control/shared/LiveIndicator.test.tsx delete mode 100644 honeycomb/src/components/agent-control/shared/LiveIndicator.tsx delete mode 100644 honeycomb/src/components/agent-control/shared/NotificationBell.tsx delete mode 100644 honeycomb/src/components/agent-control/workers/WorkerProfilePanel.tsx delete mode 100644 honeycomb/src/components/auth/LoginForm.tsx delete mode 100644 honeycomb/src/components/auth/ProtectedRoute.tsx delete mode 100644 honeycomb/src/components/auth/RegisterForm.tsx delete mode 100644 honeycomb/src/components/quickstart/AgentStatusIndicator.tsx delete mode 100644 honeycomb/src/components/quickstart/CodeBlock.tsx delete mode 100644 honeycomb/src/components/quickstart/MarkdownRenderer.tsx delete mode 100644 honeycomb/src/components/quickstart/QuickstartToolbar.tsx delete mode 100644 honeycomb/src/components/quickstart/SDKQuickstart.tsx delete mode 100644 honeycomb/src/components/quickstart/index.ts delete mode 100644 honeycomb/src/components/settings/ChangePasswordDialog.tsx delete mode 100644 honeycomb/src/components/settings/CreateAPIKeyDialog.tsx delete mode 100644 honeycomb/src/components/settings/DeveloperSettings.tsx delete mode 100644 honeycomb/src/components/settings/ProfileSettings.tsx delete mode 100644 honeycomb/src/components/settings/SettingsModal.tsx delete mode 100644 honeycomb/src/components/ui/avatar.tsx delete mode 100644 honeycomb/src/components/ui/badge.tsx delete mode 100644 honeycomb/src/components/ui/button.tsx delete mode 100644 honeycomb/src/components/ui/calendar.tsx delete mode 100644 honeycomb/src/components/ui/card.tsx delete mode 100644 honeycomb/src/components/ui/date-range-picker.tsx delete mode 100644 honeycomb/src/components/ui/dialog.tsx delete mode 100644 honeycomb/src/components/ui/dropdown-menu.tsx delete mode 100644 honeycomb/src/components/ui/input.tsx delete mode 100644 honeycomb/src/components/ui/label.tsx delete mode 100644 honeycomb/src/components/ui/popover.tsx delete mode 100644 honeycomb/src/components/ui/progress.tsx delete mode 100644 honeycomb/src/components/ui/scroll-area.tsx delete mode 100644 honeycomb/src/components/ui/select.tsx delete mode 100644 honeycomb/src/components/ui/separator.tsx delete mode 100644 honeycomb/src/components/ui/sheet.tsx delete mode 100644 honeycomb/src/components/ui/skeleton.tsx delete mode 100644 honeycomb/src/components/ui/switch.tsx delete mode 100644 honeycomb/src/components/ui/table.tsx delete mode 100644 honeycomb/src/components/ui/tabs.tsx delete mode 100644 honeycomb/src/components/ui/textarea.tsx delete mode 100644 honeycomb/src/components/ui/tooltip.tsx delete mode 100644 honeycomb/src/components/user/UserAvatar.tsx delete mode 100644 honeycomb/src/hooks/index.ts delete mode 100644 honeycomb/src/hooks/queries/index.ts delete mode 100644 honeycomb/src/hooks/queries/useAnalytics.ts delete mode 100644 honeycomb/src/hooks/queries/useBudgets.ts delete mode 100644 honeycomb/src/hooks/queries/useLogs.ts delete mode 100644 honeycomb/src/hooks/queries/useQuickstart.ts delete mode 100644 honeycomb/src/hooks/queries/useSettings.ts delete mode 100644 honeycomb/src/hooks/queries/useUser.ts delete mode 100644 honeycomb/src/hooks/useAgentStatus.ts delete mode 100644 honeycomb/src/hooks/useApi.ts delete mode 100644 honeycomb/src/hooks/useControlSocket.ts delete mode 100644 honeycomb/src/hooks/usePersistedSettings.ts delete mode 100644 honeycomb/src/lib/quickstart.ts delete mode 100644 honeycomb/src/lib/user.ts delete mode 100644 honeycomb/src/lib/utils.ts delete mode 100644 honeycomb/src/main.tsx delete mode 100644 honeycomb/src/pages/HomePage.tsx delete mode 100644 honeycomb/src/pages/LoginPage.tsx delete mode 100644 honeycomb/src/pages/NotFoundPage.tsx delete mode 100644 honeycomb/src/pages/RegisterPage.tsx delete mode 100644 honeycomb/src/services/agentControlApi.ts delete mode 100644 honeycomb/src/services/api.ts delete mode 100644 honeycomb/src/services/authApi.ts delete mode 100644 honeycomb/src/services/controlApi.ts delete mode 100644 honeycomb/src/services/orgApi.ts delete mode 100644 honeycomb/src/services/quickstartApi.ts delete mode 100644 honeycomb/src/services/settingsApi.ts delete mode 100644 honeycomb/src/services/userApi.ts delete mode 100644 honeycomb/src/stores/agentControlStore.ts delete mode 100644 honeycomb/src/stores/notificationStore.ts delete mode 100644 honeycomb/src/stores/settingsStore.ts delete mode 100644 honeycomb/src/stores/userStore.ts delete mode 100644 honeycomb/src/styles/index.css delete mode 100644 honeycomb/src/test/setup.ts delete mode 100644 honeycomb/src/types/agentControl.ts delete mode 100644 honeycomb/src/types/auth.ts delete mode 100644 honeycomb/src/types/index.ts delete mode 100644 honeycomb/src/types/quickstart.ts delete mode 100644 honeycomb/src/types/settings.ts delete mode 100644 honeycomb/src/types/user.ts delete mode 100644 honeycomb/src/utils/index.ts delete mode 100644 honeycomb/src/vite-env.d.ts delete mode 100644 honeycomb/tailwind.config.js delete mode 100644 honeycomb/tsconfig.json delete mode 100644 honeycomb/tsconfig.node.json delete mode 100644 honeycomb/vite.config.ts delete mode 100644 honeycomb/vitest.config.ts diff --git a/docker-compose.override.yml.example b/docker-compose.override.yml.example deleted file mode 100644 index caea0365..00000000 --- a/docker-compose.override.yml.example +++ /dev/null @@ -1,37 +0,0 @@ -# Development overrides -# Copy this file to docker-compose.override.yml for local development -# -# Usage: -# cp docker-compose.override.yml.example docker-compose.override.yml -# docker compose up -# -# This enables: -# - Hot reload for both frontend and backend -# - Source code mounted as volumes -# - Debug ports exposed -# - Development environment settings - -services: - honeycomb: - build: - context: ./honeycomb - dockerfile: Dockerfile.dev - volumes: - - ./honeycomb/src:/app/src:ro - - ./honeycomb/public:/app/public:ro - - ./honeycomb/index.html:/app/index.html:ro - environment: - - VITE_API_URL=http://localhost:4000 - - hive: - build: - context: ./hive - dockerfile: Dockerfile.dev - volumes: - - ./hive/src:/app/src:ro - environment: - - NODE_ENV=development - - LOG_LEVEL=debug - # Uncomment to enable Node.js debugging - # ports: - # - "9229:9229" diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 135997cc..00000000 --- a/docker-compose.yml +++ /dev/null @@ -1,168 +0,0 @@ -services: - # Frontend - React application - honeycomb: - build: - context: ./honeycomb - target: production - args: - VITE_API_URL: ${VITE_API_URL:-http://localhost:4000} - container_name: honeycomb-frontend - ports: - - "${FRONTEND_PORT:-3000}:3000" - depends_on: - hive: - condition: service_healthy - restart: unless-stopped - networks: - - honeycomb-network - - # Backend - Hive API (LLM observability & control plane) - hive: - build: - context: ./hive - target: production - args: - NPM_TOKEN: ${NPM_TOKEN:-} - container_name: honeycomb-backend - ports: - - "${BACKEND_PORT:-4000}:4000" - environment: - - NODE_ENV=${NODE_ENV:-production} - - PORT=4000 - - LOG_LEVEL=${LOG_LEVEL:-info} - # PostgreSQL (TimescaleDB) - - TSDB_PG_URL=postgresql://postgres:postgres@timescaledb:5432/aden_tsdb - # MongoDB - - MONGODB_URL=mongodb://mongodb:27017 - - MONGODB_DBNAME=${MONGODB_DBNAME:-aden} - - MONGODB_ERP_DBNAME=${MONGODB_ERP_DBNAME:-erp} - # Redis - - REDIS_URL=redis://redis:6379 - # Authentication - - JWT_SECRET=${JWT_SECRET:-change-me-in-production-use-min-32-chars} - - PASSPHRASE=${PASSPHRASE:-change-me-in-production} - # Hive backend URL for SDK quickstart documents - - HIVE_HOST=${HIVE_HOST:-http://localhost:4000} - depends_on: - timescaledb: - condition: service_healthy - mongodb: - condition: service_healthy - redis: - condition: service_healthy - healthcheck: - test: - [ - "CMD", - "node", - "-e", - "fetch('http://localhost:4000/health').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))", - ] - interval: 10s - timeout: 5s - retries: 5 - start_period: 15s - restart: unless-stopped - networks: - - honeycomb-network - - # TimescaleDB - Time series database for LLM metrics - timescaledb: - image: timescale/timescaledb:latest-pg16 - container_name: honeycomb-timescaledb - ports: - - "${TSDB_PORT:-5432}:5432" - environment: - - POSTGRES_USER=postgres - - POSTGRES_PASSWORD=postgres - - POSTGRES_DB=aden_tsdb - command: ["postgres", "-c", "log_min_messages=warning", "-c", "log_statement=none"] - volumes: - - timescaledb_data:/var/lib/postgresql/data - # Auto-run schema files on first startup (alphabetical order) - - ./hive/src/services/tsdb/00-init-timescaledb.sql:/docker-entrypoint-initdb.d/00-init-timescaledb.sql:ro - - ./hive/src/services/tsdb/schema.sql:/docker-entrypoint-initdb.d/01-schema.sql:ro - - ./hive/src/services/tsdb/users_schema.sql:/docker-entrypoint-initdb.d/02-users.sql:ro - healthcheck: - test: ["CMD-SHELL", "pg_isready -U postgres -d aden_tsdb"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 10s - restart: unless-stopped - networks: - - honeycomb-network - - # MongoDB - Policies, pricing, and control configuration - mongodb: - image: mongo:7 - container_name: honeycomb-mongodb - ports: - - "${MONGODB_PORT:-27017}:27017" - command: ["mongod", "--quiet", "--logpath", "/dev/null"] - volumes: - - mongodb_data:/data/db - healthcheck: - test: ["CMD", "mongosh", "--quiet", "--eval", "db.adminCommand('ping')"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 10s - restart: unless-stopped - networks: - - honeycomb-network - - # Redis - Caching and Socket.IO adapter - redis: - image: redis:7-alpine - container_name: honeycomb-redis - ports: - - "${REDIS_PORT:-6379}:6379" - command: ["redis-server", "--loglevel", "warning"] - volumes: - - redis_data:/data - healthcheck: - test: ["CMD", "redis-cli", "ping"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 5s - restart: unless-stopped - networks: - - honeycomb-network - - # Aden Tools MCP Server - Python tools via Model Context Protocol - aden-tools-mcp: - build: - context: ./aden-tools - container_name: honeycomb-aden-tools-mcp - ports: - - "${ADEN_TOOLS_MCP_PORT:-4001}:4001" - environment: - - MCP_PORT=4001 - # Pass through tool-specific env vars - - BRAVE_SEARCH_API_KEY=${BRAVE_SEARCH_API_KEY:-} - volumes: - - .:/workspace:rw # Mount project root for file access - - aden_tools_workspaces:/app/workdir/workspaces # Persist file system tool workspaces - working_dir: /workspace # Set working directory so relative paths work - command: ["python", "/app/mcp_server.py"] # Use absolute path since working_dir changed - healthcheck: - test: ["CMD", "python", "-c", "import httpx; httpx.get('http://localhost:4001/health').raise_for_status()"] - interval: 30s - timeout: 5s - retries: 5 - start_period: 10s - restart: unless-stopped - networks: - - honeycomb-network - -networks: - honeycomb-network: - driver: bridge - -volumes: - timescaledb_data: - mongodb_data: - redis_data: - aden_tools_workspaces: diff --git a/hive/.dockerignore b/hive/.dockerignore deleted file mode 100644 index 982246ac..00000000 --- a/hive/.dockerignore +++ /dev/null @@ -1,9 +0,0 @@ -node_modules -dist -.env -.env.* -*.log -.DS_Store -.git -.vscode -.idea diff --git a/hive/.env.example b/hive/.env.example deleted file mode 100644 index 330b93ba..00000000 --- a/hive/.env.example +++ /dev/null @@ -1,28 +0,0 @@ -# Server Configuration -PORT=4000 -NODE_ENV=development - -# TSDB PostgreSQL (TimescaleDB) -TSDB_PG_URL=postgresql://user:password@localhost:5432/aden_tsdb - -# User Database (MySQL - read-only access) -MYSQL_HOST=localhost -MYSQL_PORT=3306 -MYSQL_USER=aden_reader -MYSQL_PASSWORD= -MYSQL_DATABASE=aden - -# MongoDB (policies and pricing data) -MONGODB_URL=mongodb://localhost:27017 -MONGODB_DBNAME=aden -MONGODB_ERP_DBNAME=erp - -# Redis (caching and socket.io adapter) -REDIS_URL=redis://localhost:6379 - -# JWT Authentication -JWT_SECRET=your-jwt-secret -PASSPHRASE=your-passphrase - -# Logging -LOG_LEVEL=info diff --git a/hive/.eslintrc.cjs b/hive/.eslintrc.cjs deleted file mode 100644 index 4c5b5d4d..00000000 --- a/hive/.eslintrc.cjs +++ /dev/null @@ -1,24 +0,0 @@ -module.exports = { - root: true, - env: { node: true, es2020: true }, - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - ], - ignorePatterns: ['dist', '.eslintrc.cjs'], - parser: '@typescript-eslint/parser', - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - }, - rules: { - // Allow unused vars that start with underscore - '@typescript-eslint/no-unused-vars': ['error', { - argsIgnorePattern: '^_', - varsIgnorePattern: '^_', - destructuredArrayIgnorePattern: '^_', - }], - // Allow any types (common in API/external data handling) - '@typescript-eslint/no-explicit-any': 'off', - }, -} diff --git a/hive/Dockerfile b/hive/Dockerfile deleted file mode 100644 index 89819395..00000000 --- a/hive/Dockerfile +++ /dev/null @@ -1,66 +0,0 @@ -# Build stage -FROM node:20-alpine AS builder - -ARG NPM_TOKEN - -WORKDIR /app - -# Configure npm for private packages (@acho-inc/administration) -RUN echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > .npmrc - -# Copy package files -COPY package*.json ./ -COPY tsconfig.json ./ - -# Install all dependencies (including dev for TypeScript build) -RUN npm install - -# Copy source code -COPY src ./src - -# Copy docs for quickstart templates -COPY docs ./docs - -# Build TypeScript -RUN npm run build - -# Remove npmrc after build -RUN rm -f .npmrc - -# Production stage -FROM node:20-alpine AS production - -WORKDIR /app - -# Create non-root user -RUN addgroup -g 1001 -S nodejs && \ - adduser -S nodejs -u 1001 - -# Copy package files for production deps -COPY package*.json ./ - -# Configure npm for private packages (needed for production install) -ARG NPM_TOKEN -RUN echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > .npmrc && \ - npm install --omit=dev && \ - rm -f .npmrc && \ - npm cache clean --force - -# Copy compiled JavaScript from builder -COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist - -# Copy docs directory for quickstart templates -COPY --from=builder --chown=nodejs:nodejs /app/docs ./docs - -USER nodejs - -# Default port (can be overridden via PORT env var) -EXPOSE 4000 - -ENV NODE_ENV=production - -# Health check -HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ - CMD node -e "fetch('http://localhost:' + (process.env.PORT || 4000) + '/health').then(r => r.ok ? process.exit(0) : process.exit(1)).catch(() => process.exit(1))" - -CMD ["node", "dist/index.js"] diff --git a/hive/Dockerfile.dev b/hive/Dockerfile.dev deleted file mode 100644 index f98f5b76..00000000 --- a/hive/Dockerfile.dev +++ /dev/null @@ -1,25 +0,0 @@ -# Development Dockerfile with hot reload -# The 'production' alias allows this to work with docker-compose.yml target -FROM node:20-alpine AS production - -ARG NPM_TOKEN - -WORKDIR /app - -# Configure npm for private packages (@acho-inc/administration) -RUN echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > .npmrc - -# Copy package files -COPY package*.json ./ - -# Install dependencies -RUN npm install && rm -f .npmrc - -# Copy source code -COPY . . - -# Expose ports (app + debug) -EXPOSE 4000 9229 - -# Start development server with hot reload -CMD ["npm", "run", "dev"] diff --git a/hive/docs/aden-sdk-documents/config/agent-frameworks.json b/hive/docs/aden-sdk-documents/config/agent-frameworks.json deleted file mode 100644 index 7b9fbbdb..00000000 --- a/hive/docs/aden-sdk-documents/config/agent-frameworks.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "generic": { - "name": "Generic", - "description": "Generic agent integration", - "pythonSupport": true, - "typescriptSupport": true, - "templateFile": "generic" - }, - "langgraph": { - "name": "LangGraph", - "description": "LangGraph agent integration", - "pythonSupport": true, - "typescriptSupport": true, - "templateFile": "langgraph" - }, - "livekit": { - "name": "LiveKit", - "description": "LiveKit voice agent integration", - "pythonSupport": true, - "typescriptSupport": false, - "adenPythonExtra": "livekit", - "templateFile": "livekit" - } -} diff --git a/hive/docs/aden-sdk-documents/config/llm-vendors.json b/hive/docs/aden-sdk-documents/config/llm-vendors.json deleted file mode 100644 index d9cb26d5..00000000 --- a/hive/docs/aden-sdk-documents/config/llm-vendors.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "openai": { - "name": "OpenAI", - "envVarComment": "# or ANTHROPIC_API_KEY, GOOGLE_API_KEY" - }, - "anthropic": { - "name": "Anthropic", - "envVarComment": "# or OPENAI_API_KEY, GOOGLE_API_KEY" - }, - "google": { - "name": "Google", - "envVarComment": "# or OPENAI_API_KEY, ANTHROPIC_API_KEY" - } -} diff --git a/hive/docs/aden-sdk-documents/config/sdk-languages.json b/hive/docs/aden-sdk-documents/config/sdk-languages.json deleted file mode 100644 index 7efad1fc..00000000 --- a/hive/docs/aden-sdk-documents/config/sdk-languages.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "python": { - "name": "Python", - "adenPackage": "aden-py" - }, - "javascript": { - "name": "JavaScript/TypeScript", - "adenPackage": "aden-ts" - } -} diff --git a/hive/docs/aden-sdk-documents/python/quickstart-langflow.md b/hive/docs/aden-sdk-documents/python/quickstart-langflow.md deleted file mode 100644 index e3bd9292..00000000 --- a/hive/docs/aden-sdk-documents/python/quickstart-langflow.md +++ /dev/null @@ -1,191 +0,0 @@ -Quick reference for integrating Aden LLM observability & cost control into LangFlow applications. - -## Prerequisites - -`.env` file should contain: - -``` -OPENAI_API_KEY=sk-xxx # or ANTHROPIC_API_KEY, GOOGLE_API_KEY -ADEN_API_URL=https://hive.adenhq.com -ADEN_API_KEY=your-aden-api-key - -``` - -## Installation - -```bash -pip install aden-py langflow python-dotenv - -``` - -## Basic Setup (3 Steps) - -### 1. Import and Load Environment - -```python -import os -from dotenv import load_dotenv -load_dotenv() - -from aden import ( - instrument, - uninstrument, - MeterOptions, - create_console_emitter, - BeforeRequestResult, - RequestCancelledError, -) - -``` - -### 2. Define Budget Check Callback - -```python -def budget_check(params, context): - """Enforce budget limits before each LLM request.""" - budget_info = getattr(context, 'budget', None) - - if budget_info and budget_info.get('exhausted', False): - return BeforeRequestResult.cancel("Budget exhausted") - - if budget_info and budget_info.get('percent_used', 0) >= 95: - return BeforeRequestResult.throttle(delay_ms=2000) - - if budget_info and budget_info.get('percent_used', 0) >= 80: - return BeforeRequestResult.degrade(to_model="gpt-4o-mini", reason="Approaching limit") - - return BeforeRequestResult.proceed() - -``` - -### 3. Initialize Aden (at startup) - -```python -instrument(MeterOptions( - api_key=os.environ.get("ADEN_API_KEY"), - server_url=os.environ.get("ADEN_API_URL"), - emit_metric=create_console_emitter(pretty=True), - on_alert=lambda alert: print(f"[Aden {alert.level}] {alert.message}"), - before_request=budget_check, -)) - -``` - -### 4. Use LangFlow Components - -```python -from langflow.components.models import LanguageModelComponent - -comp = LanguageModelComponent() -comp.set_attributes({ - "provider": "Google", # or "OpenAI" - "model_name": "gemini-2.0-flash", - "api_key": os.getenv("GOOGLE_API_KEY"), - "stream": False, -}) - -model = comp.build_model() - -try: - response = model.invoke("Hello!") - print(response.content) -except RequestCancelledError as e: - print(f"Budget exceeded: {e}") - -``` - -### 5. Cleanup (on exit) - -```python -uninstrument() - -``` - -## Complete Template - -```python -"""LangFlow with Aden instrumentation""" -import os -from dotenv import load_dotenv -load_dotenv() - -from aden import ( - instrument, uninstrument, MeterOptions, - create_console_emitter, BeforeRequestResult, RequestCancelledError, -) - -# Budget enforcement callback -def budget_check(params, context): - budget_info = getattr(context, 'budget', None) - if budget_info and budget_info.get('exhausted', False): - return BeforeRequestResult.cancel("Budget exhausted") - if budget_info and budget_info.get('percent_used', 0) >= 95: - return BeforeRequestResult.throttle(delay_ms=2000) - if budget_info and budget_info.get('percent_used', 0) >= 80: - return BeforeRequestResult.degrade(to_model="gpt-4o-mini", reason="Approaching limit") - return BeforeRequestResult.proceed() - -# Initialize Aden -instrument(MeterOptions( - api_key=os.environ.get("ADEN_API_KEY"), - server_url=os.environ.get("ADEN_API_URL"), - emit_metric=create_console_emitter(pretty=True), - on_alert=lambda alert: print(f"[Aden {alert.level}] {alert.message}"), - before_request=budget_check, -)) - -# === YOUR LANGFLOW CODE HERE === - -from langflow.components.models import LanguageModelComponent - -def run_model(user_input: str): - try: - comp = LanguageModelComponent() - comp.set_attributes({ - "provider": "Google", - "model_name": "gemini-2.0-flash", - "api_key": os.getenv("GOOGLE_API_KEY"), - "stream": False, - }) - model = comp.build_model() - return model.invoke(user_input).content - except RequestCancelledError as e: - return f"Sorry, you have used up your allowance. {e}" - -if __name__ == "__main__": - try: - print(run_model("Say hello!")) - finally: - uninstrument() - -``` - -## Supported Providers - -| Provider | Model Example | Notes | -| --------- | ------------------- | -------------------------------- | -| OpenAI | gpt-4o, gpt-4o-mini | Direct SDK instrumentation | -| Google | gemini-2.0-flash | Uses gRPC client instrumentation | -| Anthropic | claude-3-opus | Direct SDK instrumentation | - -## Budget Actions Reference - -| Action | When | Behavior | -| ----------------------------------------------- | ----------------- | ------------------------------ | -| `BeforeRequestResult.proceed()` | Within budget | Request continues normally | -| `BeforeRequestResult.cancel(msg)` | Budget exhausted | Raises `RequestCancelledError` | -| `BeforeRequestResult.throttle(delay_ms=N)` | Near limit | Delays request by N ms | -| `BeforeRequestResult.degrade(to_model, reason)` | Approaching limit | Switches to cheaper model | - -## Key Points - -- `emit_metric` is **required** - use `create_console_emitter(pretty=True)` for dev -- `before_request` callback enables budget enforcement -- Always wrap model calls in `try/except RequestCancelledError` -- Call `uninstrument()` on exit to flush remaining metrics -- Control agent connects automatically when `api_key` + `server_url` are provided -- Google Gemini support works automatically via gRPC client instrumentation - -## Documentation - -Full docs: [https://pypi.org/project/aden-py](https://pypi.org/project/aden-py/) diff --git a/hive/docs/aden-sdk-documents/python/quickstart-langgraph.md b/hive/docs/aden-sdk-documents/python/quickstart-langgraph.md deleted file mode 100644 index 7a413234..00000000 --- a/hive/docs/aden-sdk-documents/python/quickstart-langgraph.md +++ /dev/null @@ -1,164 +0,0 @@ -Quick reference for integrating Aden LLM observability & cost control into Python agents. - -## Prerequisites - -`.env` file should contain: - -``` -OPENAI_API_KEY=sk-xxx # or ANTHROPIC_API_KEY, GOOGLE_API_KEY -ADEN_API_URL=https://hive.adenhq.com -ADEN_API_KEY=your-aden-api-key - -``` - -## Installation - -```bash -pip install aden-py python-dotenv - -``` - -## Basic Setup (3 Steps) - -### 1. Import and Load Environment - -```python -import os -from dotenv import load_dotenv -load_dotenv() - -from aden import ( - instrument, - uninstrument, - MeterOptions, - create_console_emitter, - BeforeRequestResult, - RequestCancelledError, -) - -``` - -### 2. Define Budget Check Callback - -```python -def budget_check(params, context): - """Enforce budget limits before each LLM request.""" - budget_info = getattr(context, 'budget', None) - - if budget_info and budget_info.get('exhausted', False): - return BeforeRequestResult.cancel("Budget exhausted") - - if budget_info and budget_info.get('percent_used', 0) >= 95: - return BeforeRequestResult.throttle(delay_ms=2000) - - if budget_info and budget_info.get('percent_used', 0) >= 80: - return BeforeRequestResult.degrade(to_model="gpt-4o-mini", reason="Approaching limit") - - return BeforeRequestResult.proceed() - -``` - -### 3. Initialize Aden (at startup) - -```python -instrument(MeterOptions( - api_key=os.environ.get("ADEN_API_KEY"), - server_url=os.environ.get("ADEN_API_URL"), - emit_metric=create_console_emitter(pretty=True), - on_alert=lambda alert: print(f"[Aden {alert.level}] {alert.message}"), - before_request=budget_check, -)) - -``` - -### 4. Handle Budget Errors in Your Agent - -```python -def run_agent(user_input: str): - try: - # Your agent logic here - result = graph.invoke({"messages": [{"role": "user", "content": user_input}]}) - return result["messages"][-1].content - except RequestCancelledError as e: - return f"Sorry, you have used up your allowance. {e}" - -``` - -### 5. Cleanup (on exit) - -```python -uninstrument() - -``` - -## Complete Template - -```python -"""Agent with Aden instrumentation""" -import os -from dotenv import load_dotenv -load_dotenv() - -from aden import ( - instrument, uninstrument, MeterOptions, - create_console_emitter, BeforeRequestResult, RequestCancelledError, -) - -# Budget enforcement callback -def budget_check(params, context): - budget_info = getattr(context, 'budget', None) - if budget_info and budget_info.get('exhausted', False): - return BeforeRequestResult.cancel("Budget exhausted") - if budget_info and budget_info.get('percent_used', 0) >= 95: - return BeforeRequestResult.throttle(delay_ms=2000) - if budget_info and budget_info.get('percent_used', 0) >= 80: - return BeforeRequestResult.degrade(to_model="gpt-4o-mini", reason="Approaching limit") - return BeforeRequestResult.proceed() - -# Initialize Aden -instrument(MeterOptions( - api_key=os.environ.get("ADEN_API_KEY"), - server_url=os.environ.get("ADEN_API_URL"), - emit_metric=create_console_emitter(pretty=True), - on_alert=lambda alert: print(f"[Aden {alert.level}] {alert.message}"), - before_request=budget_check, -)) - -# === YOUR AGENT CODE HERE === - -def run_agent(user_input: str): - try: - # Your LLM calls here - pass - except RequestCancelledError as e: - return f"Sorry, you have used up your allowance. {e}" - -if __name__ == "__main__": - try: - # Your main loop - pass - finally: - uninstrument() - -``` - -## Budget Actions Reference - -| Action | When | Behavior | -| ----------------------------------------------- | ----------------- | ------------------------------ | -| `BeforeRequestResult.proceed()` | Within budget | Request continues normally | -| `BeforeRequestResult.cancel(msg)` | Budget exhausted | Raises `RequestCancelledError` | -| `BeforeRequestResult.throttle(delay_ms=N)` | Near limit | Delays request by N ms | -| `BeforeRequestResult.degrade(to_model, reason)` | Approaching limit | Switches to cheaper model | - -## Key Points - -- `emit_metric` is **required** - use `create_console_emitter(pretty=True)` for dev -- `before_request` callback enables budget enforcement -- Always wrap agent calls in `try/except RequestCancelledError` -- Call `uninstrument()` on exit to flush remaining metrics -- Control agent connects automatically when `api_key` + `server_url` are provided - -## Documentation - -Full docs: [https://pypi.org/project/aden-py](https://pypi.org/project/aden-py/json) diff --git a/hive/docs/aden-sdk-documents/python/quickstart-livekit.md b/hive/docs/aden-sdk-documents/python/quickstart-livekit.md deleted file mode 100644 index 35c0f9ab..00000000 --- a/hive/docs/aden-sdk-documents/python/quickstart-livekit.md +++ /dev/null @@ -1,165 +0,0 @@ -# Aden-py LiveKit Integration Guide - -Quick reference for integrating Aden LLM observability & cost control into LiveKit voice agents. - -## Prerequisites - -`.env` file should contain: - -``` -OPENAI_API_KEY=sk-xxx -ADEN_API_URL=https://hive.adenhq.com -ADEN_API_KEY=your-aden-api-key -``` - -## Installation - -```bash -pip install 'aden-py[livekit]' python-dotenv -``` - -## Setup (4 Steps) - -### 1. Import and Load Environment - -```python -import os -from dotenv import load_dotenv -load_dotenv() - -from aden import ( - instrument, - MeterOptions, - create_console_emitter, - BeforeRequestResult, - RequestCancelledError, -) -``` - -### 2. Define Budget Check Callback - -```python -def budget_check(params, context): - """Enforce budget limits before each LLM request.""" - budget_info = getattr(context, 'budget', None) - - if budget_info and budget_info.get('exhausted', False): - return BeforeRequestResult.cancel("Budget exhausted") - - if budget_info and budget_info.get('percent_used', 0) >= 95: - return BeforeRequestResult.throttle(delay_ms=2000) - - if budget_info and budget_info.get('percent_used', 0) >= 80: - return BeforeRequestResult.degrade(to_model="gpt-4o-mini", reason="Approaching limit") - - return BeforeRequestResult.proceed() -``` - -### 3. Create Worker Prewarm Function - -**IMPORTANT:** LiveKit uses multiprocessing. Instrumentation must happen in each worker process, not the main process. - -```python -def initialize_aden_in_worker(proc): - """Initialize Aden instrumentation in each worker process.""" - instrument(MeterOptions( - api_key=os.environ.get("ADEN_API_KEY"), - server_url=os.environ.get("ADEN_API_URL"), - emit_metric=create_console_emitter(pretty=True), - on_alert=lambda alert: print(f"[Aden {alert.level}] {alert.message}"), - before_request=budget_check, - )) -``` - -### 4. Pass Prewarm Function to WorkerOptions - -```python -if __name__ == "__main__": - agents.cli.run_app(agents.WorkerOptions( - entrypoint_fnc=entrypoint, - agent_name="my-agent", - prewarm_fnc=initialize_aden_in_worker, # <-- This is the key! - )) -``` - -## Complete Template - -```python -"""LiveKit Voice Agent with Aden instrumentation""" -import os -from dotenv import load_dotenv -load_dotenv() - -from livekit import agents -from livekit.plugins import openai - -from aden import ( - instrument, MeterOptions, create_console_emitter, - BeforeRequestResult, RequestCancelledError, -) - -# Budget enforcement callback -def budget_check(params, context): - budget_info = getattr(context, 'budget', None) - if budget_info and budget_info.get('exhausted', False): - return BeforeRequestResult.cancel("Budget exhausted") - if budget_info and budget_info.get('percent_used', 0) >= 95: - return BeforeRequestResult.throttle(delay_ms=2000) - if budget_info and budget_info.get('percent_used', 0) >= 80: - return BeforeRequestResult.degrade(to_model="gpt-4o-mini", reason="Approaching limit") - return BeforeRequestResult.proceed() - -# Worker initialization - runs in each spawned process -def initialize_aden_in_worker(proc): - instrument(MeterOptions( - api_key=os.environ.get("ADEN_API_KEY"), - server_url=os.environ.get("ADEN_API_URL"), - emit_metric=create_console_emitter(pretty=True), - on_alert=lambda alert: print(f"[Aden {alert.level}] {alert.message}"), - before_request=budget_check, - )) - -async def entrypoint(ctx: agents.JobContext): - # Your agent logic here - session = agents.AgentSession( - llm=openai.LLM(model="gpt-4o-mini"), - # ... - ) - await session.start(ctx.room) - -if __name__ == "__main__": - agents.cli.run_app(agents.WorkerOptions( - entrypoint_fnc=entrypoint, - agent_name="my-agent", - prewarm_fnc=initialize_aden_in_worker, - )) -``` - -## Budget Actions Reference - -| Action | When | Behavior | -| ----------------------------------------------- | ------------------------ | ------------------------------ | -| `BeforeRequestResult.proceed()` | Within budget | Request continues normally | -| `BeforeRequestResult.cancel(msg)` | Budget exhausted | Raises `RequestCancelledError` | -| `BeforeRequestResult.throttle(delay_ms=N)` | Near limit (95%+) | Delays request by N ms | -| `BeforeRequestResult.degrade(to_model, reason)` | Approaching limit (80%+) | Switches to cheaper model | - -## Key Points - -- **Use `prewarm_fnc`** - LiveKit spawns worker processes; instrumentation must happen in each worker -- **Don't instrument in main process** - It won't affect the worker processes where LLM calls happen -- `emit_metric` is **required** - use `create_console_emitter(pretty=True)` for dev -- Control agent connects automatically when `api_key` + `server_url` are provided - -## Troubleshooting - -**No metrics showing?** - -- Ensure `prewarm_fnc` is set in `WorkerOptions` -- Check that `ADEN_API_KEY` and `ADEN_API_URL` are in your `.env` -- Verify you're using `aden-py[livekit]` (with the livekit extra) - -**Metrics in test but not in agent?** - -- LiveKit uses multiprocessing - the main process instrumentation doesn't carry over -- The `prewarm_fnc` runs in each worker before your `entrypoint` is called diff --git a/hive/docs/aden-sdk-documents/templates/javascript/generic.md b/hive/docs/aden-sdk-documents/templates/javascript/generic.md deleted file mode 100644 index fe8dca0c..00000000 --- a/hive/docs/aden-sdk-documents/templates/javascript/generic.md +++ /dev/null @@ -1,194 +0,0 @@ -Quick reference for integrating Aden LLM observability & cost control into TypeScript/JavaScript agents. - -## Prerequisites - -`.env` file should contain: - -``` -OPENAI_API_KEY=sk-xxx {{envVarComment}} -ADEN_API_URL={{serverUrl}} -ADEN_API_KEY={{apiKey}} -``` - -## Installation - -```bash -npm install aden-ts dotenv - -# Install the LLM SDKs you use -npm install openai # For OpenAI -npm install @anthropic-ai/sdk # For Anthropic -npm install @google/generative-ai # For Google Gemini -``` - -## Basic Setup - -### 1. Import Aden and SDK (at top of file) - -```typescript -import "dotenv/config"; -import OpenAI from "openai"; -import { - instrument, - uninstrument, - createConsoleEmitter, - RequestCancelledError, -} from "aden-ts"; -import type { BeforeRequestContext, BeforeRequestResult } from "aden-ts"; -``` - -### 2. Define Before Request Callback (optional) - -```typescript -// Custom logic before each LLM request -// Budget enforcement is handled server-side by the control agent -function beforeRequest( - _params: Record, - context: BeforeRequestContext -): BeforeRequestResult { - console.log(`[Aden] Request to model: ${context.model}`); - return { action: "proceed" }; -} -``` - -### 3. Initialize Aden (at startup, BEFORE using SDK) - -```typescript -await instrument({ - apiKey: process.env.ADEN_API_KEY, - serverUrl: process.env.ADEN_API_URL, - emitMetric: createConsoleEmitter({ pretty: true }), - onAlert: (alert: { level: string; message: string }) => - console.log(`[Aden ${alert.level}] ${alert.message}`), - beforeRequest, - sdks: { OpenAI }, -}); -``` - -### 4. Handle Budget Errors in Your Agent - -```typescript -async function runAgent(userInput: string): Promise { - try { - const openai = new OpenAI(); - const response = await openai.chat.completions.create({ - model: "gpt-4o", - messages: [{ role: "user", content: userInput }], - }); - return response.choices[0]?.message?.content ?? ""; - } catch (e) { - if (e instanceof RequestCancelledError) { - return `Sorry, your budget has been exhausted. ${e.message}`; - } - throw e; - } -} -``` - -### 5. Cleanup (on exit) - -```typescript -await uninstrument(); -``` - -## Complete Template - -```typescript -/** - * Agent with Aden instrumentation - */ -import "dotenv/config"; -import OpenAI from "openai"; -import { - instrument, - uninstrument, - createConsoleEmitter, - RequestCancelledError, -} from "aden-ts"; -import type { BeforeRequestContext, BeforeRequestResult } from "aden-ts"; - -// Before request callback (optional) -function beforeRequest( - _params: Record, - context: BeforeRequestContext -): BeforeRequestResult { - console.log(`[Aden] Request to model: ${context.model}`); - return { action: "proceed" }; -} - -// Initialize Aden FIRST -await instrument({ - apiKey: process.env.ADEN_API_KEY, - serverUrl: process.env.ADEN_API_URL, - emitMetric: createConsoleEmitter({ pretty: true }), - onAlert: (alert: { level: string; message: string }) => - console.log(`[Aden ${alert.level}] ${alert.message}`), - beforeRequest, - sdks: { OpenAI }, -}); - -// === YOUR AGENT CODE HERE === - -async function runAgent(userInput: string): Promise { - try { - const openai = new OpenAI(); - const response = await openai.chat.completions.create({ - model: "gpt-4o", - messages: [{ role: "user", content: userInput }], - }); - return response.choices[0]?.message?.content ?? ""; - } catch (e) { - if (e instanceof RequestCancelledError) { - return `Sorry, your budget has been exhausted. ${e.message}`; - } - throw e; - } -} - -// Main entry point -async function main() { - try { - const result = await runAgent("Hello, world!"); - console.log(result); - } finally { - await uninstrument(); - } -} - -main(); -``` - -## BeforeRequestContext Reference - -The `context` parameter in `beforeRequest` contains: - -| Field | Type | Description | -| --- | --- | --- | -| `model` | string | Model being used for this request | -| `stream` | boolean | Whether this is a streaming request | -| `spanId` | string | Generated span ID (OTel standard) | -| `traceId` | string | Trace ID grouping related operations | -| `timestamp` | Date | When the request was initiated | -| `metadata` | Record | Custom metadata (optional) | - -## BeforeRequestResult Actions - -| Action | Usage | Behavior | -| --- | --- | --- | -| `{ action: "proceed" }` | Allow request | Request continues normally | -| `{ action: "cancel", reason: "..." }` | Block request | Throws `RequestCancelledError` | -| `{ action: "throttle", delayMs: N }` | Rate limit | Delays request by N ms | -| `{ action: "degrade", toModel: "...", reason: "..." }` | Downgrade | Switches to specified model | - -## Key Points - -- Module name is `aden-ts` (not `aden`) -- `emitMetric` is **required** - use `createConsoleEmitter({ pretty: true })` for dev -- Budget enforcement is handled **server-side** by the control agent -- Always wrap agent calls in `try/catch` for `RequestCancelledError` -- Call `await uninstrument()` on exit to flush remaining metrics -- Control agent connects automatically when `apiKey` + `serverUrl` are provided - -## Documentation - -Full docs: [https://www.npmjs.com/package/aden-ts](https://www.npmjs.com/package/aden-ts) diff --git a/hive/docs/aden-sdk-documents/templates/javascript/langgraph.md b/hive/docs/aden-sdk-documents/templates/javascript/langgraph.md deleted file mode 100644 index a911a7bd..00000000 --- a/hive/docs/aden-sdk-documents/templates/javascript/langgraph.md +++ /dev/null @@ -1,297 +0,0 @@ -Quick reference for integrating Aden LLM observability & cost control into TypeScript/JavaScript agents. - -## Prerequisites - -`.env` file should contain: - -``` -OPENAI_API_KEY=sk-xxx {{envVarComment}} -ADEN_API_URL={{serverUrl}} -ADEN_API_KEY={{apiKey}} -``` - -## Installation - -```bash -npm install aden-ts dotenv - -# Install the LLM SDKs you use -npm install openai # For OpenAI -npm install @anthropic-ai/sdk # For Anthropic -npm install @google/generative-ai # For Google Gemini -``` - -## Basic Setup - -### 1. Import Aden and SDK (at top of file) - -```typescript -import "dotenv/config"; -import OpenAI from "openai"; -import { - instrument, - uninstrument, - createConsoleEmitter, - RequestCancelledError, -} from "aden-ts"; -import type { BeforeRequestContext, BeforeRequestResult } from "aden-ts"; -``` - -### 2. Define Before Request Callback (optional) - -```typescript -// Custom logic before each LLM request -// Budget enforcement is handled server-side by the control agent -function beforeRequest( - _params: Record, - context: BeforeRequestContext -): BeforeRequestResult { - console.log(`[Aden] Request to model: ${context.model}`); - return { action: "proceed" }; -} -``` - -### 3. Initialize Aden (at startup, BEFORE using SDK) - -```typescript -await instrument({ - apiKey: process.env.ADEN_API_KEY, - serverUrl: process.env.ADEN_API_URL, - emitMetric: createConsoleEmitter({ pretty: true }), - onAlert: (alert: { level: string; message: string }) => - console.log(`[Aden ${alert.level}] ${alert.message}`), - beforeRequest, - sdks: { OpenAI }, -}); -``` - -### 4. Handle Budget Errors in Your Agent - -```typescript -async function runAgent(userInput: string): Promise { - try { - const openai = new OpenAI(); - const response = await openai.chat.completions.create({ - model: "gpt-4o", - messages: [{ role: "user", content: userInput }], - }); - return response.choices[0]?.message?.content ?? ""; - } catch (e) { - if (e instanceof RequestCancelledError) { - return `Sorry, your budget has been exhausted. ${e.message}`; - } - throw e; - } -} -``` - -### 5. Cleanup (on exit) - -```typescript -await uninstrument(); -``` - -## Complete Template (Direct SDK Usage) - -```typescript -/** - * Agent with Aden instrumentation - Direct SDK usage - */ -import "dotenv/config"; -import OpenAI from "openai"; -import { - instrument, - uninstrument, - createConsoleEmitter, - RequestCancelledError, -} from "aden-ts"; -import type { BeforeRequestContext, BeforeRequestResult } from "aden-ts"; - -// Before request callback (optional) -function beforeRequest( - _params: Record, - context: BeforeRequestContext -): BeforeRequestResult { - console.log(`[Aden] Request to model: ${context.model}`); - return { action: "proceed" }; -} - -// Initialize Aden FIRST -await instrument({ - apiKey: process.env.ADEN_API_KEY, - serverUrl: process.env.ADEN_API_URL, - emitMetric: createConsoleEmitter({ pretty: true }), - onAlert: (alert: { level: string; message: string }) => - console.log(`[Aden ${alert.level}] ${alert.message}`), - beforeRequest, - sdks: { OpenAI }, -}); - -// === YOUR AGENT CODE HERE === - -async function runAgent(userInput: string): Promise { - try { - const openai = new OpenAI(); - const response = await openai.chat.completions.create({ - model: "gpt-4o", - messages: [{ role: "user", content: userInput }], - }); - return response.choices[0]?.message?.content ?? ""; - } catch (e) { - if (e instanceof RequestCancelledError) { - return `Sorry, your budget has been exhausted. ${e.message}`; - } - throw e; - } -} - -// Main entry point -async function main() { - try { - const result = await runAgent("Hello, world!"); - console.log(result); - } finally { - await uninstrument(); - } -} - -main(); -``` - -## LangChain / LangGraph Integration - -When using LangChain or LangGraph, you **MUST** use dynamic imports to ensure instrumentation is applied before LangChain loads the SDK. - -### Critical: SDK Version Matching - -LangChain bundles its own SDK dependencies. To ensure instrumentation works, your SDK version must match LangChain's: - -```bash -# Check what version LangChain uses -cat node_modules/@langchain/anthropic/node_modules/@anthropic-ai/sdk/package.json | grep version - -# Update your package.json to match that version -# e.g., "@anthropic-ai/sdk": "^0.65.0" - -# Reinstall to dedupe -rm -rf node_modules package-lock.json && npm install - -# Verify no nested SDK (should show "No such file") -ls node_modules/@langchain/anthropic/node_modules 2>/dev/null || echo "OK: SDK is shared" -``` - -### LangChain Template - -```typescript -/** - * LangGraph Agent with Aden instrumentation - * Key: Use dynamic imports AFTER instrument() - */ -import "dotenv/config"; -import Anthropic from "@anthropic-ai/sdk"; -import { - instrument, - uninstrument, - createConsoleEmitter, - RequestCancelledError, -} from "aden-ts"; -import type { BeforeRequestContext, BeforeRequestResult } from "aden-ts"; - -function beforeRequest( - _params: Record, - context: BeforeRequestContext -): BeforeRequestResult { - console.log(`[Aden] Request to model: ${context.model}`); - return { action: "proceed" }; -} - -async function main() { - // 1. Initialize Aden FIRST (before any LangChain imports) - await instrument({ - apiKey: process.env.ADEN_API_KEY, - serverUrl: process.env.ADEN_API_URL, - emitMetric: createConsoleEmitter({ pretty: true }), - onAlert: (alert: { level: string; message: string }) => - console.log(`[Aden ${alert.level}] ${alert.message}`), - beforeRequest, - sdks: { Anthropic }, - }); - - // 2. Dynamic imports AFTER instrumentation - const { ChatAnthropic } = await import("@langchain/anthropic"); - const { HumanMessage } = await import("@langchain/core/messages"); - // ... other LangChain imports - - // 3. Now create your LangChain components - const model = new ChatAnthropic({ - model: "claude-sonnet-4-20250514", - temperature: 0, - }); - - try { - // Your agent logic here - const response = await model.invoke([new HumanMessage("Hello!")]); - console.log(response.content); - } catch (error) { - if (error instanceof RequestCancelledError) { - console.log(`Budget exhausted: ${error.message}`); - } else { - throw error; - } - } finally { - await uninstrument(); - } -} - -main(); -``` - -## BeforeRequestContext Reference - -The `context` parameter in `beforeRequest` contains: - -| Field | Type | Description | -| --- | --- | --- | -| `model` | string | Model being used for this request | -| `stream` | boolean | Whether this is a streaming request | -| `spanId` | string | Generated span ID (OTel standard) | -| `traceId` | string | Trace ID grouping related operations | -| `timestamp` | Date | When the request was initiated | -| `metadata` | Record | Custom metadata (optional) | - -## BeforeRequestResult Actions - -| Action | Usage | Behavior | -| --- | --- | --- | -| `{ action: "proceed" }` | Allow request | Request continues normally | -| `{ action: "cancel", reason: "..." }` | Block request | Throws `RequestCancelledError` | -| `{ action: "throttle", delayMs: N }` | Rate limit | Delays request by N ms | -| `{ action: "degrade", toModel: "...", reason: "..." }` | Downgrade | Switches to specified model | - -## Key Points - -- Module name is `aden-ts` (not `aden`) -- `emitMetric` is **required** - use `createConsoleEmitter({ pretty: true })` for dev -- Budget enforcement is handled **server-side** by the control agent -- Always wrap agent calls in `try/catch` for `RequestCancelledError` -- Call `await uninstrument()` on exit to flush remaining metrics -- Control agent connects automatically when `apiKey` + `serverUrl` are provided -- **LangChain users**: Must use dynamic imports and match SDK versions - -## Troubleshooting - -### No metrics being captured - -1. **Check SDK version match**: Run `npm ls @anthropic-ai/sdk` - should show only ONE version -2. **Use dynamic imports**: Import LangChain modules AFTER `instrument()` is called -3. **Verify instrumentation**: Look for `[aden] Instrumented: anthropic + control agent` at startup - -### RequestCancelledError not thrown - -Budget enforcement is server-side. Ensure: -- `ADEN_API_KEY` and `ADEN_API_URL` are set correctly -- Control agent connection is established (check startup logs) - -## Documentation - -Full docs: [https://www.npmjs.com/package/aden-ts](https://www.npmjs.com/package/aden-ts) diff --git a/hive/docs/aden-sdk-documents/templates/python/generic.md b/hive/docs/aden-sdk-documents/templates/python/generic.md deleted file mode 100644 index d5e6fe79..00000000 --- a/hive/docs/aden-sdk-documents/templates/python/generic.md +++ /dev/null @@ -1,164 +0,0 @@ -Quick reference for integrating Aden LLM observability & cost control into Python agents. - -## Prerequisites - -`.env` file should contain: - -``` -OPENAI_API_KEY=sk-xxx {{envVarComment}} -ADEN_API_URL={{serverUrl}} -ADEN_API_KEY={{apiKey}} - -``` - -## Installation - -```bash -pip install aden-py python-dotenv - -``` - -## Basic Setup (3 Steps) - -### 1. Import and Load Environment - -```python -import os -from dotenv import load_dotenv -load_dotenv() - -from aden import ( - instrument, - uninstrument, - MeterOptions, - create_console_emitter, - BeforeRequestResult, - RequestCancelledError, -) - -``` - -### 2. Define Budget Check Callback - -```python -def budget_check(params, context): - """Enforce budget limits before each LLM request.""" - budget_info = getattr(context, 'budget', None) - - if budget_info and budget_info.get('exhausted', False): - return BeforeRequestResult.cancel("Budget exhausted") - - if budget_info and budget_info.get('percent_used', 0) >= 95: - return BeforeRequestResult.throttle(delay_ms=2000) - - if budget_info and budget_info.get('percent_used', 0) >= 80: - return BeforeRequestResult.degrade(to_model="gpt-4o-mini", reason="Approaching limit") - - return BeforeRequestResult.proceed() - -``` - -### 3. Initialize Aden (at startup) - -```python -instrument(MeterOptions( - api_key=os.environ.get("ADEN_API_KEY"), - server_url=os.environ.get("ADEN_API_URL"), - emit_metric=create_console_emitter(pretty=True), - on_alert=lambda alert: print(f"[Aden {alert.level}] {alert.message}"), - before_request=budget_check, -)) - -``` - -### 4. Handle Budget Errors in Your Agent - -```python -def run_agent(user_input: str): - try: - # Your agent logic here - result = graph.invoke({"messages": [{"role": "user", "content": user_input}]}) - return result["messages"][-1].content - except RequestCancelledError as e: - return f"Sorry, you have used up your allowance. {e}" - -``` - -### 5. Cleanup (on exit) - -```python -uninstrument() - -``` - -## Complete Template - -```python -"""Agent with Aden instrumentation""" -import os -from dotenv import load_dotenv -load_dotenv() - -from aden import ( - instrument, uninstrument, MeterOptions, - create_console_emitter, BeforeRequestResult, RequestCancelledError, -) - -# Budget enforcement callback -def budget_check(params, context): - budget_info = getattr(context, 'budget', None) - if budget_info and budget_info.get('exhausted', False): - return BeforeRequestResult.cancel("Budget exhausted") - if budget_info and budget_info.get('percent_used', 0) >= 95: - return BeforeRequestResult.throttle(delay_ms=2000) - if budget_info and budget_info.get('percent_used', 0) >= 80: - return BeforeRequestResult.degrade(to_model="gpt-4o-mini", reason="Approaching limit") - return BeforeRequestResult.proceed() - -# Initialize Aden -instrument(MeterOptions( - api_key=os.environ.get("ADEN_API_KEY"), - server_url=os.environ.get("ADEN_API_URL"), - emit_metric=create_console_emitter(pretty=True), - on_alert=lambda alert: print(f"[Aden {alert.level}] {alert.message}"), - before_request=budget_check, -)) - -# === YOUR AGENT CODE HERE === - -def run_agent(user_input: str): - try: - # Your LLM calls here - pass - except RequestCancelledError as e: - return f"Sorry, you have used up your allowance. {e}" - -if __name__ == "__main__": - try: - # Your main loop - pass - finally: - uninstrument() - -``` - -## Budget Actions Reference - -| Action | When | Behavior | -| --- | --- | --- | -| `BeforeRequestResult.proceed()` | Within budget | Request continues normally | -| `BeforeRequestResult.cancel(msg)` | Budget exhausted | Raises `RequestCancelledError` | -| `BeforeRequestResult.throttle(delay_ms=N)` | Near limit | Delays request by N ms | -| `BeforeRequestResult.degrade(to_model, reason)` | Approaching limit | Switches to cheaper model | - -## Key Points - -- `emit_metric` is **required** - use `create_console_emitter(pretty=True)` for dev -- `before_request` callback enables budget enforcement -- Always wrap agent calls in `try/except RequestCancelledError` -- Call `uninstrument()` on exit to flush remaining metrics -- Control agent connects automatically when `api_key` + `server_url` are provided - -## Documentation - -Full docs: [https://pypi.org/project/aden-py](https://pypi.org/project/aden-py/) diff --git a/hive/docs/aden-sdk-documents/templates/python/langflow.md b/hive/docs/aden-sdk-documents/templates/python/langflow.md deleted file mode 100644 index 12e52166..00000000 --- a/hive/docs/aden-sdk-documents/templates/python/langflow.md +++ /dev/null @@ -1,191 +0,0 @@ -Quick reference for integrating Aden LLM observability & cost control into LangFlow applications. - -## Prerequisites - -`.env` file should contain: - -``` -OPENAI_API_KEY=sk-xxx {{envVarComment}} -ADEN_API_URL={{serverUrl}} -ADEN_API_KEY={{apiKey}} - -``` - -## Installation - -```bash -pip install aden-py langflow python-dotenv - -``` - -## Basic Setup (3 Steps) - -### 1. Import and Load Environment - -```python -import os -from dotenv import load_dotenv -load_dotenv() - -from aden import ( - instrument, - uninstrument, - MeterOptions, - create_console_emitter, - BeforeRequestResult, - RequestCancelledError, -) - -``` - -### 2. Define Budget Check Callback - -```python -def budget_check(params, context): - """Enforce budget limits before each LLM request.""" - budget_info = getattr(context, 'budget', None) - - if budget_info and budget_info.get('exhausted', False): - return BeforeRequestResult.cancel("Budget exhausted") - - if budget_info and budget_info.get('percent_used', 0) >= 95: - return BeforeRequestResult.throttle(delay_ms=2000) - - if budget_info and budget_info.get('percent_used', 0) >= 80: - return BeforeRequestResult.degrade(to_model="gpt-4o-mini", reason="Approaching limit") - - return BeforeRequestResult.proceed() - -``` - -### 3. Initialize Aden (at startup) - -```python -instrument(MeterOptions( - api_key=os.environ.get("ADEN_API_KEY"), - server_url=os.environ.get("ADEN_API_URL"), - emit_metric=create_console_emitter(pretty=True), - on_alert=lambda alert: print(f"[Aden {alert.level}] {alert.message}"), - before_request=budget_check, -)) - -``` - -### 4. Use LangFlow Components - -```python -from langflow.components.models import LanguageModelComponent - -comp = LanguageModelComponent() -comp.set_attributes({ - "provider": "Google", # or "OpenAI" - "model_name": "gemini-2.0-flash", - "api_key": os.getenv("GOOGLE_API_KEY"), - "stream": False, -}) - -model = comp.build_model() - -try: - response = model.invoke("Hello!") - print(response.content) -except RequestCancelledError as e: - print(f"Budget exceeded: {e}") - -``` - -### 5. Cleanup (on exit) - -```python -uninstrument() - -``` - -## Complete Template - -```python -"""LangFlow with Aden instrumentation""" -import os -from dotenv import load_dotenv -load_dotenv() - -from aden import ( - instrument, uninstrument, MeterOptions, - create_console_emitter, BeforeRequestResult, RequestCancelledError, -) - -# Budget enforcement callback -def budget_check(params, context): - budget_info = getattr(context, 'budget', None) - if budget_info and budget_info.get('exhausted', False): - return BeforeRequestResult.cancel("Budget exhausted") - if budget_info and budget_info.get('percent_used', 0) >= 95: - return BeforeRequestResult.throttle(delay_ms=2000) - if budget_info and budget_info.get('percent_used', 0) >= 80: - return BeforeRequestResult.degrade(to_model="gpt-4o-mini", reason="Approaching limit") - return BeforeRequestResult.proceed() - -# Initialize Aden -instrument(MeterOptions( - api_key=os.environ.get("ADEN_API_KEY"), - server_url=os.environ.get("ADEN_API_URL"), - emit_metric=create_console_emitter(pretty=True), - on_alert=lambda alert: print(f"[Aden {alert.level}] {alert.message}"), - before_request=budget_check, -)) - -# === YOUR LANGFLOW CODE HERE === - -from langflow.components.models import LanguageModelComponent - -def run_model(user_input: str): - try: - comp = LanguageModelComponent() - comp.set_attributes({ - "provider": "Google", - "model_name": "gemini-2.0-flash", - "api_key": os.getenv("GOOGLE_API_KEY"), - "stream": False, - }) - model = comp.build_model() - return model.invoke(user_input).content - except RequestCancelledError as e: - return f"Sorry, you have used up your allowance. {e}" - -if __name__ == "__main__": - try: - print(run_model("Say hello!")) - finally: - uninstrument() - -``` - -## Supported Providers - -| Provider | Model Example | Notes | -| --- | --- | --- | -| OpenAI | gpt-4o, gpt-4o-mini | Direct SDK instrumentation | -| Google | gemini-2.0-flash | Uses gRPC client instrumentation | -| Anthropic | claude-3-opus | Direct SDK instrumentation | - -## Budget Actions Reference - -| Action | When | Behavior | -| --- | --- | --- | -| `BeforeRequestResult.proceed()` | Within budget | Request continues normally | -| `BeforeRequestResult.cancel(msg)` | Budget exhausted | Raises `RequestCancelledError` | -| `BeforeRequestResult.throttle(delay_ms=N)` | Near limit | Delays request by N ms | -| `BeforeRequestResult.degrade(to_model, reason)` | Approaching limit | Switches to cheaper model | - -## Key Points - -- `emit_metric` is **required** - use `create_console_emitter(pretty=True)` for dev -- `before_request` callback enables budget enforcement -- Always wrap model calls in `try/except RequestCancelledError` -- Call `uninstrument()` on exit to flush remaining metrics -- Control agent connects automatically when `api_key` + `server_url` are provided -- Google Gemini support works automatically via gRPC client instrumentation - -## Documentation - -Full docs: [https://pypi.org/project/aden-py](https://pypi.org/project/aden-py/) diff --git a/hive/docs/aden-sdk-documents/templates/python/langgraph.md b/hive/docs/aden-sdk-documents/templates/python/langgraph.md deleted file mode 100644 index d5e6fe79..00000000 --- a/hive/docs/aden-sdk-documents/templates/python/langgraph.md +++ /dev/null @@ -1,164 +0,0 @@ -Quick reference for integrating Aden LLM observability & cost control into Python agents. - -## Prerequisites - -`.env` file should contain: - -``` -OPENAI_API_KEY=sk-xxx {{envVarComment}} -ADEN_API_URL={{serverUrl}} -ADEN_API_KEY={{apiKey}} - -``` - -## Installation - -```bash -pip install aden-py python-dotenv - -``` - -## Basic Setup (3 Steps) - -### 1. Import and Load Environment - -```python -import os -from dotenv import load_dotenv -load_dotenv() - -from aden import ( - instrument, - uninstrument, - MeterOptions, - create_console_emitter, - BeforeRequestResult, - RequestCancelledError, -) - -``` - -### 2. Define Budget Check Callback - -```python -def budget_check(params, context): - """Enforce budget limits before each LLM request.""" - budget_info = getattr(context, 'budget', None) - - if budget_info and budget_info.get('exhausted', False): - return BeforeRequestResult.cancel("Budget exhausted") - - if budget_info and budget_info.get('percent_used', 0) >= 95: - return BeforeRequestResult.throttle(delay_ms=2000) - - if budget_info and budget_info.get('percent_used', 0) >= 80: - return BeforeRequestResult.degrade(to_model="gpt-4o-mini", reason="Approaching limit") - - return BeforeRequestResult.proceed() - -``` - -### 3. Initialize Aden (at startup) - -```python -instrument(MeterOptions( - api_key=os.environ.get("ADEN_API_KEY"), - server_url=os.environ.get("ADEN_API_URL"), - emit_metric=create_console_emitter(pretty=True), - on_alert=lambda alert: print(f"[Aden {alert.level}] {alert.message}"), - before_request=budget_check, -)) - -``` - -### 4. Handle Budget Errors in Your Agent - -```python -def run_agent(user_input: str): - try: - # Your agent logic here - result = graph.invoke({"messages": [{"role": "user", "content": user_input}]}) - return result["messages"][-1].content - except RequestCancelledError as e: - return f"Sorry, you have used up your allowance. {e}" - -``` - -### 5. Cleanup (on exit) - -```python -uninstrument() - -``` - -## Complete Template - -```python -"""Agent with Aden instrumentation""" -import os -from dotenv import load_dotenv -load_dotenv() - -from aden import ( - instrument, uninstrument, MeterOptions, - create_console_emitter, BeforeRequestResult, RequestCancelledError, -) - -# Budget enforcement callback -def budget_check(params, context): - budget_info = getattr(context, 'budget', None) - if budget_info and budget_info.get('exhausted', False): - return BeforeRequestResult.cancel("Budget exhausted") - if budget_info and budget_info.get('percent_used', 0) >= 95: - return BeforeRequestResult.throttle(delay_ms=2000) - if budget_info and budget_info.get('percent_used', 0) >= 80: - return BeforeRequestResult.degrade(to_model="gpt-4o-mini", reason="Approaching limit") - return BeforeRequestResult.proceed() - -# Initialize Aden -instrument(MeterOptions( - api_key=os.environ.get("ADEN_API_KEY"), - server_url=os.environ.get("ADEN_API_URL"), - emit_metric=create_console_emitter(pretty=True), - on_alert=lambda alert: print(f"[Aden {alert.level}] {alert.message}"), - before_request=budget_check, -)) - -# === YOUR AGENT CODE HERE === - -def run_agent(user_input: str): - try: - # Your LLM calls here - pass - except RequestCancelledError as e: - return f"Sorry, you have used up your allowance. {e}" - -if __name__ == "__main__": - try: - # Your main loop - pass - finally: - uninstrument() - -``` - -## Budget Actions Reference - -| Action | When | Behavior | -| --- | --- | --- | -| `BeforeRequestResult.proceed()` | Within budget | Request continues normally | -| `BeforeRequestResult.cancel(msg)` | Budget exhausted | Raises `RequestCancelledError` | -| `BeforeRequestResult.throttle(delay_ms=N)` | Near limit | Delays request by N ms | -| `BeforeRequestResult.degrade(to_model, reason)` | Approaching limit | Switches to cheaper model | - -## Key Points - -- `emit_metric` is **required** - use `create_console_emitter(pretty=True)` for dev -- `before_request` callback enables budget enforcement -- Always wrap agent calls in `try/except RequestCancelledError` -- Call `uninstrument()` on exit to flush remaining metrics -- Control agent connects automatically when `api_key` + `server_url` are provided - -## Documentation - -Full docs: [https://pypi.org/project/aden-py](https://pypi.org/project/aden-py/) diff --git a/hive/docs/aden-sdk-documents/templates/python/livekit.md b/hive/docs/aden-sdk-documents/templates/python/livekit.md deleted file mode 100644 index e0cc13f5..00000000 --- a/hive/docs/aden-sdk-documents/templates/python/livekit.md +++ /dev/null @@ -1,162 +0,0 @@ -# Aden-py LiveKit Integration Guide - -Quick reference for integrating Aden LLM observability & cost control into LiveKit voice agents. - -## Prerequisites - -`.env` file should contain: -``` -OPENAI_API_KEY=sk-xxx -ADEN_API_URL={{serverUrl}} -ADEN_API_KEY={{apiKey}} -``` - -## Installation - -```bash -pip install 'aden-py[livekit]' python-dotenv -``` - -## Setup (4 Steps) - -### 1. Import and Load Environment - -```python -import os -from dotenv import load_dotenv -load_dotenv() - -from aden import ( - instrument, - MeterOptions, - create_console_emitter, - BeforeRequestResult, - RequestCancelledError, -) -``` - -### 2. Define Budget Check Callback - -```python -def budget_check(params, context): - """Enforce budget limits before each LLM request.""" - budget_info = getattr(context, 'budget', None) - - if budget_info and budget_info.get('exhausted', False): - return BeforeRequestResult.cancel("Budget exhausted") - - if budget_info and budget_info.get('percent_used', 0) >= 95: - return BeforeRequestResult.throttle(delay_ms=2000) - - if budget_info and budget_info.get('percent_used', 0) >= 80: - return BeforeRequestResult.degrade(to_model="gpt-4o-mini", reason="Approaching limit") - - return BeforeRequestResult.proceed() -``` - -### 3. Create Worker Prewarm Function - -**IMPORTANT:** LiveKit uses multiprocessing. Instrumentation must happen in each worker process, not the main process. - -```python -def initialize_aden_in_worker(proc): - """Initialize Aden instrumentation in each worker process.""" - instrument(MeterOptions( - api_key=os.environ.get("ADEN_API_KEY"), - server_url=os.environ.get("ADEN_API_URL"), - emit_metric=create_console_emitter(pretty=True), - on_alert=lambda alert: print(f"[Aden {alert.level}] {alert.message}"), - before_request=budget_check, - )) -``` - -### 4. Pass Prewarm Function to WorkerOptions - -```python -if __name__ == "__main__": - agents.cli.run_app(agents.WorkerOptions( - entrypoint_fnc=entrypoint, - agent_name="my-agent", - prewarm_fnc=initialize_aden_in_worker, # <-- This is the key! - )) -``` - -## Complete Template - -```python -"""LiveKit Voice Agent with Aden instrumentation""" -import os -from dotenv import load_dotenv -load_dotenv() - -from livekit import agents -from livekit.plugins import openai - -from aden import ( - instrument, MeterOptions, create_console_emitter, - BeforeRequestResult, RequestCancelledError, -) - -# Budget enforcement callback -def budget_check(params, context): - budget_info = getattr(context, 'budget', None) - if budget_info and budget_info.get('exhausted', False): - return BeforeRequestResult.cancel("Budget exhausted") - if budget_info and budget_info.get('percent_used', 0) >= 95: - return BeforeRequestResult.throttle(delay_ms=2000) - if budget_info and budget_info.get('percent_used', 0) >= 80: - return BeforeRequestResult.degrade(to_model="gpt-4o-mini", reason="Approaching limit") - return BeforeRequestResult.proceed() - -# Worker initialization - runs in each spawned process -def initialize_aden_in_worker(proc): - instrument(MeterOptions( - api_key=os.environ.get("ADEN_API_KEY"), - server_url=os.environ.get("ADEN_API_URL"), - emit_metric=create_console_emitter(pretty=True), - on_alert=lambda alert: print(f"[Aden {alert.level}] {alert.message}"), - before_request=budget_check, - )) - -async def entrypoint(ctx: agents.JobContext): - # Your agent logic here - session = agents.AgentSession( - llm=openai.LLM(model="gpt-4o-mini"), - # ... - ) - await session.start(ctx.room) - -if __name__ == "__main__": - agents.cli.run_app(agents.WorkerOptions( - entrypoint_fnc=entrypoint, - agent_name="my-agent", - prewarm_fnc=initialize_aden_in_worker, - )) -``` - -## Budget Actions Reference - -| Action | When | Behavior | -|--------|------|----------| -| `BeforeRequestResult.proceed()` | Within budget | Request continues normally | -| `BeforeRequestResult.cancel(msg)` | Budget exhausted | Raises `RequestCancelledError` | -| `BeforeRequestResult.throttle(delay_ms=N)` | Near limit (95%+) | Delays request by N ms | -| `BeforeRequestResult.degrade(to_model, reason)` | Approaching limit (80%+) | Switches to cheaper model | - -## Key Points - -- **Use `prewarm_fnc`** - LiveKit spawns worker processes; instrumentation must happen in each worker -- **Don't instrument in main process** - It won't affect the worker processes where LLM calls happen -- `emit_metric` is **required** - use `create_console_emitter(pretty=True)` for dev -- Control agent connects automatically when `api_key` + `server_url` are provided - -## Troubleshooting - -**No metrics showing?** -- Ensure `prewarm_fnc` is set in `WorkerOptions` -- Check that `ADEN_API_KEY` and `ADEN_API_URL` are in your `.env` -- Verify you're using `aden-py[livekit]` (with the livekit extra) - -**Metrics in test but not in agent?** -- LiveKit uses multiprocessing - the main process instrumentation doesn't carry over -- The `prewarm_fnc` runs in each worker before your `entrypoint` is called diff --git a/hive/docs/api/user-authentication.md b/hive/docs/api/user-authentication.md deleted file mode 100644 index 7d19ff31..00000000 --- a/hive/docs/api/user-authentication.md +++ /dev/null @@ -1,247 +0,0 @@ -# User Authentication API - -This document describes the user authentication endpoints available in the Hive backend. - -## Base URL - -``` -http://localhost:4000 -``` - -## Endpoints - -### Register a New User - -Create a new user account and receive an authentication token. - -``` -POST /user/register -``` - -#### Request Headers - -| Header | Value | Required | -| ------------ | ---------------- | -------- | -| Content-Type | application/json | Yes | - -#### Request Body - -| Field | Type | Required | Description | -| --------- | ------ | -------- | ------------------------------- | -| email | string | Yes | User's email address | -| password | string | Yes | Password (minimum 8 characters) | -| name | string | No | Display name | -| firstname | string | No | First name | -| lastname | string | No | Last name | - -#### Example Request - -```bash -curl -X POST http://localhost:4000/user/register \ - -H "Content-Type: application/json" \ - -d '{ - "email": "user@example.com", - "password": "securepassword123", - "firstname": "John", - "lastname": "Doe" - }' -``` - -#### Success Response (201 Created) - -```json -{ - "success": true, - "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", - "email": "user@example.com", - "name": "John Doe", - "firstname": "John", - "lastname": "Doe", - "current_team_id": 1, - "create_time": "2026-01-13T01:52:56.604Z" -} -``` - -#### Error Responses - -| Status | Code | Message | -| ------ | --------------------- | -------------------------------------- | -| 400 | Bad Request | Email and password are required | -| 400 | Bad Request | Please enter a valid email | -| 400 | Bad Request | Password must be at least 8 characters | -| 409 | Conflict | Email already registered | -| 500 | Internal Server Error | Registration failed. Please try again. | - ---- - -### Login - -Authenticate an existing user and receive an authentication token. - -``` -POST /user/login-v2 -``` - -#### Request Headers - -| Header | Value | Required | -| ------------ | ---------------- | -------- | -| Content-Type | application/json | Yes | - -#### Request Body - -| Field | Type | Required | Description | -| -------- | ------ | -------- | -------------------- | -| email | string | Yes | User's email address | -| password | string | Yes | User's password | - -#### Example Request - -```bash -curl -X POST http://localhost:4000/user/login-v2 \ - -H "Content-Type: application/json" \ - -d '{ - "email": "user@example.com", - "password": "securepassword123" - }' -``` - -#### Success Response (200 OK) - -```json -{ - "success": true, - "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", - "email": "user@example.com", - "firstname": "John", - "lastname": "Doe", - "name": "John Doe", - "current_team_id": 1, - "create_time": "2026-01-13T01:52:56.594Z" -} -``` - -#### Error Responses - -| Status | Code | Message | -| ------ | --------------------- | -------------------------------------- | -| 400 | Bad Request | Email and password are required | -| 400 | Bad Request | Please enter a valid email | -| 400 | Bad Request | Password must be at least 6 characters | -| 400 | Bad Request | Please sign in with OAuth | -| 401 | Unauthorized | Invalid email or password | -| 403 | Forbidden | Your account has been disabled | -| 500 | Internal Server Error | Login failed. Please try again. | - ---- - -### Get Current User - -Retrieve information about the currently authenticated user. - -``` -GET /user/me -``` - -#### Request Headers - -| Header | Value | Required | -| ------------- | ------- | -------- | -| Authorization | {token} | Yes | - -#### Example Request - -```bash -curl -X GET http://localhost:4000/user/me \ - -H "Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." -``` - -#### Success Response (200 OK) - -```json -{ - "success": true, - "user": { - "id": 1, - "email": "user@example.com", - "name": "John Doe", - "firstname": "John", - "lastname": "Doe", - "current_team_id": 1, - "avatar_url": null - } -} -``` - -#### Error Responses - -| Status | Code | Message | -| ------ | --------------------- | ----------------------- | -| 401 | Unauthorized | No token provided | -| 401 | Unauthorized | Invalid token | -| 500 | Internal Server Error | Failed to get user info | - ---- - -## Authentication - -After successful login or registration, the API returns a JWT token. Include this token in the `Authorization` header for authenticated requests: - -``` -Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... -``` - -### Token Structure - -The JWT token contains the following claims: - -| Claim | Description | -| --------------- | -------------------------------- | -| id | User ID | -| email | User email | -| firstname | User first name | -| lastname | User last name | -| current_team_id | User's current team ID | -| salt | Random salt for token validation | -| iat | Issued at timestamp | -| exp | Expiration timestamp | - -### Token Expiration - -By default, tokens expire after 7 days. This can be configured via the `JWT_EXPIRES_IN` environment variable. - ---- - -## Development Credentials - -For local development, the following default user is available: - -| Field | Value | -| -------- | ------------------- | -| Email | dev@honeycomb.local | -| Password | honeycomb123 | - ---- - -## Error Response Format - -All error responses follow this format: - -```json -{ - "success": false, - "msg": "Error message describing what went wrong" -} -``` - ---- - -## Rate Limiting - -Currently, rate limiting is not enabled by default. It can be enabled via the `features.rate_limiting` config option. - ---- - -## CORS - -The API supports CORS. Configure the allowed origin via the `cors.origin` config option (default: `http://localhost:3000`). diff --git a/hive/docs/sdk-event-specification.md b/hive/docs/sdk-event-specification.md deleted file mode 100644 index 78ccf07b..00000000 --- a/hive/docs/sdk-event-specification.md +++ /dev/null @@ -1,703 +0,0 @@ -# Aden SDK Trace Event Specification - -**Version:** 2.0.0 -**Last Updated:** 2026-01-08 - -This document defines the authoritative specification for all events transmitted between the Aden SDK and the Aden Hive control server. - ---- - -## Table of Contents - -1. [Overview](#overview) -2. [Event Types](#event-types) -3. [MetricEvent](#metricevent) -4. [ContentCapture (Layer 0)](#contentcapture-layer-0) -5. [ToolCallCapture (Layer 6)](#toolcallcapture-layer-6) -6. [ControlEvent](#controlevent) -7. [HeartbeatEvent](#heartbeatevent) -8. [ErrorEvent](#errorevent) -9. [API Endpoints](#api-endpoints) -10. [Storage Architecture](#storage-architecture) - ---- - -## Overview - -The Aden SDK captures telemetry from LLM API calls and transmits events to the Aden Hive server for: -- **Observability**: Token usage, latency, cost tracking -- **Governance**: Content capture, tool call validation -- **Control**: Budget enforcement, rate limiting, model degradation - -### Providers Supported - -| Provider | Value | -|----------|-------| -| OpenAI | `openai` | -| Anthropic | `anthropic` | -| Google Gemini | `gemini` | - -### Transport - -Events are sent via: -- **HTTP POST** to `/v1/control/events` (batch) -- **WebSocket** for real-time policy sync - ---- - -## Event Types - -| Event Type | Description | Direction | -|------------|-------------|-----------| -| `metric` | LLM call telemetry | SDK → Server | -| `control` | Control action taken | SDK → Server | -| `heartbeat` | Health status | SDK → Server | -| `error` | Error report | SDK → Server | - ---- - -## MetricEvent - -The primary event emitted after each LLM API call. Contains flat fields for consistent cross-provider analytics. - -### Envelope Structure - -```json -{ - "event_type": "metric", - "timestamp": "2026-01-08T12:00:00.000Z", - "sdk_instance_id": "uuid-v4", - "data": { /* MetricEvent fields */ } -} -``` - -### MetricEvent Fields - -#### Identity (OpenTelemetry-compatible) - -| Field | Type | Required | Description | -|-------|------|----------|-------------| -| `trace_id` | string | **Yes** | Trace ID grouping related operations | -| `span_id` | string | Yes | Unique span ID for this operation | -| `parent_span_id` | string | No | Parent span for nested calls | -| `request_id` | string | No | Provider-specific request ID | -| `call_sequence` | integer | Yes | Sequence number within the trace | - -#### Provider & Model - -| Field | Type | Required | Description | -|-------|------|----------|-------------| -| `provider` | string | **Yes** | `openai`, `anthropic`, `gemini` | -| `model` | string | **Yes** | Model identifier (e.g., `gpt-4o`, `claude-3-opus`) | -| `stream` | boolean | Yes | Whether streaming was enabled | -| `timestamp` | string | **Yes** | ISO 8601 timestamp of request start | - -#### Performance - -| Field | Type | Required | Description | -|-------|------|----------|-------------| -| `latency_ms` | float | Yes | Request latency in milliseconds | -| `status_code` | integer | No | HTTP status code | -| `error` | string | No | Error message if request failed | - -#### Token Usage - -| Field | Type | Required | Description | -|-------|------|----------|-------------| -| `input_tokens` | integer | Yes | Input/prompt tokens consumed | -| `output_tokens` | integer | Yes | Output/completion tokens consumed | -| `total_tokens` | integer | Yes | Total tokens (input + output) | -| `cached_tokens` | integer | No | Tokens served from cache | -| `reasoning_tokens` | integer | No | Reasoning tokens (o1/o3 models) | - -#### Rate Limits - -| Field | Type | Required | Description | -|-------|------|----------|-------------| -| `rate_limit_remaining_requests` | integer | No | Remaining requests in window | -| `rate_limit_remaining_tokens` | integer | No | Remaining tokens in window | -| `rate_limit_reset_requests` | float | No | Seconds until request limit resets | -| `rate_limit_reset_tokens` | float | No | Seconds until token limit resets | - -#### Call Context - -| Field | Type | Required | Description | -|-------|------|----------|-------------| -| `agent_stack` | string[] | No | Stack of agent names leading to this call | -| `call_site_file` | string | No | File path of immediate caller | -| `call_site_line` | integer | No | Line number | -| `call_site_column` | integer | No | Column number | -| `call_site_function` | string | No | Function name | -| `call_stack` | string[] | No | Full call stack (file:line:function) | - -#### Tool Usage (Summary) - -| Field | Type | Required | Description | -|-------|------|----------|-------------| -| `tool_call_count` | integer | No | Number of tool calls made | -| `tool_names` | string | No | Tool names (comma-separated) | - -#### Provider-specific - -| Field | Type | Required | Description | -|-------|------|----------|-------------| -| `service_tier` | string | No | Service tier (auto, default, flex, priority) | -| `metadata` | object | No | Custom metadata attached to request | - -#### Layer 0: Content Capture - -| Field | Type | Required | Description | -|-------|------|----------|-------------| -| `content_capture` | ContentCapture | No | Full content capture (see below) | - -#### Layer 6: Tool Call Deep Inspection - -| Field | Type | Required | Description | -|-------|------|----------|-------------| -| `tool_calls_captured` | ToolCallCapture[] | No | Detailed tool call captures | -| `tool_validation_errors_count` | integer | No | Count of validation errors | - -### Example MetricEvent - -```json -{ - "event_type": "metric", - "timestamp": "2026-01-08T12:00:00.000Z", - "sdk_instance_id": "abc123", - "data": { - "trace_id": "tr_abc123", - "span_id": "sp_def456", - "call_sequence": 1, - "provider": "openai", - "model": "gpt-4o", - "stream": false, - "latency_ms": 1234.5, - "input_tokens": 150, - "output_tokens": 50, - "total_tokens": 200, - "cached_tokens": 0, - "agent_stack": ["main_agent", "sub_agent"], - "tool_call_count": 2, - "tool_names": "search,calculate", - "metadata": { - "user_id": "user_123", - "session_id": "sess_456" - }, - "content_capture": { - "system_prompt": "You are a helpful assistant.", - "messages": [...], - "response_content": "Here is my response...", - "finish_reason": "stop" - } - } -} -``` - ---- - -## ContentCapture (Layer 0) - -Full content capture for request and response. Enables governance, debugging, and compliance. - -### Fields - -| Field | Type | Description | -|-------|------|-------------| -| `system_prompt` | string \| ContentReference | System prompt | -| `messages` | MessageCapture[] \| ContentReference | Message history | -| `tools` | ToolSchemaCapture[] \| ContentReference | Tools schema | -| `params` | RequestParamsCapture | Request parameters | -| `response_content` | string \| ContentReference | Response text | -| `finish_reason` | string | Why response ended: `stop`, `length`, `tool_calls`, `content_filter` | -| `choice_count` | integer | Number of choices (for n > 1) | -| `has_images` | boolean | Whether request contained images | -| `image_urls` | string[] | Image URLs (never base64) | - -### ContentReference - -When content exceeds `max_content_bytes`, it's stored separately and referenced: - -```json -{ - "content_id": "uuid-v4", - "content_hash": "sha256-hex", - "byte_size": 12345, - "truncated_preview": "First 100 chars..." -} -``` - -### MessageCapture - -```json -{ - "role": "user|assistant|system|tool", - "content": "string or ContentReference", - "name": "optional name", - "tool_call_id": "for tool results" -} -``` - -### ToolSchemaCapture - -```json -{ - "name": "function_name", - "description": "Tool description", - "parameters_schema": { /* JSON Schema */ } -} -``` - -### RequestParamsCapture - -```json -{ - "temperature": 0.7, - "max_tokens": 1000, - "top_p": 1.0, - "frequency_penalty": 0, - "presence_penalty": 0, - "stop": ["STOP"], - "seed": 12345, - "top_k": 40 -} -``` - ---- - -## ToolCallCapture (Layer 6) - -Detailed tool call capture with validation results. - -### Fields - -| Field | Type | Description | -|-------|------|-------------| -| `id` | string | Tool call ID for correlation | -| `name` | string | Tool/function name | -| `arguments` | object \| ContentReference | Parsed arguments | -| `arguments_raw` | string \| ContentReference | Raw JSON string | -| `validation_errors` | ValidationError[] | Schema validation errors | -| `is_valid` | boolean | Whether arguments passed validation | -| `index` | integer | Position in tool_calls array | - -### ValidationError - -```json -{ - "path": "properties.name", - "message": "Required property missing", - "expected_type": "string", - "actual_type": "undefined" -} -``` - ---- - -## ControlEvent - -Emitted when a control action is taken on a request. - -### Fields - -| Field | Type | Required | Description | -|-------|------|----------|-------------| -| `event_type` | string | Yes | Always `"control"` | -| `timestamp` | string | Yes | ISO 8601 timestamp | -| `sdk_instance_id` | string | Yes | SDK instance identifier | -| `trace_id` | string | Yes | Associated trace ID | -| `span_id` | string | Yes | Associated span ID | -| `provider` | string | Yes | Provider name | -| `original_model` | string | Yes | Originally requested model | -| `action` | string | Yes | Action taken (see below) | -| `reason` | string | No | Human-readable reason | -| `degraded_to` | string | No | Model switched to (if degraded) | -| `throttle_delay_ms` | integer | No | Delay applied (if throttled) | -| `estimated_cost` | float | No | Estimated cost that triggered decision | -| `policy_id` | string | Yes | Policy ID (default: `"default"`) | -| `budget_id` | string | No | Budget that triggered action | -| `context_id` | string | No | Context ID (user, session, etc.) | - -### Control Actions - -| Action | Description | -|--------|-------------| -| `allow` | Request proceeds normally | -| `block` | Request is rejected | -| `throttle` | Request is delayed before proceeding | -| `degrade` | Request uses a cheaper/fallback model | -| `alert` | Request proceeds but triggers alert | - -### Example ControlEvent - -```json -{ - "event_type": "control", - "timestamp": "2026-01-08T12:00:00.000Z", - "sdk_instance_id": "abc123", - "trace_id": "tr_abc123", - "span_id": "sp_def456", - "provider": "openai", - "original_model": "gpt-4o", - "action": "degrade", - "reason": "Budget limit exceeded", - "degraded_to": "gpt-4o-mini", - "estimated_cost": 0.05, - "policy_id": "default", - "budget_id": "budget_monthly" -} -``` - ---- - -## HeartbeatEvent - -Periodic health check sent by the SDK. - -### Fields - -| Field | Type | Required | Description | -|-------|------|----------|-------------| -| `event_type` | string | Yes | Always `"heartbeat"` | -| `timestamp` | string | Yes | ISO 8601 timestamp | -| `sdk_instance_id` | string | Yes | SDK instance identifier | -| `status` | string | Yes | `healthy`, `degraded`, `reconnecting` | -| `requests_since_last` | integer | Yes | Requests since last heartbeat | -| `errors_since_last` | integer | Yes | Errors since last heartbeat | -| `policy_cache_age_seconds` | integer | Yes | Policy cache age | -| `websocket_connected` | boolean | Yes | WebSocket connection status | -| `sdk_version` | string | Yes | SDK version | - ---- - -## ErrorEvent - -Emitted when an error occurs in the SDK. - -### Fields - -| Field | Type | Required | Description | -|-------|------|----------|-------------| -| `event_type` | string | Yes | Always `"error"` | -| `timestamp` | string | Yes | ISO 8601 timestamp | -| `sdk_instance_id` | string | Yes | SDK instance identifier | -| `message` | string | Yes | Error message | -| `code` | string | No | Error code | -| `stack` | string | No | Stack trace | -| `trace_id` | string | No | Related trace ID | - ---- - -## API Endpoints - -### POST /v1/control/events - -Submit events batch. - -**Request:** -```json -{ - "events": [ - { "event_type": "metric", "timestamp": "...", "data": {...} }, - { "event_type": "control", "timestamp": "...", ... } - ] -} -``` - -**Response:** -```json -{ - "success": true, - "processed": 2 -} -``` - -### POST /v1/control/content - -Store large content items (MongoDB - for SDK content references). - -**Request:** -```json -{ - "items": [ - { - "content_id": "uuid", - "content_hash": "sha256-hex", - "content": "full content string", - "byte_size": 12345 - } - ] -} -``` - -**Response:** -```json -{ - "success": true, - "stored": 1 -} -``` - -### GET /v1/control/content/:contentId - -Retrieve stored content by ID (MongoDB). - -**Response:** -```json -{ - "content_id": "uuid", - "content_hash": "sha256-hex", - "content": "full content string", - "byte_size": 12345 -} -``` - -### GET /v1/control/events/:traceId/:callSequence/content - -Retrieve content for a specific event from TSDB warm/cold storage. - -**Response:** -```json -{ - "trace_id": "tr_abc123", - "call_sequence": 1, - "content_items": [ - { - "content_type": "system_prompt", - "content_hash": "sha256-hex", - "byte_size": 256, - "truncated_preview": "You are a helpful...", - "content": "You are a helpful assistant..." - }, - { - "content_type": "messages", - "content_hash": "sha256-hex", - "byte_size": 4096, - "message_count": 5, - "truncated_preview": "[{\"role\":\"user\"...", - "content": "[{\"role\":\"user\",\"content\":\"Hello\"}...]" - }, - { - "content_type": "response", - "content_hash": "sha256-hex", - "byte_size": 512, - "truncated_preview": "Here is my response...", - "content": "Here is my response to your question..." - } - ], - "count": 3 -} -``` - -### GET /v1/control/content/hash/:contentHash - -Retrieve content from cold storage by SHA-256 hash. - -**Response:** -```json -{ - "content_hash": "sha256-hex", - "content": "full content string", - "byte_size": 12345 -} -``` - -### GET /v1/control/policy - -Fetch current control policy. - -### POST /v1/control/budget/validate - -Server-side budget validation (hybrid enforcement). - ---- - -## Storage Architecture - -The storage system uses a **hot/warm/cold** architecture optimized for time-series analytics with content deduplication. - -``` -┌─────────────────────────────────────────────────────────────────────┐ -│ SDK Event Ingestion │ -└─────────────────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────────────┐ -│ Event Normalization & Content Extraction │ -│ │ -│ • Extract content_capture fields │ -│ • Hash content with SHA-256 │ -│ • Create lightweight content flags for hot table │ -└─────────────────────────────────────────────────────────────────────┘ - │ - ┌───────────────┼───────────────┐ - ▼ ▼ ▼ - ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ - │ HOT TABLE │ │ WARM TABLE │ │ COLD TABLE │ - │ llm_events │ │llm_event_ │ │llm_content_ │ - │ │ │ content │ │ store │ - │ Metrics only │ │Content refs │ │ Deduplicated │ - │ Fast queries │ │ per event │ │ content │ - └──────────────┘ └──────────────┘ └──────────────┘ -``` - -### Design Principles - -1. **Hot/Cold Separation**: Metrics stay in the hot table for fast time-series queries; content is stored separately -2. **Content Deduplication**: Identical content (same SHA-256 hash) is stored once, regardless of how many events reference it -3. **Reference Counting**: Cold storage tracks how many events reference each piece of content -4. **Preview Without Fetch**: Warm table stores truncated previews for quick scanning without fetching full content - -### TSDB Hot Table: `llm_events` - -Stores metric events for fast time-series analytics. **Content is NOT stored here** (only lightweight flags). - -| Column | Type | Description | -|--------|------|-------------| -| `timestamp` | timestamptz | Event timestamp (partition key) | -| `ingest_date` | date | Ingestion date | -| `team_id` | text | Team identifier | -| `user_id` | text | User identifier | -| `trace_id` | text | Trace ID | -| `span_id` | text | Span ID | -| `parent_span_id` | text | Parent span ID | -| `request_id` | text | Provider request ID | -| `provider` | text | Provider name | -| `call_sequence` | integer | Sequence within trace | -| `model` | text | Model identifier | -| `stream` | boolean | Streaming flag | -| `agent` | text | Primary agent name | -| `agent_stack` | jsonb | Full agent stack | -| `latency_ms` | double precision | Latency in ms | -| `usage_input_tokens` | double precision | Input tokens | -| `usage_output_tokens` | double precision | Output tokens | -| `usage_total_tokens` | double precision | Total tokens | -| `usage_cached_tokens` | double precision | Cached tokens | -| `usage_reasoning_tokens` | double precision | Reasoning tokens | -| `cost_total` | numeric | Calculated cost | -| `metadata` | jsonb | Custom metadata | -| `call_site` | jsonb | Call site info | -| `has_content` | boolean | Whether content was captured | -| `finish_reason` | text | Response finish reason | -| `tool_call_count` | integer | Number of tool calls | -| `created_at` | timestamptz | Record creation time | - -**Primary Key:** `(timestamp, trace_id, call_sequence)` - -**Indexes:** -- `idx_llm_events_ts` - timestamp DESC -- `idx_llm_events_team_ts` - team_id, timestamp DESC -- `idx_llm_events_model` - model -- `idx_llm_events_agent` - agent -- `idx_llm_events_trace` - trace_id - -### TSDB Warm Table: `llm_event_content` - -Links events to deduplicated content in cold storage. One row per content type per event. - -| Column | Type | Description | -|--------|------|-------------| -| `id` | bigserial | Auto-increment ID | -| `timestamp` | timestamptz | Event timestamp | -| `trace_id` | text | Trace ID | -| `call_sequence` | integer | Sequence within trace | -| `team_id` | text | Team identifier | -| `content_type` | text | Type: `system_prompt`, `messages`, `response`, `tools`, `params` | -| `content_hash` | text | SHA-256 hash (FK to cold store) | -| `byte_size` | integer | Content size in bytes | -| `message_count` | integer | Number of messages (for `messages` type) | -| `truncated_preview` | text | First 200 chars for quick preview | -| `created_at` | timestamptz | Record creation time | - -**Primary Key:** `(id)` - -**Indexes:** -- `idx_llm_event_content_event` - trace_id, call_sequence, timestamp -- `idx_llm_event_content_type` - team_id, content_type, timestamp DESC -- `idx_llm_event_content_hash` - content_hash - -### TSDB Cold Table: `llm_content_store` - -Content-addressable storage with SHA-256 hashes. Deduplicated across all events. - -| Column | Type | Description | -|--------|------|-------------| -| `content_hash` | text | SHA-256 hash of content (PK) | -| `team_id` | text | Team identifier (PK) | -| `content` | text | Full content string | -| `byte_size` | integer | Content size in bytes | -| `ref_count` | integer | Number of events referencing this content | -| `first_seen_at` | timestamptz | When content was first stored | -| `last_seen_at` | timestamptz | When content was last referenced | - -**Primary Key:** `(content_hash, team_id)` - -**Indexes:** -- `idx_llm_content_store_refs` - team_id, ref_count, last_seen_at (for cleanup) - -### MongoDB: `aden_control_content` - -Stores large content items from SDK's content reference system (separate from TSDB storage). - -| Field | Type | Description | -|-------|------|-------------| -| `content_id` | string | Unique content identifier | -| `team_id` | string | Team identifier | -| `content_hash` | string | SHA-256 hash | -| `content` | string | Full content | -| `byte_size` | number | Content size in bytes | -| `created_at` | string | Creation timestamp | -| `updated_at` | string | Last update timestamp | - -**Index:** `{ content_id: 1, team_id: 1 }` (unique) - -### MongoDB: `aden_control_policies` - -Stores control policies for teams. - ---- - -## Content Types - -The warm table stores references to different content types: - -| Type | Description | Example | -|------|-------------|---------| -| `system_prompt` | System/developer message | "You are a helpful assistant..." | -| `messages` | Full conversation history | JSON array of messages | -| `response` | Model's response content | "Here is my response..." | -| `tools` | Tool/function schemas | JSON array of tool definitions | -| `params` | Request parameters | `{"temperature": 0.7, "max_tokens": 1000}` | - ---- - -## Deduplication Example - -When the same system prompt is used across multiple requests: - -``` -Request 1: system_prompt = "You are a helpful assistant." - → Hash: abc123... - → Cold store: INSERT (ref_count = 1) - → Warm store: INSERT reference for event 1 - -Request 2: system_prompt = "You are a helpful assistant." (same) - → Hash: abc123... (same hash) - → Cold store: UPDATE ref_count = 2 - → Warm store: INSERT reference for event 2 - -Request 3: system_prompt = "You are a code reviewer." - → Hash: def456... (different) - → Cold store: INSERT (ref_count = 1) - → Warm store: INSERT reference for event 3 -``` - -This means the first system prompt is stored **once** but referenced by two events. - ---- - -## Version History - -| Version | Date | Changes | -|---------|------|---------| -| 2.0.0 | 2026-01-08 | Hot/warm/cold storage architecture; content deduplication | -| 1.0.0 | 2026-01-08 | Initial specification | diff --git a/hive/jest.config.js b/hive/jest.config.js deleted file mode 100644 index 0906aa83..00000000 --- a/hive/jest.config.js +++ /dev/null @@ -1,24 +0,0 @@ -/** @type {import('ts-jest').JestConfigWithTsJest} */ -module.exports = { - preset: 'ts-jest', - testEnvironment: 'node', - roots: ['/tests'], - testMatch: ['**/*.test.ts'], - moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], - collectCoverageFrom: [ - 'src/**/*.ts', - '!src/**/*.d.ts', - '!src/index.ts', - ], - coverageDirectory: 'coverage', - coverageReporters: ['text', 'lcov', 'html'], - setupFilesAfterEnv: ['/tests/setup.ts'], - transform: { - '^.+\\.tsx?$': ['ts-jest', { - tsconfig: 'tsconfig.test.json' - }] - }, - testTimeout: 10000, - clearMocks: true, - restoreMocks: true, -}; diff --git a/hive/k8s/base/deployment.yaml b/hive/k8s/base/deployment.yaml deleted file mode 100644 index 6023d634..00000000 --- a/hive/k8s/base/deployment.yaml +++ /dev/null @@ -1,101 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: aden-hive - labels: - app: aden-hive - app.kubernetes.io/name: aden-hive -spec: - replicas: 1 - selector: - matchLabels: - app: aden-hive - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 25% - maxUnavailable: 25% - template: - metadata: - labels: - app: aden-hive - app.kubernetes.io/name: aden-hive - spec: - containers: - - name: aden-hive - image: aden-hive - imagePullPolicy: IfNotPresent - ports: - - name: http - containerPort: 3001 - protocol: TCP - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: POD_IP - valueFrom: - fieldRef: - fieldPath: status.podIP - - name: MYSQL_SSL_CA - value: /mnt/certs/mysql/server-ca.pem - - name: MYSQL_SSL_KEY - value: /mnt/certs/mysql/client-key.pem - - name: MYSQL_SSL_CERT - value: /mnt/certs/mysql/client-cert.pem - volumeMounts: - - name: mysql-ssl-certs - mountPath: /mnt/certs/mysql - readOnly: true - envFrom: - - configMapRef: - name: aden-hive-config - - secretRef: - name: aden-hive-secrets - resources: - requests: - cpu: 250m - memory: 256Mi - limits: - cpu: 1000m - memory: 512Mi - livenessProbe: - httpGet: - path: /health - port: 3001 - initialDelaySeconds: 60 - periodSeconds: 60 - timeoutSeconds: 15 - failureThreshold: 5 - readinessProbe: - httpGet: - path: /health - port: 3001 - initialDelaySeconds: 30 - periodSeconds: 30 - timeoutSeconds: 10 - failureThreshold: 5 - securityContext: - allowPrivilegeEscalation: false - runAsNonRoot: true - runAsUser: 1001 - capabilities: - drop: - - ALL - volumes: - - name: mysql-ssl-certs - secret: - secretName: mysql-ssl-certs - defaultMode: 0444 - items: - - key: server-ca.pem - path: server-ca.pem - - key: client-key.pem - path: client-key.pem - - key: client-cert.pem - path: client-cert.pem diff --git a/hive/k8s/base/kustomization.yaml b/hive/k8s/base/kustomization.yaml deleted file mode 100644 index 5b98e944..00000000 --- a/hive/k8s/base/kustomization.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -resources: - - deployment.yaml - - service.yaml diff --git a/hive/k8s/base/service.yaml b/hive/k8s/base/service.yaml deleted file mode 100644 index 3df25259..00000000 --- a/hive/k8s/base/service.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: aden-hive - labels: - app: aden-hive -spec: - type: ClusterIP - ports: - - port: 80 - targetPort: 3001 - protocol: TCP - name: http - selector: - app: aden-hive diff --git a/hive/k8s/overlays/production/kustomization.yaml b/hive/k8s/overlays/production/kustomization.yaml deleted file mode 100644 index b426fcc9..00000000 --- a/hive/k8s/overlays/production/kustomization.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -namespace: production - -resources: - - ../../base - - namespace.yaml - -namePrefix: prod- - -commonLabels: - environment: production - -images: - - name: aden-hive - newName: gcr.io/tool-for-analyst/aden-hive - newTag: latest - -patches: - - path: patches/deployment.yaml diff --git a/hive/k8s/overlays/production/namespace.yaml b/hive/k8s/overlays/production/namespace.yaml deleted file mode 100644 index 43df7d33..00000000 --- a/hive/k8s/overlays/production/namespace.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: production - labels: - environment: production diff --git a/hive/k8s/overlays/production/patches/deployment.yaml b/hive/k8s/overlays/production/patches/deployment.yaml deleted file mode 100644 index f1f2423c..00000000 --- a/hive/k8s/overlays/production/patches/deployment.yaml +++ /dev/null @@ -1,27 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: aden-hive -spec: - replicas: 2 - template: - spec: - containers: - - name: aden-hive - env: - - name: NODE_ENV - value: production - envFrom: - - configMapRef: - name: aden-api-server-config - - secretRef: - name: aden-api-server-secrets - - secretRef: - name: database-secrets - resources: - requests: - cpu: 500m - memory: 512Mi - limits: - cpu: 1000m - memory: 1Gi diff --git a/hive/k8s/overlays/staging/kustomization.yaml b/hive/k8s/overlays/staging/kustomization.yaml deleted file mode 100644 index 4f83faf1..00000000 --- a/hive/k8s/overlays/staging/kustomization.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -namespace: staging - -resources: - - ../../base - - namespace.yaml - -namePrefix: staging- - -commonLabels: - environment: staging - -images: - - name: aden-hive - newName: gcr.io/acho-alpha-project/aden-hive - newTag: latest - -patches: - - path: patches/deployment.yaml diff --git a/hive/k8s/overlays/staging/namespace.yaml b/hive/k8s/overlays/staging/namespace.yaml deleted file mode 100644 index 11eb8621..00000000 --- a/hive/k8s/overlays/staging/namespace.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: staging - labels: - environment: staging diff --git a/hive/k8s/overlays/staging/patches/deployment.yaml b/hive/k8s/overlays/staging/patches/deployment.yaml deleted file mode 100644 index 962acbf8..00000000 --- a/hive/k8s/overlays/staging/patches/deployment.yaml +++ /dev/null @@ -1,27 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: aden-hive -spec: - replicas: 1 - template: - spec: - containers: - - name: aden-hive - env: - - name: NODE_ENV - value: staging - envFrom: - - configMapRef: - name: aden-api-server-config - - secretRef: - name: aden-api-server-secrets - - secretRef: - name: database-secrets - resources: - requests: - cpu: 250m - memory: 256Mi - limits: - cpu: 500m - memory: 512Mi diff --git a/hive/package.json b/hive/package.json deleted file mode 100644 index 1fa3b5d3..00000000 --- a/hive/package.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "name": "hive", - "version": "1.0.0", - "description": "Aden Hive - LLM observability and control plane backend", - "private": true, - "main": "dist/index.js", - "scripts": { - "dev": "ts-node-dev --respawn --transpile-only src/index.ts", - "build": "tsc && npm run build:copy-sql", - "build:copy-sql": "find src -name '*.sql' -exec sh -c 'mkdir -p dist/$(dirname ${1#src/}) && cp \"$1\" dist/${1#src/}' _ {} \\;", - "start": "node dist/index.js", - "test": "jest", - "test:watch": "jest --watch", - "test:coverage": "jest --coverage", - "test:mcp": "ts-node --transpile-only scripts/test-mcp.ts", - "test:mcp:quick": "./scripts/test-mcp-curl.sh", - "lint": "eslint src/", - "typecheck": "tsc --noEmit", - "clean": "rm -rf dist node_modules" - }, - "dependencies": { - "@acho-inc/administration": "^1.0.7", - "@modelcontextprotocol/sdk": "^1.25.2", - "@socket.io/redis-adapter": "^8.2.1", - "@socket.io/redis-emitter": "^5.1.0", - "compression": "^1.7.4", - "cors": "^2.8.5", - "dotenv": "^16.3.1", - "express": "^4.18.2", - "helmet": "^7.1.0", - "http-errors": "^2.0.0", - "ioredis": "^5.3.2", - "jsonwebtoken": "^9.0.2", - "mongodb": "^6.3.0", - "morgan": "^1.10.0", - "passport": "^0.7.0", - "passport-jwt": "^4.0.1", - "pg": "^8.11.3", - "socket.io": "^4.6.1", - "zod": "^4.3.5" - }, - "devDependencies": { - "@types/compression": "^1.7.5", - "@types/cors": "^2.8.17", - "@types/express": "^4.17.21", - "@types/jest": "^30.0.0", - "@types/jsonwebtoken": "^9.0.5", - "@types/morgan": "^1.9.9", - "@types/node": "^20.10.0", - "@types/passport": "^1.0.16", - "@types/passport-jwt": "^4.0.1", - "@types/pg": "^8.10.9", - "@types/supertest": "^6.0.3", - "@typescript-eslint/eslint-plugin": "^6.14.0", - "@typescript-eslint/parser": "^6.14.0", - "eslint": "^8.56.0", - "jest": "^29.7.0", - "supertest": "^7.2.2", - "ts-jest": "^29.4.6", - "ts-node": "^10.9.2", - "ts-node-dev": "^2.0.0", - "typescript": "^5.3.0" - }, - "engines": { - "node": ">=18.0.0" - } -} diff --git a/hive/scripts/migrate-add-agent-name.ts b/hive/scripts/migrate-add-agent-name.ts deleted file mode 100644 index f9d8f945..00000000 --- a/hive/scripts/migrate-add-agent-name.ts +++ /dev/null @@ -1,129 +0,0 @@ -/** - * Migration: Add agent_name column to llm_events table - * - * This script adds the `agent_name` column to all existing team schemas. - * Run with: npx ts-node scripts/migrate-add-agent-name.ts - * - * Environment variables required: - * - PGHOST, PGUSER, PGPASSWORD, PGDATABASE, PGPORT (or PG_CONNECTION_STRING) - */ - -import { Pool } from "pg"; - -const getPool = (): Pool => { - // Support multiple env var names - const connectionString = - process.env.TSDB_PG_URL || - process.env.PG_CONNECTION_STRING || - process.env.DATABASE_URL; - - if (connectionString) { - return new Pool({ connectionString }); - } - - return new Pool({ - host: process.env.PGHOST || "localhost", - user: process.env.PGUSER || "postgres", - password: process.env.PGPASSWORD || "postgres", - database: process.env.PGDATABASE || "aden", - port: parseInt(process.env.PGPORT || "5432", 10), - }); -}; - -async function migrate() { - const pool = getPool(); - - try { - console.log("[Migration] Starting agent_name column migration..."); - - // Find all team schemas (schemas starting with 'team_') - const schemasResult = await pool.query(` - SELECT schema_name - FROM information_schema.schemata - WHERE schema_name LIKE 'team_%' - ORDER BY schema_name - `); - - const schemas = schemasResult.rows.map((r) => r.schema_name as string); - console.log(`[Migration] Found ${schemas.length} team schemas`); - - if (schemas.length === 0) { - console.log("[Migration] No team schemas found. Nothing to migrate."); - return; - } - - let successCount = 0; - let skipCount = 0; - let errorCount = 0; - - for (const schema of schemas) { - try { - // Check if llm_events table exists in this schema - const tableExists = await pool.query( - ` - SELECT 1 - FROM information_schema.tables - WHERE table_schema = $1 AND table_name = 'llm_events' - `, - [schema] - ); - - if (tableExists.rows.length === 0) { - console.log(`[Migration] ${schema}: No llm_events table, skipping`); - skipCount++; - continue; - } - - // Check if agent_name column already exists - const columnExists = await pool.query( - ` - SELECT 1 - FROM information_schema.columns - WHERE table_schema = $1 - AND table_name = 'llm_events' - AND column_name = 'agent_name' - `, - [schema] - ); - - if (columnExists.rows.length > 0) { - console.log(`[Migration] ${schema}: agent_name column already exists, skipping`); - skipCount++; - continue; - } - - // Add the agent_name column after agent column - await pool.query(` - ALTER TABLE ${schema}.llm_events - ADD COLUMN agent_name text - `); - - console.log(`[Migration] ${schema}: Added agent_name column`); - successCount++; - } catch (err) { - console.error(`[Migration] ${schema}: Error - ${(err as Error).message}`); - errorCount++; - } - } - - console.log("\n[Migration] Summary:"); - console.log(` - Schemas processed: ${schemas.length}`); - console.log(` - Successfully migrated: ${successCount}`); - console.log(` - Skipped (already migrated or no table): ${skipCount}`); - console.log(` - Errors: ${errorCount}`); - - if (errorCount === 0) { - console.log("\n[Migration] Completed successfully!"); - } else { - console.log("\n[Migration] Completed with errors. Please review above."); - process.exit(1); - } - } catch (err) { - console.error("[Migration] Fatal error:", (err as Error).message); - process.exit(1); - } finally { - await pool.end(); - } -} - -migrate(); diff --git a/hive/scripts/test-mcp-curl.sh b/hive/scripts/test-mcp-curl.sh deleted file mode 100755 index ed4d1f28..00000000 --- a/hive/scripts/test-mcp-curl.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/bash -# -# Quick MCP Server Test using curl -# -# Usage: -# ADEN_AUTH_TOKEN=your-jwt-token ./scripts/test-mcp-curl.sh -# -# The script tests basic connectivity and endpoints. - -set -e - -API_URL="${ADEN_API_URL:-http://localhost:3000}" -TOKEN="${ADEN_AUTH_TOKEN}" - -if [ -z "$TOKEN" ]; then - echo "Error: ADEN_AUTH_TOKEN environment variable is required" - echo "Usage: ADEN_AUTH_TOKEN=your-jwt-token ./scripts/test-mcp-curl.sh" - exit 1 -fi - -echo "============================================================" -echo "MCP Server Quick Test" -echo "============================================================" -echo "API URL: $API_URL" -echo "" - -# Test 1: Health check -echo "1. Health Check (GET /mcp/health)" -curl -s "$API_URL/mcp/health" | jq . -echo "" - -# Test 2: List sessions (should be empty or show existing) -echo "2. List Sessions (GET /mcp/sessions)" -curl -s -H "Authorization: Bearer $TOKEN" "$API_URL/mcp/sessions" | jq . -echo "" - -# Test 3: Start SSE connection and capture session ID -echo "3. Testing SSE Connection (GET /mcp)" -echo " Starting connection (will timeout after 2s)..." - -# Use timeout to limit the SSE connection -SESSION_ID=$(timeout 2s curl -s -N \ - -H "Authorization: Bearer $TOKEN" \ - -H "Accept: text/event-stream" \ - "$API_URL/mcp" 2>&1 | head -5 || true) - -echo " Response (first 5 lines):" -echo "$SESSION_ID" | head -5 -echo "" - -# Test 4: Check sessions again -echo "4. Sessions After Connection (GET /mcp/sessions)" -curl -s -H "Authorization: Bearer $TOKEN" "$API_URL/mcp/sessions" | jq . -echo "" - -echo "============================================================" -echo "Quick test completed!" -echo "" -echo "For full tool testing, use the TypeScript test client:" -echo " ADEN_AUTH_TOKEN=\$TOKEN npx ts-node scripts/test-mcp.ts" -echo "============================================================" diff --git a/hive/scripts/test-mcp.ts b/hive/scripts/test-mcp.ts deleted file mode 100644 index bb0be516..00000000 --- a/hive/scripts/test-mcp.ts +++ /dev/null @@ -1,176 +0,0 @@ -/** - * MCP Server Test Script - * - * Tests the MCP server by connecting via HTTP/SSE and invoking tools. - * - * Usage: - * npx ts-node scripts/test-mcp.ts - * - * Environment: - * ADEN_API_URL - Base URL (default: http://localhost:3000) - * ADEN_AUTH_TOKEN - JWT token for authentication - */ - -import { Client } from "@modelcontextprotocol/sdk/client/index.js"; -import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; - -const API_URL = process.env.ADEN_API_URL || "http://localhost:3000"; -const AUTH_TOKEN = process.env.ADEN_AUTH_TOKEN; - -if (!AUTH_TOKEN) { - console.error("Error: ADEN_AUTH_TOKEN environment variable is required"); - console.error("Usage: ADEN_AUTH_TOKEN=your-jwt-token npx ts-node scripts/test-mcp.ts"); - process.exit(1); -} - -async function main() { - console.log("=".repeat(60)); - console.log("MCP Server Test"); - console.log("=".repeat(60)); - console.log(`API URL: ${API_URL}`); - console.log(""); - - // Create MCP client - const client = new Client({ - name: "mcp-test-client", - version: "1.0.0", - }); - - // Create SSE transport with auth headers - const transport = new SSEClientTransport(new URL(`${API_URL}/mcp`), { - requestInit: { - headers: { - Authorization: `Bearer ${AUTH_TOKEN}`, - }, - }, - }); - - try { - // Connect to MCP server - console.log("Connecting to MCP server..."); - await client.connect(transport); - console.log("✓ Connected successfully\n"); - - // List available tools - console.log("Listing available tools..."); - const tools = await client.listTools(); - console.log(`✓ Found ${tools.tools.length} tools:\n`); - - // Group tools by category - const categories: Record = { - budget: [], - agents: [], - analytics: [], - policies: [], - }; - - for (const tool of tools.tools) { - if (tool.name.includes("budget")) { - categories.budget.push(tool.name); - } else if (tool.name.includes("agent")) { - categories.agents.push(tool.name); - } else if ( - tool.name.includes("analytics") || - tool.name.includes("insights") || - tool.name.includes("metrics") || - tool.name.includes("logs") - ) { - categories.analytics.push(tool.name); - } else if (tool.name.includes("polic")) { - categories.policies.push(tool.name); - } - } - - for (const [category, toolNames] of Object.entries(categories)) { - console.log(` ${category.toUpperCase()} (${toolNames.length}):`); - for (const name of toolNames) { - console.log(` - ${name}`); - } - } - console.log(""); - - // Run test scenarios - console.log("=".repeat(60)); - console.log("Running Test Scenarios"); - console.log("=".repeat(60)); - console.log(""); - - // Test 1: Get policy - await runTest(client, "hive_policy_get", { policyId: "default" }, "Get default policy"); - - // Test 2: List agents - await runTest(client, "hive_agents_summary", {}, "Get agent fleet summary"); - - // Test 3: Get insights - await runTest(client, "hive_insights", { days: 7 }, "Get 7-day insights"); - - // Test 4: Get metrics - await runTest(client, "hive_metrics", { days: 30 }, "Get 30-day metrics"); - - // Test 5: Budget validation (dry run) - await runTest( - client, - "hive_budget_validate", - { - estimatedCost: 0.01, - context: { agent: "test-agent" }, - }, - "Validate budget (dry run)" - ); - - console.log("=".repeat(60)); - console.log("All tests completed!"); - console.log("=".repeat(60)); - } catch (error) { - console.error("Error:", error); - process.exit(1); - } finally { - await client.close(); - } -} - -async function runTest( - client: Client, - toolName: string, - args: Record, - description: string -) { - console.log(`Test: ${description}`); - console.log(` Tool: ${toolName}`); - console.log(` Args: ${JSON.stringify(args)}`); - - try { - const startTime = Date.now(); - const result = await client.callTool({ name: toolName, arguments: args }); - const duration = Date.now() - startTime; - - console.log(` Status: ✓ Success (${duration}ms)`); - - // Parse and display result - if (result.content && result.content.length > 0) { - const textContent = result.content.find((c) => c.type === "text"); - if (textContent && "text" in textContent) { - try { - const parsed = JSON.parse(textContent.text); - console.log(` Result: ${JSON.stringify(parsed, null, 2).split("\n").slice(0, 10).join("\n")}`); - if (JSON.stringify(parsed, null, 2).split("\n").length > 10) { - console.log(" ... (truncated)"); - } - } catch { - console.log(` Result: ${textContent.text.slice(0, 200)}...`); - } - } - } - - if (result.isError) { - console.log(` Warning: Tool returned isError=true`); - } - } catch (error) { - console.log(` Status: ✗ Failed`); - console.log(` Error: ${error instanceof Error ? error.message : error}`); - } - - console.log(""); -} - -main().catch(console.error); diff --git a/hive/src/app.ts b/hive/src/app.ts deleted file mode 100644 index 197dc493..00000000 --- a/hive/src/app.ts +++ /dev/null @@ -1,150 +0,0 @@ -/** - * Express App Configuration - * - * Sets up Express with middleware and routes. - * No global state - uses dependency injection. - * Supports both MySQL (production) and PostgreSQL (local development) for user auth. - */ - -import express, { Request, Response } from 'express'; -import compression from 'compression'; -import cors from 'cors'; -import passport from 'passport'; -import { Pool } from 'pg'; - -import { auth, database, models } from '@acho-inc/administration'; -import config from './config'; -import routes from './routes'; -import { errorHandler } from './middleware/error-handler.middleware'; -import { createMcpRouter } from './mcp'; - -// Initialize Express app -const app = express(); - -// ============================================================================= -// Middleware -// ============================================================================= - -app.use(compression({ - filter: (req, res) => { - // Don't compress SSE responses - compression breaks streaming - if (req.headers.accept === 'text/event-stream' || - req.path.endsWith('/stream')) { - return false; - } - return compression.filter(req, res); - } -})); -app.use(cors()); - -// Skip body parsing for MCP message route (SDK's handlePostMessage reads raw body stream) -app.use((req, res, next) => { - if (req.path === '/mcp/message') { - return next(); - } - express.json({ limit: '10mb' })(req, res, next); -}); -app.use((req, res, next) => { - if (req.path === '/mcp/message') { - return next(); - } - express.urlencoded({ extended: true })(req, res, next); -}); - -// Disable x-powered-by header -app.disable('x-powered-by'); - -// ============================================================================= -// Database Connections -// ============================================================================= - -let userDbService: ReturnType; - -if (config.userDbType === 'postgres') { - // PostgreSQL for local development - console.log('[App] Using PostgreSQL for user authentication'); - - const pgPool = new Pool({ - connectionString: config.userDb.url, - }); - - userDbService = models.createUserDbService({ - pgPool, - dbType: 'postgres', - tables: { - USER: 'users', - DEVELOPERS: 'developers', - }, - }); - - app.locals.pgPool = pgPool; -} else { - // MySQL for production - console.log('[App] Using MySQL for user authentication'); - - const mysqlPool = database.createMySQLPool(config.mysql); - - userDbService = models.createUserDbService({ - mysqlPool, - tables: { - USER: 'user', - DEVELOPERS: 'developers', - }, - }); - - app.locals.mysqlPool = mysqlPool; -} - -// Store user service in app.locals for access in routes -app.locals.userDbService = userDbService; - -// ============================================================================= -// Passport Authentication -// ============================================================================= - -const passportStrategy = auth.createPassportStrategy({ - findSaltByToken: userDbService.findSaltByToken, - jwtSecret: config.jwt.secret, -}); - -passport.use(passportStrategy); -app.use(passport.initialize()); - -// ============================================================================= -// Routes -// ============================================================================= - -// Health check (unauthenticated) -app.get('/health', (req: Request, res: Response) => { - res.json({ - status: 'ok', - service: 'aden-hive', - timestamp: new Date().toISOString(), - userDbType: config.userDbType, - }); -}); - -// API routes -app.use('/', routes); - -// MCP Server routes (Model Context Protocol) -// The controlEmitter is set in index.ts after WebSocket initialization -const mcpRouter = createMcpRouter(() => app.locals.controlEmitter); -app.use('/mcp', mcpRouter); - -// ============================================================================= -// Error Handling -// ============================================================================= - -// 404 handler -app.use((req: Request, res: Response) => { - res.status(404).json({ - error: 'not_found', - message: `Route ${req.method} ${req.path} not found`, - }); -}); - -// Global error handler -app.use(errorHandler); - -export default app; diff --git a/hive/src/config/index.ts b/hive/src/config/index.ts deleted file mode 100644 index 5568d1d7..00000000 --- a/hive/src/config/index.ts +++ /dev/null @@ -1,134 +0,0 @@ -/** - * Configuration Module - * - * Centralizes all configuration loading and validation. - * Supports both MySQL (production) and PostgreSQL (local development) for user database. - */ - -import fs from 'fs'; - -/** - * Helper function to safely read SSL certificates - * @param {string} envKey - Environment variable containing cert path - * @param {string} fallbackPath - Fallback path if env var not set - * @returns {Buffer|null} Certificate content or null - */ -function readCertificate(envKey: string, fallbackPath: string): Buffer | null { - const certPath = process.env[envKey]; - if (certPath && fs.existsSync(certPath)) { - return fs.readFileSync(certPath); - } - if (fallbackPath && fs.existsSync(fallbackPath)) { - return fs.readFileSync(fallbackPath); - } - return null; -} - -/** - * Load MySQL SSL certificates from environment or default paths - * @returns {Object|null} SSL config object or null if certs not found - */ -function loadMySQLSSL(): { ca: Buffer; key: Buffer; cert: Buffer } | null { - const ca = readCertificate('MYSQL_SSL_CA', '/mnt/certs/mysql/server-ca.pem'); - const key = readCertificate('MYSQL_SSL_KEY', '/mnt/certs/mysql/client-key.pem'); - const cert = readCertificate('MYSQL_SSL_CERT', '/mnt/certs/mysql/client-cert.pem'); - - return ca && key && cert ? { ca, key, cert } : null; -} - -/** - * Determine which database type to use for user authentication - * Priority: USER_DB_TYPE env var > MySQL if configured > PostgreSQL fallback - */ -function getUserDbType(): 'mysql' | 'postgres' { - const explicit = process.env.USER_DB_TYPE?.toLowerCase(); - if (explicit === 'mysql' || explicit === 'postgres') { - return explicit; - } - // Default to MySQL if MySQL host is configured, otherwise use PostgreSQL - return process.env.MYSQL_HOST ? 'mysql' : 'postgres'; -} - -const config = { - // Server - port: parseInt(process.env.PORT as string, 10) || 4000, - nodeEnv: process.env.NODE_ENV || 'development', - - // TSDB PostgreSQL (metrics storage) - tsdb: { - url: process.env.TSDB_PG_URL, - }, - - // User Database Type ('mysql' or 'postgres') - userDbType: getUserDbType(), - - // User Database (MySQL) - for production - mysql: { - host: process.env.MYSQL_HOST, - port: parseInt(process.env.MYSQL_PORT as string, 10) || 3306, - user: process.env.MYSQL_USER, - password: process.env.MYSQL_PASSWORD, - database: process.env.MYSQL_DATABASE, - ssl: loadMySQLSSL(), - }, - - // User Database (PostgreSQL) - for local development - // Defaults to same DB as TSDB if not specified - userDb: { - url: process.env.USER_DB_PG_URL || process.env.TSDB_PG_URL, - }, - - // MongoDB - mongodb: { - url: process.env.MONGODB_URL, - dbName: process.env.MONGODB_DBNAME || 'aden', - erpDbName: process.env.MONGODB_ERP_DBNAME || 'erp', - }, - - // Redis - redis: { - url: process.env.REDIS_URL, - }, - - // JWT - jwt: { - secret: process.env.JWT_SECRET || 'dev-secret-change-in-production', - expiresIn: process.env.JWT_EXPIRES_IN || '7d', - passphrase: process.env.PASSPHRASE, - }, -}; - -/** - * Validates required configuration - * @throws {Error} If required config is missing - */ -function validateConfig(): void { - const required: [string, string | undefined][] = [ - ['TSDB_PG_URL', config.tsdb.url], - ]; - - // Add database-specific requirements - if (config.userDbType === 'mysql') { - required.push( - ['MYSQL_HOST', config.mysql.host], - ['MYSQL_USER', config.mysql.user], - ['MYSQL_DATABASE', config.mysql.database], - ); - } else { - required.push(['USER_DB_PG_URL or TSDB_PG_URL', config.userDb.url]); - } - - const missing = required.filter(([, value]) => !value); - - if (missing.length > 0) { - const names = missing.map(([name]) => name).join(', '); - console.warn(`[Config] Warning: Missing environment variables: ${names}`); - } - - console.log(`[Config] User database type: ${config.userDbType}`); -} - -// Validate on load -validateConfig(); - -export default config; diff --git a/hive/src/controllers/control.controller.ts b/hive/src/controllers/control.controller.ts deleted file mode 100644 index 6c5b85a9..00000000 --- a/hive/src/controllers/control.controller.ts +++ /dev/null @@ -1,1885 +0,0 @@ -/** - * Aden Control Controller - * - * HTTP endpoints for Aden SDK control plane: - * - GET /v1/control/policy - Get current policy - * - POST /v1/control/events - Submit events (batch) - * - POST /v1/control/content - Store large content items - * - GET /v1/control/events - Get events (dashboard) - * - PUT /v1/control/policy - Update policy (dashboard) - */ - -import express, { Request, Response, NextFunction } from "express"; -import createError from "http-errors"; -import passport from "passport"; - -import controlService from "../services/control/control_service"; -import pricingService from "../services/tsdb/pricing_service"; -import * as tsdbService from "../services/tsdb/tsdb_service"; -import { getTeamPool, buildSchemaName } from "../services/tsdb/team_context"; - -const router = express.Router(); - -// Passport is initialized in app.js - -interface UserPayload { - id: string; - current_team_id: string; - [key: string]: unknown; -} - -interface UserContext { - user_id: string; - team_id: string; -} - -interface AuthenticatedRequest extends Request { - user?: UserPayload; -} - -interface BudgetAlert { - threshold: number; - enabled: boolean; -} - -interface BudgetNotifications { - inApp: boolean; - email: boolean; - emailRecipients: string[]; - webhook: boolean; -} - -interface BudgetRule { - id: string; - name: string; - type: string; - tags?: string[]; - limit: number; - spent: number; - limitAction: string; - degradeToModel?: string; - degradeToProvider?: string; - alerts: BudgetAlert[]; - notifications: BudgetNotifications; -} - -interface ValidationContext { - agent?: string; - tenant_id?: string; - customer_id?: string; - feature?: string; - tags?: string[]; -} - -declare const global: { - _ADEN_CONTROL_EMITTER?: { - emitPolicyUpdate: ( - teamId: string, - policyId: string | null, - policy: unknown - ) => void; - }; -}; - -/** - * Extract user context from JWT payload for audit/scoping - * @param req - Express request with req.user from passport - * @returns User context { user_id, team_id } - */ -function getUserContext(req: AuthenticatedRequest): UserContext | null { - if (!req.user) return null; - return { - user_id: req.user.id, - team_id: req.user.current_team_id, - }; -} - -/** - * Get policy ID from request (header or query param) - * Returns null if not specified (will use default policy) - */ -function getPolicyId(req: Request): string | null { - return ( - (req.headers["x-policy-id"] as string) || - (req.query.policy_id as string) || - null - ); -} - -/** - * Resolve policy ID - handles "default" as special value - * Returns null for "default" which tells service to use team's default policy - */ -function resolvePolicyId(policyId: string): string | null { - if (!policyId || policyId === "default") { - return null; - } - return policyId; -} - -// ============================================================================= -// SDK Endpoints (used by Aden SDK) -// ============================================================================= - -/** - * GET /v1/control/policy - * Get the current control policy for the SDK - * Optional X-Policy-ID header to specify policy (uses default if not specified) - */ -router.get( - "/policy", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - const userContext = getUserContext(req); - if (!userContext?.team_id) { - return next(createError(400, "Team context required")); - } - - const policyId = getPolicyId(req); - const policy = await controlService.getPolicy( - userContext.team_id, - policyId - ); - res.json(policy); - } catch (error) { - console.error("[Aden Control] Error getting policy:", error); - next(createError(500, "Failed to get policy")); - } - } -); - -/** - * POST /v1/control/events - * Submit events from the SDK (batch) - * Optional X-Policy-ID header to specify policy (uses default if not specified) - */ -router.post( - "/events", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - const userContext = getUserContext(req); - if (!userContext?.team_id) { - return next(createError(400, "Team context required")); - } - - const { events } = req.body; - - if (!events || !Array.isArray(events)) { - return next(createError(400, "events array required")); - } - - const policyId = getPolicyId(req); - await controlService.processEvents( - userContext.team_id, - policyId, - events, - userContext - ); - - res.json({ success: true, processed: events.length }); - } catch (error) { - console.error("[Aden Control] Error processing events:", error); - next(createError(500, "Failed to process events")); - } - } -); - -/** - * POST /v1/control/content - * Store large content items from the SDK (Layer 0 content capture) - * Used for content that exceeds max_content_bytes threshold - * - * Body: { items: Array<{ content_id, content_hash, content, byte_size }> } - */ -router.post( - "/content", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - console.log("[Aden Control] Received content storage request"); - const userContext = getUserContext(req); - if (!userContext?.team_id) { - return next(createError(400, "Team context required")); - } - - const { items } = req.body; - - if (!items || !Array.isArray(items)) { - return next(createError(400, "items array required")); - } - - // Validate each item has required fields - for (let i = 0; i < items.length; i++) { - const item = items[i]; - if (!item.content_id || typeof item.content_id !== "string") { - return next( - createError(400, `items[${i}].content_id (string) is required`) - ); - } - if (!item.content_hash || typeof item.content_hash !== "string") { - return next( - createError(400, `items[${i}].content_hash (string) is required`) - ); - } - if (item.content === undefined || item.content === null) { - return next(createError(400, `items[${i}].content is required`)); - } - if (typeof item.byte_size !== "number" || item.byte_size < 0) { - return next( - createError( - 400, - `items[${i}].byte_size must be a non-negative number` - ) - ); - } - } - - const result = await controlService.storeContent( - userContext.team_id, - items - ); - - res.json({ success: true, stored: result.stored }); - } catch (error) { - console.error("[Aden Control] Error storing content:", error); - next(createError(500, "Failed to store content")); - } - } -); - -/** - * GET /v1/control/content/:contentId - * Retrieve content by ID - */ -router.get( - "/content/:contentId", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - const userContext = getUserContext(req); - if (!userContext?.team_id) { - return next(createError(400, "Team context required")); - } - - const { contentId } = req.params; - const content = await controlService.getContent( - userContext.team_id, - contentId - ); - - if (!content) { - return next(createError(404, "Content not found")); - } - - res.json(content); - } catch (error) { - console.error("[Aden Control] Error getting content:", error); - next(createError(500, "Failed to get content")); - } - } -); - -// ============================================================================= -// TSDB Content Retrieval Endpoints (warm/cold storage) -// ============================================================================= - -/** - * GET /v1/control/events/:traceId/:callSequence/content - * Get all content for a specific event from warm/cold storage - * Returns content references with full content from cold store - */ -router.get( - "/events/:traceId/:callSequence/content", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - const userContext = getUserContext(req); - if (!userContext?.team_id) { - return next(createError(400, "Team context required")); - } - - const { traceId, callSequence } = req.params; - const callSeq = parseInt(callSequence); - - if (!traceId || isNaN(callSeq)) { - return next(createError(400, "Valid traceId and callSequence required")); - } - - // Get team pool and set schema - const pool = await getTeamPool(userContext.team_id); - const schema = buildSchemaName(userContext.team_id); - const client = await pool.connect(); - - try { - await client.query(`SET search_path TO ${schema}, public`); - await tsdbService.ensureSchema(client); - - const content = await tsdbService.getEventContent( - userContext.team_id, - traceId, - callSeq, - client - ); - - res.json({ - trace_id: traceId, - call_sequence: callSeq, - content_items: content, - count: content.length, - }); - } finally { - client.release(); - } - } catch (error) { - console.error("[Aden Control] Error getting event content:", error); - next(createError(500, "Failed to get event content")); - } - } -); - -/** - * GET /v1/control/content/hash/:contentHash - * Get content from cold storage by hash - * Useful for fetching deduplicated content directly - */ -router.get( - "/content/hash/:contentHash", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - const userContext = getUserContext(req); - if (!userContext?.team_id) { - return next(createError(400, "Team context required")); - } - - const { contentHash } = req.params; - - if (!contentHash || contentHash.length !== 64) { - return next(createError(400, "Valid SHA-256 content hash required")); - } - - // Get team pool and set schema - const pool = await getTeamPool(userContext.team_id); - const schema = buildSchemaName(userContext.team_id); - const client = await pool.connect(); - - try { - await client.query(`SET search_path TO ${schema}, public`); - await tsdbService.ensureSchema(client); - - const content = await tsdbService.getContentByHash( - userContext.team_id, - contentHash, - client - ); - - if (!content) { - return next(createError(404, "Content not found")); - } - - res.json({ - content_hash: contentHash, - content, - byte_size: Buffer.byteLength(content, "utf8"), - }); - } finally { - client.release(); - } - } catch (error) { - console.error("[Aden Control] Error getting content by hash:", error); - next(createError(500, "Failed to get content")); - } - } -); - -// ============================================================================= -// Dashboard Endpoints (used by Aden Dashboard) -// ============================================================================= - -/** - * GET /v1/control/events - * Get events for the dashboard (queries TSDB) - * Query params: limit, offset, start_date, end_date, policy_id - */ -router.get( - "/events", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - const { limit, offset, start_date, end_date, policy_id } = req.query; - const userContext = getUserContext(req); - - if (!userContext?.team_id) { - return next(createError(400, "Team context required")); - } - - const events = await controlService.getEvents( - userContext.team_id, - (policy_id as string) || null, - { - limit: parseInt(limit as string) || 100, - offset: parseInt(offset as string) || 0, - start_date: start_date as string | undefined, - end_date: end_date as string | undefined, - } - ); - - res.json({ events, count: events.length }); - } catch (error) { - console.error("[Aden Control] Error getting events:", error); - next(createError(500, "Failed to get events")); - } - } -); - -/** - * PUT /v1/control/policies/:policyId - * Update the control policy (from dashboard) - * Use "default" as policyId to update the team's default policy - */ -router.put( - "/policies/:policyId", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - const policyId = resolvePolicyId(req.params.policyId); - const policyUpdate = req.body; - const userContext = getUserContext(req); - - if (!userContext?.team_id) { - return next(createError(400, "Team context required")); - } - - // Validate policy structure - const validKeys = [ - "name", - "budgets", - "throttles", - "blocks", - "degradations", - "alerts", - ]; - const invalidKeys = Object.keys(policyUpdate).filter( - (k) => !validKeys.includes(k) - ); - if (invalidKeys.length > 0) { - return next( - createError(400, `Invalid policy keys: ${invalidKeys.join(", ")}`) - ); - } - - const policy = await controlService.updatePolicy( - userContext.team_id, - policyId, - policyUpdate, - userContext - ); - - // Notify connected SDK instances via WebSocket - if (global._ADEN_CONTROL_EMITTER) { - global._ADEN_CONTROL_EMITTER.emitPolicyUpdate( - userContext.team_id, - policyId, - policy - ); - } - - res.json(policy); - } catch (error) { - console.error("[Aden Control] Error updating policy:", error); - next(createError(500, "Failed to update policy")); - } - } -); - -/** - * DELETE /v1/control/policies/:policyId/rules - * Clear all rules from the policy (keeps the policy itself) - * Use "default" as policyId to clear the team's default policy - */ -router.delete( - "/policies/:policyId/rules", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - const policyId = resolvePolicyId(req.params.policyId); - const userContext = getUserContext(req); - - if (!userContext?.team_id) { - return next(createError(400, "Team context required")); - } - - const policy = await controlService.clearPolicy( - userContext.team_id, - policyId, - userContext - ); - - // Notify connected SDK instances via WebSocket - if (global._ADEN_CONTROL_EMITTER) { - global._ADEN_CONTROL_EMITTER.emitPolicyUpdate( - userContext.team_id, - policyId, - policy - ); - } - - res.json(policy); - } catch (error) { - console.error("[Aden Control] Error clearing policy:", error); - next(createError(500, "Failed to clear policy")); - } - } -); - -// ============================================================================= -// Rule Management Endpoints -// ============================================================================= - -/** - * Valid budget types matching frontend BudgetType enum - */ -const VALID_BUDGET_TYPES = [ - "global", - "agent", - "tenant", - "customer", - "feature", - "tag", -]; - -/** - * Valid limit actions matching frontend LimitAction enum - */ -const VALID_LIMIT_ACTIONS = ["kill", "throttle", "degrade"]; - -/** - * Validate BudgetAlert structure - */ -function isValidBudgetAlert(alert: unknown): alert is BudgetAlert { - return ( - alert !== null && - typeof alert === "object" && - typeof (alert as BudgetAlert).threshold === "number" && - (alert as BudgetAlert).threshold >= 0 && - (alert as BudgetAlert).threshold <= 100 && - typeof (alert as BudgetAlert).enabled === "boolean" - ); -} - -/** - * Validate BudgetNotifications structure - */ -function isValidBudgetNotifications( - notifications: unknown -): notifications is BudgetNotifications { - if (!notifications || typeof notifications !== "object") return false; - const n = notifications as BudgetNotifications; - if (typeof n.inApp !== "boolean") return false; - if (typeof n.email !== "boolean") return false; - if (!Array.isArray(n.emailRecipients)) return false; - if (typeof n.webhook !== "boolean") return false; - return true; -} - -/** - * POST /v1/control/policies/:policyId/budgets - * Add a budget rule - * - * Expected body (BudgetConfig): - * { - * id: string, - * name: string, - * type: 'global' | 'agent' | 'tenant' | 'customer' | 'feature' | 'tag', - * tagCategory?: string, - * limit: number, - * spent: number, - * limitAction: 'kill' | 'throttle' | 'degrade', - * degradeToModel?: string, // required when limitAction is 'degrade' - * degradeToProvider?: string, // required when limitAction is 'degrade' - * alerts: Array<{ threshold: number, enabled: boolean }>, - * notifications: { inApp: boolean, email: boolean, emailRecipients: string[], webhook: boolean } - * } - */ -router.post( - "/policies/:policyId/budgets", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - const policyId = resolvePolicyId(req.params.policyId); - const rule = req.body as BudgetRule; - const userContext = getUserContext(req); - - if (!userContext?.team_id) { - return next(createError(400, "Team context required")); - } - - // Validate required fields - if (!rule.id || typeof rule.id !== "string") { - return next(createError(400, "id (string) is required")); - } - - if (!rule.name || typeof rule.name !== "string") { - return next(createError(400, "name (string) is required")); - } - - if (!rule.type || !VALID_BUDGET_TYPES.includes(rule.type)) { - return next( - createError( - 400, - `type must be one of: ${VALID_BUDGET_TYPES.join(", ")}` - ) - ); - } - - // tags array is required when type is 'tag' - if (rule.type === "tag") { - if (!Array.isArray(rule.tags) || rule.tags.length === 0) { - return next( - createError( - 400, - "tags (non-empty array) is required when type is 'tag'" - ) - ); - } - // Validate each tag is a string - for (let i = 0; i < rule.tags.length; i++) { - if (typeof rule.tags[i] !== "string") { - return next(createError(400, `tags[${i}] must be a string`)); - } - } - } - - if (typeof rule.limit !== "number" || rule.limit < 0) { - return next(createError(400, "limit must be a non-negative number")); - } - - if (typeof rule.spent !== "number" || rule.spent < 0) { - return next(createError(400, "spent must be a non-negative number")); - } - - if ( - !rule.limitAction || - !VALID_LIMIT_ACTIONS.includes(rule.limitAction) - ) { - return next( - createError( - 400, - `limitAction must be one of: ${VALID_LIMIT_ACTIONS.join(", ")}` - ) - ); - } - - // degradeToModel and degradeToProvider are required when limitAction is 'degrade' - if (rule.limitAction === "degrade") { - if (!rule.degradeToModel || typeof rule.degradeToModel !== "string") { - return next( - createError( - 400, - "degradeToModel is required when limitAction is 'degrade'" - ) - ); - } - if ( - !rule.degradeToProvider || - typeof rule.degradeToProvider !== "string" - ) { - return next( - createError( - 400, - "degradeToProvider is required when limitAction is 'degrade'" - ) - ); - } - - // Validate model belongs to the specified provider - const targets = await pricingService.getDegradationTargets(); - const providerModels = targets.models[rule.degradeToProvider]; - - if (!providerModels) { - return next( - createError(400, `Unknown provider: ${rule.degradeToProvider}`) - ); - } - - const validModelNames = providerModels.map( - (m: { model: string }) => m.model - ); - if (!validModelNames.includes(rule.degradeToModel)) { - return next( - createError( - 400, - `degradeToModel "${rule.degradeToModel}" does not belong to provider "${rule.degradeToProvider}"` - ) - ); - } - } - - if (!Array.isArray(rule.alerts)) { - return next(createError(400, "alerts must be an array")); - } - for (let i = 0; i < rule.alerts.length; i++) { - if (!isValidBudgetAlert(rule.alerts[i])) { - return next( - createError( - 400, - `alerts[${i}] must have threshold (0-100) and enabled (boolean)` - ) - ); - } - } - - if (!isValidBudgetNotifications(rule.notifications)) { - return next( - createError( - 400, - "notifications must have inApp, email, emailRecipients[], and webhook fields" - ) - ); - } - - const policy = await controlService.addBudgetRule( - userContext.team_id, - policyId, - rule, - userContext - ); - - if (global._ADEN_CONTROL_EMITTER) { - global._ADEN_CONTROL_EMITTER.emitPolicyUpdate( - userContext.team_id, - policyId, - policy - ); - } - - res.json(policy); - } catch (error) { - console.error("[Aden Control] Error adding budget rule:", error); - next(createError(500, "Failed to add budget rule")); - } - } -); - -/** - * POST /v1/control/policies/:policyId/throttles - * Add a throttle rule - */ -router.post( - "/policies/:policyId/throttles", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - const policyId = resolvePolicyId(req.params.policyId); - const rule = req.body; - const userContext = getUserContext(req); - - if (!userContext?.team_id) { - return next(createError(400, "Team context required")); - } - - if (!rule.requests_per_minute && !rule.delay_ms) { - return next( - createError(400, "requests_per_minute or delay_ms required") - ); - } - - const policy = await controlService.addThrottleRule( - userContext.team_id, - policyId, - rule, - userContext - ); - - if (global._ADEN_CONTROL_EMITTER) { - global._ADEN_CONTROL_EMITTER.emitPolicyUpdate( - userContext.team_id, - policyId, - policy - ); - } - - res.json(policy); - } catch (error) { - console.error("[Aden Control] Error adding throttle rule:", error); - next(createError(500, "Failed to add throttle rule")); - } - } -); - -/** - * POST /v1/control/policies/:policyId/blocks - * Add a block rule - */ -router.post( - "/policies/:policyId/blocks", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - const policyId = resolvePolicyId(req.params.policyId); - const rule = req.body; - const userContext = getUserContext(req); - - if (!userContext?.team_id) { - return next(createError(400, "Team context required")); - } - - if (!rule.reason) { - return next(createError(400, "reason required")); - } - - const policy = await controlService.addBlockRule( - userContext.team_id, - policyId, - rule, - userContext - ); - - if (global._ADEN_CONTROL_EMITTER) { - global._ADEN_CONTROL_EMITTER.emitPolicyUpdate( - userContext.team_id, - policyId, - policy - ); - } - - res.json(policy); - } catch (error) { - console.error("[Aden Control] Error adding block rule:", error); - next(createError(500, "Failed to add block rule")); - } - } -); - -/** - * POST /v1/control/policies/:policyId/degradations - * Add a degradation rule (within same provider only - no cross-vendor degradation) - * - * Body: - * { - * provider: string, // e.g., "openai", "anthropic" - * from_model: string, // Model to degrade from, e.g., "gpt-4o" - * to_model: string, // Model to degrade to, e.g., "gpt-4o-mini" - * trigger: string // When to trigger: "budget_exceeded", "rate_limit", etc. - * } - */ -router.post( - "/policies/:policyId/degradations", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - const policyId = resolvePolicyId(req.params.policyId); - const rule = req.body; - const userContext = getUserContext(req); - - if (!userContext?.team_id) { - return next(createError(400, "Team context required")); - } - - if (!rule.provider || typeof rule.provider !== "string") { - return next(createError(400, "provider (string) is required")); - } - - if (!rule.from_model || typeof rule.from_model !== "string") { - return next(createError(400, "from_model (string) is required")); - } - - if (!rule.to_model || typeof rule.to_model !== "string") { - return next(createError(400, "to_model (string) is required")); - } - - if (!rule.trigger || typeof rule.trigger !== "string") { - return next(createError(400, "trigger (string) is required")); - } - - // Validate models belong to the specified provider - const targets = await pricingService.getDegradationTargets(); - const providerModels = targets.models[rule.provider]; - - if (!providerModels) { - return next(createError(400, `Unknown provider: ${rule.provider}`)); - } - - const validModelNames = providerModels.map( - (m: { model: string }) => m.model - ); - - if (!validModelNames.includes(rule.from_model)) { - return next( - createError( - 400, - `from_model "${rule.from_model}" does not belong to provider "${rule.provider}"` - ) - ); - } - - if (!validModelNames.includes(rule.to_model)) { - return next( - createError( - 400, - `to_model "${rule.to_model}" does not belong to provider "${rule.provider}"` - ) - ); - } - - const policy = await controlService.addDegradeRule( - userContext.team_id, - policyId, - rule, - userContext - ); - - if (global._ADEN_CONTROL_EMITTER) { - global._ADEN_CONTROL_EMITTER.emitPolicyUpdate( - userContext.team_id, - policyId, - policy - ); - } - - res.json(policy); - } catch (error) { - console.error("[Aden Control] Error adding degradation rule:", error); - next(createError(500, "Failed to add degradation rule")); - } - } -); - -/** - * POST /v1/control/policies/:policyId/alerts - * Add an alert rule - */ -router.post( - "/policies/:policyId/alerts", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - const policyId = resolvePolicyId(req.params.policyId); - const rule = req.body; - const userContext = getUserContext(req); - - if (!userContext?.team_id) { - return next(createError(400, "Team context required")); - } - - if (!rule.trigger || !rule.level || !rule.message) { - return next(createError(400, "trigger, level, and message required")); - } - - // Validate level - if (!["info", "warning", "critical"].includes(rule.level)) { - return next( - createError(400, "level must be one of: info, warning, critical") - ); - } - - // Validate trigger - if ( - !["budget_threshold", "model_usage", "always"].includes(rule.trigger) - ) { - return next( - createError( - 400, - "trigger must be one of: budget_threshold, model_usage, always" - ) - ); - } - - const policy = await controlService.addAlertRule( - userContext.team_id, - policyId, - rule, - userContext - ); - - if (global._ADEN_CONTROL_EMITTER) { - global._ADEN_CONTROL_EMITTER.emitPolicyUpdate( - userContext.team_id, - policyId, - policy - ); - } - - res.json(policy); - } catch (error) { - console.error("[Aden Control] Error adding alert rule:", error); - next(createError(500, "Failed to add alert rule")); - } - } -); - -// ============================================================================= -// Budget Management Endpoints -// ============================================================================= - -/** - * GET /v1/control/budget/:budgetId - * Get budget status for a budget ID - */ -router.get( - "/budget/:budgetId", - passport.authenticate("jwt", { session: false }), - async (req: Request, res: Response, next: NextFunction) => { - try { - const { budgetId } = req.params; - const status = await controlService.getBudgetStatus(budgetId); - res.json(status); - } catch (error) { - console.error("[Aden Control] Error getting budget status:", error); - next(createError(500, "Failed to get budget status")); - } - } -); - -/** - * POST /v1/control/budget/:budgetId/reset - * Reset budget for a budget ID - */ -router.post( - "/budget/:budgetId/reset", - passport.authenticate("jwt", { session: false }), - async (req: Request, res: Response, next: NextFunction) => { - try { - const { budgetId } = req.params; - await controlService.resetBudget(budgetId); - res.json({ success: true, id: budgetId }); - } catch (error) { - console.error("[Aden Control] Error resetting budget:", error); - next(createError(500, "Failed to reset budget")); - } - } -); - -// ============================================================================= -// Team Policies & Metrics Endpoints -// ============================================================================= - -/** - * GET /v1/control/policies - * Get all policies for the current team (dashboard) - */ -router.get( - "/policies", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - const userContext = getUserContext(req); - if (!userContext?.team_id) { - return next(createError(400, "Team context required")); - } - - const { limit, offset } = req.query; - const policies = await controlService.getPoliciesByTeam( - userContext.team_id, - { - limit: parseInt(limit as string) || 100, - offset: parseInt(offset as string) || 0, - } - ); - - res.json({ policies, count: policies.length }); - } catch (error) { - console.error("[Aden Control] Error getting team policies:", error); - next(createError(500, "Failed to get team policies")); - } - } -); - -/** - * POST /v1/control/policies - * Create a new policy for the team - */ -router.post( - "/policies", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - const userContext = getUserContext(req); - if (!userContext?.team_id) { - return next(createError(400, "Team context required")); - } - - const { name } = req.body; - if (!name || typeof name !== "string") { - return next(createError(400, "name (string) is required")); - } - - // Create a new policy with the given name - const policy = await controlService.updatePolicy( - userContext.team_id, - null, // Will generate a new policy ID - { name }, - userContext - ); - - res.status(201).json(policy); - } catch (error) { - console.error("[Aden Control] Error creating policy:", error); - next(createError(500, "Failed to create policy")); - } - } -); - -/** - * GET /v1/control/policies/:policyId - * Get a specific policy by ID - * Use "default" as policyId to get the team's default policy - */ -router.get( - "/policies/:policyId", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - const policyId = resolvePolicyId(req.params.policyId); - const userContext = getUserContext(req); - - if (!userContext?.team_id) { - return next(createError(400, "Team context required")); - } - - const policy = await controlService.getPolicy( - userContext.team_id, - policyId, - userContext - ); - - if (!policy) { - return next(createError(404, "Policy not found")); - } - - res.json(policy); - } catch (error) { - console.error("[Aden Control] Error getting policy:", error); - next(createError(500, "Failed to get policy")); - } - } -); - -/** - * DELETE /v1/control/policies/:policyId - * Delete a policy - * Note: "default" is NOT allowed here - must specify actual policy ID - */ -router.delete( - "/policies/:policyId", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - const { policyId } = req.params; - - // Don't allow deleting "default" - must specify actual policy ID - if (policyId === "default") { - return next( - createError(400, "Cannot delete 'default' - specify actual policy ID") - ); - } - - const userContext = getUserContext(req); - - if (!userContext?.team_id) { - return next(createError(400, "Team context required")); - } - - await controlService.deletePolicy( - userContext.team_id, - policyId, - userContext - ); - - res.json({ success: true, id: policyId }); - } catch (error) { - console.error("[Aden Control] Error deleting policy:", error); - next(createError(500, "Failed to delete policy")); - } - } -); - -/** - * GET /v1/control/metrics - * Get metrics summary for the current team (dashboard analytics) - */ -router.get( - "/metrics", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - const userContext = getUserContext(req); - if (!userContext?.team_id) { - return next(createError(400, "Team context required")); - } - - const { start_date, end_date } = req.query; - const summary = await controlService.getMetricsSummary( - userContext.team_id, - { - start_date: start_date as string | undefined, - end_date: end_date as string | undefined, - } - ); - - res.json(summary); - } catch (error) { - console.error("[Aden Control] Error getting metrics summary:", error); - next(createError(500, "Failed to get metrics summary")); - } - } -); - -// ============================================================================= -// Usage & Rate Analytics Endpoints -// ============================================================================= - -/** - * GET /v1/control/metrics/usage - * Get usage breakdown (daily, by model, by feature) - */ -router.get( - "/metrics/usage", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - const userContext = getUserContext(req); - if (!userContext?.team_id) { - return next(createError(400, "Team context required")); - } - - const { days, context_id } = req.query; - const breakdown = await controlService.getUsageBreakdown( - userContext.team_id, - { - days: days ? parseInt(days as string) : 7, - context_id: context_id as string | undefined, - } - ); - - res.json(breakdown); - } catch (error) { - console.error("[Aden Control] Error getting usage breakdown:", error); - next(createError(500, "Failed to get usage breakdown")); - } - } -); - -/** - * GET /v1/control/metrics/rates - * Get rate metrics (peak, p95, avg, min, burst) - */ -router.get( - "/metrics/rates", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - const userContext = getUserContext(req); - if (!userContext?.team_id) { - return next(createError(400, "Team context required")); - } - - const { days, context_id } = req.query; - const rates = await controlService.getRateMetrics(userContext.team_id, { - days: days ? parseInt(days as string) : 30, - context_id: context_id as string | undefined, - }); - - res.json(rates); - } catch (error) { - console.error("[Aden Control] Error getting rate metrics:", error); - next(createError(500, "Failed to get rate metrics")); - } - } -); - -/** - * GET /v1/control/policies/:policyId/budgets/:budgetId - * Get detailed budget info including usage stats - */ -router.get( - "/policies/:policyId/budgets/:budgetId", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - const policyId = resolvePolicyId(req.params.policyId); - const { budgetId } = req.params; - const userContext = getUserContext(req); - - if (!userContext?.team_id) { - return next(createError(400, "Team context required")); - } - - const budget = await controlService.getBudgetDetails( - userContext.team_id, - policyId, - budgetId - ); - - if (!budget) { - return next(createError(404, "Budget not found")); - } - - res.json(budget); - } catch (error) { - console.error("[Aden Control] Error getting budget details:", error); - next(createError(500, "Failed to get budget details")); - } - } -); - -/** - * GET /v1/control/policies/:policyId/budgets/:budgetId/usage - * Get usage breakdown for a specific budget - * Returns: { daily, by_model, by_feature } - */ -router.get( - "/policies/:policyId/budgets/:budgetId/usage", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - const policyId = resolvePolicyId(req.params.policyId); - const { budgetId } = req.params; - const { days } = req.query; - const userContext = getUserContext(req); - - if (!userContext?.team_id) { - return next(createError(400, "Team context required")); - } - - // Get budget details for filtering - const budget = await controlService.getBudgetDetails( - userContext.team_id, - policyId, - budgetId - ); - - if (!budget) { - return next(createError(404, "Budget not found")); - } - - // Pass the budget object for type-aware filtering - const breakdown = await controlService.getUsageBreakdown( - userContext.team_id, - { - days: days ? parseInt(days as string) : 7, - budget, - } - ); - - res.json(breakdown); - } catch (error) { - console.error("[Aden Control] Error getting budget usage:", error); - next(createError(500, "Failed to get budget usage")); - } - } -); - -/** - * GET /v1/control/policies/:policyId/budgets/:budgetId/rates - * Get rate metrics for a specific budget - * Returns: { peak_rate, p95_rate, avg_rate, min_rate, max_burst } - */ -router.get( - "/policies/:policyId/budgets/:budgetId/rates", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - const policyId = resolvePolicyId(req.params.policyId); - const { budgetId } = req.params; - const { days } = req.query; - const userContext = getUserContext(req); - - if (!userContext?.team_id) { - return next(createError(400, "Team context required")); - } - - // Get budget details for filtering - const budget = await controlService.getBudgetDetails( - userContext.team_id, - policyId, - budgetId - ); - - if (!budget) { - return next(createError(404, "Budget not found")); - } - - // Pass the budget object for type-aware filtering - const rates = await controlService.getRateMetrics(userContext.team_id, { - days: days ? parseInt(days as string) : 30, - budget, - }); - - res.json(rates); - } catch (error) { - console.error("[Aden Control] Error getting budget rates:", error); - next(createError(500, "Failed to get budget rates")); - } - } -); - -// ============================================================================= -// Budget Validation Endpoint (for Hybrid Enforcement) -// ============================================================================= - -/** - * POST /v1/control/budget/validate - * Server-side budget validation for hybrid enforcement. - * - * Called by SDK when local budget usage approaches threshold (e.g., 80%). - * Returns authoritative spend from TSDB and enforcement decision. - */ -router.post( - "/budget/validate", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - const userContext = getUserContext(req); - if (!userContext?.team_id) { - return next(createError(400, "Team context required")); - } - - const { budget_id, estimated_cost, context, local_spend } = req.body as { - budget_id?: string; - estimated_cost: number; - context?: ValidationContext; - local_spend?: number; - }; - const policyId = getPolicyId(req); - - if (typeof estimated_cost !== "number" || estimated_cost < 0) { - return next( - createError(400, "estimated_cost must be a non-negative number") - ); - } - - // Get the policy with authoritative budget data from TSDB - const policy = await controlService.getPolicy( - userContext.team_id, - policyId, - userContext - ); - - if (!policy) { - return next(createError(404, "Policy not found")); - } - - // MULTI-BUDGET MODE: Use context to find all matching budgets - if (context && typeof context === "object") { - const matchingBudgets = controlService.findMatchingBudgetsForContext( - policy.budgets || [], - context - ); - - if (matchingBudgets.length === 0) { - // No budgets match this context - allow by default - return res.json({ - allowed: true, - action: "allow", - reason: "No budgets match the provided context", - authoritative_spend: 0, - budget_limit: 0, - usage_percent: 0, - projected_percent: 0, - policy_version: policy.version, - budgets_checked: [], - }); - } - - // Validate all matching budgets and get most restrictive result - const result = controlService.validateMultipleBudgets( - matchingBudgets, - estimated_cost, - local_spend - ); - - // Log the validation for audit - console.log( - `[Aden Control] Multi-budget validation: ` + - `checked ${result.budgets_checked.length} budgets, ` + - `action: ${result.action}` + - (result.restricting_budget_name - ? `, restricting: ${result.restricting_budget_name}` - : "") - ); - - return res.json({ - ...result, - policy_version: policy.version, - }); - } - - // SINGLE-BUDGET MODE (backward compatible): Use budget_id - if (!budget_id) { - return next(createError(400, "budget_id or context is required")); - } - - // Find the budget by ID - const budget = policy.budgets?.find( - (b: { id: string }) => b.id === budget_id - ); - if (!budget) { - // Budget not found - allow by default (budget may have been removed) - return res.json({ - allowed: true, - action: "allow", - reason: "Budget not found in policy", - authoritative_spend: 0, - budget_limit: 0, - usage_percent: 0, - projected_percent: 0, - policy_version: policy.version, - budgets_checked: [], - }); - } - - // Use the multi-budget validator for consistency (with single budget) - const result = controlService.validateMultipleBudgets( - [budget], - estimated_cost, - local_spend - ); - - // Log the validation for audit - console.log( - `[Aden Control] Budget validation: ${budget_id} - ` + - `spend: $${result.authoritative_spend.toFixed(4)}, ` + - `limit: $${budget.limit}, ` + - `action: ${result.action}` - ); - - res.json({ - ...result, - policy_version: policy.version, - // Keep backward-compatible fields - updated_spend: result.authoritative_spend, - }); - } catch (error) { - console.error("[Aden Control] Error validating budget:", error); - next(createError(500, "Failed to validate budget")); - } - } -); - -// ============================================================================= -// Model Options for Degradation -// ============================================================================= - -/** - * GET /v1/control/degradation-targets - * Get available target models for budget degradation mode, grouped by provider - * Models are sorted by cost (cheapest first) - * - * Query params: - * provider (optional) - Filter to specific provider (e.g., "openai", "anthropic") - * - * Response (no filter): - * { providers: [...], models: { openai: [...], anthropic: [...] } } - * - * Response (with provider filter): - * { provider: "openai", models: [...] } - */ -router.get( - "/degradation-targets", - passport.authenticate("jwt", { session: false }), - async (req: Request, res: Response, next: NextFunction) => { - try { - const { provider } = req.query; - const targets = await pricingService.getDegradationTargets(); - - // If provider specified, filter to that provider only - if (provider) { - const providerModels = targets.models[provider as string]; - if (!providerModels) { - return next(createError(400, `Unknown provider: ${provider}`)); - } - return res.json({ - provider, - models: providerModels, - }); - } - - res.json(targets); - } catch (error) { - console.error("[Aden Control] Error getting degradation targets:", error); - next(createError(500, "Failed to get degradation targets")); - } - } -); - -// ============================================================================= -// SSE - Real-time Agent Status Stream -// ============================================================================= - -interface ControlEmitter { - getConnectedCount: (teamId: string | number) => number; - getConnectedInstances: (teamId: string | number) => Array<{ - instance_id: string; - policy_id: string | null; - agent_name: string | null; - connected_at: string; - last_heartbeat: string; - connection_type: "websocket" | "http"; - status?: string; - }>; - getTotalConnectedCount: () => number; -} - -/** - * GET /v1/control/agent-status/stream - * SSE endpoint for real-time agent connection status - * - * Streams updates every 2 seconds with: - * - active: boolean indicating if any agents are connected - * - count: number of connected agents - * - instances: array of connected agent details - */ -router.get( - "/agent-status/stream", - passport.authenticate("jwt", { session: false }), - (req: AuthenticatedRequest, res: Response) => { - const teamId = req.user?.current_team_id; - - if (!teamId) { - res.status(401).json({ error: "Team ID required" }); - return; - } - - // Set SSE headers - res.setHeader("Content-Type", "text/event-stream"); - res.setHeader("Cache-Control", "no-cache"); - res.setHeader("Connection", "keep-alive"); - res.setHeader("X-Accel-Buffering", "no"); // Disable nginx buffering - res.flushHeaders(); - - const controlEmitter = req.app.locals.controlEmitter as - | ControlEmitter - | undefined; - - // Send initial status immediately - const sendStatus = () => { - if (!controlEmitter) { - const data = { - active: false, - count: 0, - instances: [], - timestamp: new Date().toISOString(), - error: "WebSocket not initialized", - }; - res.write(`data: ${JSON.stringify(data)}\n\n`); - return; - } - - const count = controlEmitter.getConnectedCount(teamId); - const instances = controlEmitter.getConnectedInstances(teamId); - - const data = { - active: count > 0, - count, - instances, - timestamp: new Date().toISOString(), - }; - - res.write(`data: ${JSON.stringify(data)}\n\n`); - }; - - // Send immediately - sendStatus(); - - // Send updates every 2 seconds - const intervalId = setInterval(sendStatus, 2000); - - // Cleanup on client disconnect - req.on("close", () => { - clearInterval(intervalId); - }); - } -); - -/** - * GET /v1/control/agent-status - * Get current agent connection status (non-streaming) - */ -router.get( - "/agent-status", - passport.authenticate("jwt", { session: false }), - (req: AuthenticatedRequest, res: Response) => { - const teamId = req.user?.current_team_id; - - if (!teamId) { - res.status(401).json({ error: "Team ID required" }); - return; - } - - const controlEmitter = req.app.locals.controlEmitter as - | ControlEmitter - | undefined; - - if (!controlEmitter) { - res.json({ - active: false, - count: 0, - instances: [], - timestamp: new Date().toISOString(), - error: "WebSocket not initialized", - }); - return; - } - - const count = controlEmitter.getConnectedCount(teamId); - const instances = controlEmitter.getConnectedInstances(teamId); - - res.json({ - active: count > 0, - count, - instances, - timestamp: new Date().toISOString(), - }); - } -); - -// ============================================================================= -// Agent Discovery - Historical agents with availability -// ============================================================================= - -/** - * GET /v1/control/agents - * Get all agents from past events with their current availability status - * - * Query params: - * - since: ISO date string to filter events from (optional) - * - limit: Max number of agents to return (default: 100) - * - * Returns agents sorted by last_seen descending with: - * - agent: unique agent identifier - * - agent_name: human-readable name (if available) - * - status: "connected" | "disconnected" - * - connection_type: "websocket" | "http" | null (null if disconnected) - * - first_seen: when agent first appeared in events - * - last_seen: when agent last appeared in events - * - total_requests: total LLM requests made by this agent - * - total_cost: total cost incurred by this agent - */ -router.get( - "/agents", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - const teamId = req.user?.current_team_id; - if (!teamId) { - throw createError(401, "Team ID required"); - } - - // Parse query params - const since = req.query.since ? new Date(req.query.since as string) : undefined; - const limit = req.query.limit ? parseInt(req.query.limit as string, 10) : 100; - - // Get team-specific pool/schema - const teamPool = await getTeamPool(teamId); - const schemaName = buildSchemaName(teamId); - const client = await teamPool.connect(); - - let historicalAgents; - try { - await client.query(`SET search_path TO ${schemaName}`); - await tsdbService.ensureSchema(client); - - // Get all distinct agents from TSDB - historicalAgents = await tsdbService.getDistinctAgents( - teamId, - { since, limit }, - client - ); - } finally { - client.release(); - } - - // Get currently connected instances - const controlEmitter = req.app.locals.controlEmitter as ControlEmitter | undefined; - const connectedInstances = controlEmitter?.getConnectedInstances(teamId) || []; - - // Build a map of connected agents (by instance_id and agent_name) - const connectedByInstanceId = new Map(); - const connectedByAgentName = new Map(); - - for (const instance of connectedInstances) { - connectedByInstanceId.set(instance.instance_id, instance); - if (instance.agent_name) { - connectedByAgentName.set(instance.agent_name, instance); - } - } - - // Merge historical agents with connection status - const agents = historicalAgents.map((agent) => { - // Try to match by agent ID (instance_id) or agent_name - const connectedInstance = - connectedByInstanceId.get(agent.agent) || - connectedByAgentName.get(agent.agent) || - (agent.agent_name ? connectedByAgentName.get(agent.agent_name) : null); - - return { - agent: agent.agent, - agent_name: agent.agent_name || connectedInstance?.agent_name || null, - status: connectedInstance ? "connected" : "disconnected", - connection_type: connectedInstance?.connection_type || null, - instance_id: connectedInstance?.instance_id || null, - first_seen: agent.first_seen.toISOString(), - last_seen: agent.last_seen.toISOString(), - total_requests: agent.total_requests, - total_cost: agent.total_cost, - }; - }); - - // Also add any connected agents that don't have historical events yet - const historicalAgentIds = new Set(historicalAgents.map((a) => a.agent)); - const historicalAgentNames = new Set( - historicalAgents.map((a) => a.agent_name).filter(Boolean) - ); - - for (const instance of connectedInstances) { - const isInHistory = - historicalAgentIds.has(instance.instance_id) || - (instance.agent_name && historicalAgentNames.has(instance.agent_name)); - - if (!isInHistory) { - agents.push({ - agent: instance.instance_id, - agent_name: instance.agent_name, - status: "connected", - connection_type: instance.connection_type, - instance_id: instance.instance_id, - first_seen: instance.connected_at, - last_seen: instance.last_heartbeat, - total_requests: 0, - total_cost: 0, - }); - } - } - - res.json({ - agents, - total: agents.length, - connected_count: agents.filter((a) => a.status === "connected").length, - timestamp: new Date().toISOString(), - }); - } catch (error) { - next(error); - } - } -); - -// ============================================================================= -// Health Check -// ============================================================================= - -/** - * GET /v1/control/health - * Health check endpoint - */ -router.get("/health", (_req: Request, res: Response) => { - res.json({ - status: "healthy", - timestamp: new Date().toISOString(), - websocket: !!global._ADEN_CONTROL_EMITTER, - }); -}); - -export default router; diff --git a/hive/src/controllers/iam.controller.ts b/hive/src/controllers/iam.controller.ts deleted file mode 100644 index 8a734bac..00000000 --- a/hive/src/controllers/iam.controller.ts +++ /dev/null @@ -1,154 +0,0 @@ -/** - * IAM Controller - * - * Handles Identity and Access Management endpoints. - */ - -import { Router, Request, Response } from 'express'; - -const router = Router(); - -/** - * Extract token from Authorization header - * Supports: "jwt ", "Bearer ", or raw "" - */ -function extractToken(authHeader: string): string { - if (authHeader.startsWith('jwt ')) { - return authHeader.slice(4); - } - if (authHeader.startsWith('Bearer ')) { - return authHeader.slice(7); - } - return authHeader; -} - -/** - * GET /iam/get-current-team - * - * Get the current team/organization for the authenticated user. - */ -router.get('/get-current-team', async (req: Request, res: Response) => { - try { - const authHeader = req.headers.authorization; - if (!authHeader) { - return res.status(401).json({ - success: false, - msg: 'No token provided', - }); - } - - const userDbService = req.app.locals.userDbService; - const user = await userDbService.findByToken(extractToken(authHeader)); - - if (!user) { - return res.status(401).json({ - success: false, - msg: 'Invalid token', - }); - } - - const pgPool = req.app.locals.pgPool; - if (!pgPool) { - // Return default team if no database - return res.json({ - orgId: user.current_team_id || 1, - orgName: 'Default Organization', - teamId: user.current_team_id || 1, - teamName: 'Default Team', - }); - } - - // Get team info from database - const result = await pgPool.query( - `SELECT id, name, slug FROM teams WHERE id = $1`, - [user.current_team_id || 1] - ); - - const team = result.rows[0]; - - if (!team) { - // Return default if team not found - return res.json({ - orgId: user.current_team_id || 1, - orgName: 'Default Organization', - teamId: user.current_team_id || 1, - teamName: 'Default Team', - }); - } - - res.json({ - orgId: team.id, - orgName: team.name, - teamId: team.id, - teamName: team.name, - }); - } catch (err) { - console.error('[IAMController] /get-current-team error:', err instanceof Error ? err.message : err); - res.status(500).json({ - success: false, - msg: 'Failed to get current team', - }); - } -}); - -/** - * GET /iam/team/get-team-role-by-id/:teamId - * - * Get the user's role in a specific team. - */ -router.get('/team/get-team-role-by-id/:teamId', async (req: Request, res: Response) => { - try { - const authHeader = req.headers.authorization; - if (!authHeader) { - return res.status(401).json({ - success: false, - msg: 'No token provided', - }); - } - - const userDbService = req.app.locals.userDbService; - const user = await userDbService.findByToken(extractToken(authHeader)); - - if (!user) { - return res.status(401).json({ - success: false, - msg: 'Invalid token', - }); - } - - const teamId = parseInt(req.params.teamId, 10); - - const pgPool = req.app.locals.pgPool; - if (!pgPool) { - // Return default role if no database - return res.json({ roleId: 1 }); - } - - // Get user's role in this team - const result = await pgPool.query( - `SELECT role FROM team_members WHERE user_id = $1 AND team_id = $2`, - [user.id, teamId] - ); - - const membership = result.rows[0]; - - // Map role name to roleId (admin=1, member=2, viewer=3) - const roleMap: Record = { - admin: 1, - member: 2, - viewer: 3, - }; - - const roleId = membership ? (roleMap[membership.role] || 2) : 2; - - res.json({ roleId }); - } catch (err) { - console.error('[IAMController] /team/get-team-role-by-id error:', err instanceof Error ? err.message : err); - res.status(500).json({ - success: false, - msg: 'Failed to get team role', - }); - } -}); - -export default router; diff --git a/hive/src/controllers/quickstart.controller.ts b/hive/src/controllers/quickstart.controller.ts deleted file mode 100644 index 1e66d58c..00000000 --- a/hive/src/controllers/quickstart.controller.ts +++ /dev/null @@ -1,192 +0,0 @@ -/** - * Quickstart Documentation API Controller - * Generates SDK quickstart documentation based on agent framework - */ -import express, { Request, Response, NextFunction } from "express"; -import passport from "passport"; -// Passport is initialized in app.js - -import * as quickstartService from "../services/quickstart/quickstart_service"; - -const router = express.Router(); - -interface AuthenticatedUser { - id: number; - current_team_id: number; - [key: string]: unknown; -} - -interface AuthenticatedRequest extends Request { - user?: AuthenticatedUser; -} - -/** - * @swagger - * /quickstart/options: - * get: - * summary: Get available options for quickstart generation - * tags: - * - Quickstart - * responses: - * 200: - * description: Available options for quickstart document generation - */ -router.get("/options", async (req: Request, res: Response, next: NextFunction) => { - try { - const options = quickstartService.getQuickstartOptions(); - res.send(options); - } catch (error) { - next(error); - } -}); - -/** - * @swagger - * /quickstart/generate: - * post: - * summary: Generate quickstart documentation with user's system token - * tags: - * - Quickstart - * security: - * - jwtAuth: [] - * requestBody: - * required: true - * content: - * application/json: - * schema: - * type: object - * required: - * - agentFramework - * properties: - * agentFramework: - * type: string - * enum: [generic, langgraph, livekit] - * description: The agent framework to use - * responses: - * 200: - * description: Generated quickstart documentation - * 400: - * description: Invalid parameters - * 401: - * description: Unauthorized - JWT token required - */ -router.post( - "/generate", - passport.authenticate("jwt", { session: false }), - async (req: AuthenticatedRequest, res: Response, next: NextFunction) => { - try { - const { user, body } = req; - const { agentFramework, llmVendor, sdkLanguage } = body; - - // Get the user's latest non-system API key - const userDbService = req.app.locals.userDbService; - const tokenObj = user ? await userDbService.getLatestUserDevToken(user) : null; - - let apiKey: string; - let tokenName: string; - if (tokenObj) { - apiKey = tokenObj.token; - tokenName = tokenObj.label; - } else { - // No user API key - use placeholder - apiKey = "eyJ-xxx"; - tokenName = "No Key"; - } - - // Generate the quickstart document - const markdown = quickstartService.generateQuickstart({ - agentFramework, - llmVendor, - sdkLanguage, - apiKey, - }); - - res.send({ - markdown, - metadata: { - agentFramework, - llmVendor, - sdkLanguage, - tokenName, - generatedAt: new Date().toISOString(), - }, - }); - } catch (error) { - if ((error as Error).message.includes("Invalid")) { - return res.status(400).send({ error: (error as Error).message }); - } - next(error); - } - } -); - -/** - * @swagger - * /quickstart/generate-with-key: - * post: - * summary: Generate quickstart documentation with a provided API key - * description: Generate documentation without requiring authentication - API key is provided directly - * tags: - * - Quickstart - * requestBody: - * required: true - * content: - * application/json: - * schema: - * type: object - * required: - * - agentFramework - * - apiKey - * properties: - * agentFramework: - * type: string - * enum: [generic, livekit] - * apiKey: - * type: string - * description: The Aden API key to embed in the documentation - * responses: - * 200: - * description: Generated quickstart documentation - * 400: - * description: Invalid parameters - */ -router.post("/generate-with-key", async (req: Request, res: Response, next: NextFunction) => { - try { - const { agentFramework, llmVendor, sdkLanguage, apiKey } = req.body; - - if (!apiKey) { - return res.status(400).send({ - error: "API key is required", - message: "Please provide an apiKey in the request body", - }); - } - - // Generate the quickstart document - const markdown = quickstartService.generateQuickstart({ - agentFramework, - llmVendor, - sdkLanguage, - apiKey, - }); - - res.send({ - markdown, - metadata: { - agentFramework, - llmVendor, - sdkLanguage, - generatedAt: new Date().toISOString(), - }, - }); - } catch (error) { - if ( - (error as Error).message.includes("Invalid") || - (error as Error).message.includes("required") - ) { - return res.status(400).send({ error: (error as Error).message }); - } - next(error); - } -}); - -export default router; diff --git a/hive/src/controllers/tsdb.controller.ts b/hive/src/controllers/tsdb.controller.ts deleted file mode 100644 index d9944622..00000000 --- a/hive/src/controllers/tsdb.controller.ts +++ /dev/null @@ -1,1205 +0,0 @@ -/** - * TSDB ingestion and preview endpoints (protected) - */ -import express, { Request, Response } from "express"; -import passport from "passport"; -import type { PoolClient } from "pg"; - -import { - ensureSchema, - upsertEvents, -} from "../services/tsdb/tsdb_service"; -import pricingService from "../services/tsdb/pricing_service"; -import { parseToken, getTeamPool, buildSchemaName } from "../services/tsdb/team_context"; -import { buildAnalytics } from "../services/tsdb/analytics_service"; - -const router = express.Router(); - -const AUTH_MIDDLEWARE = passport.authenticate("jwt", { session: false }); - - -interface TokenContext { - team_id: string; - user_id?: string; -} - -interface QueryRow { - [key: string]: unknown; -} - - -interface MetricRow { - period: string; - total_requests: string | number; - unique_traces: string | number; - unique_users: string | number; - total_input_tokens: string | number; - total_output_tokens: string | number; - total_tokens: string | number; - cached_tokens: string | number; - reasoning_tokens: string | number; - total_cost: string | number; - avg_latency_ms: string | number; - p50_latency_ms: string | number; - p95_latency_ms: string | number; - p99_latency_ms: string | number; - max_latency_ms: string | number; - streaming_requests: string | number; -} - -interface LLMEventRow { - timestamp: Date; - trace_id: string; - call_sequence: number; - model: string; - provider: string; - usage_input_tokens: number; - usage_output_tokens: number; - usage_cached_tokens: number; - cost_total: string | number; -} - -interface MergedRow { - request_count: number; - total_input_tokens: number; - total_output_tokens: number; - total_tokens: number; - total_cost: number; - avg_latency_ms: number; - latency_sum: number; - first_seen: Date; - last_seen: Date; - [key: string]: unknown; -} - -const getAuthorizationHeader = (req: Request): string | undefined => { - return req.headers.authorization || (req.headers as Record).Authorization; -}; - -const getTokenContext = (req: Request): TokenContext | null => { - return parseToken(getAuthorizationHeader(req)) as TokenContext | null; -}; - -const connectTeamClient = async (teamId: string | number): Promise => { - const pool = await getTeamPool(teamId, {}); - const schema = buildSchemaName(teamId); - const client = await pool.connect(); - await client.query(`CREATE SCHEMA IF NOT EXISTS ${schema}`); - await client.query(`SET search_path TO ${schema}, public`); - await ensureSchema(client); - return client; -}; - -router.post("/events", AUTH_MIDDLEWARE, async (req: Request, res: Response) => { - let client: PoolClient | undefined; - try { - const ctx = getTokenContext(req); - if (!ctx || !ctx.team_id) { - return res.status(401).json({ error: "invalid_token", detail: "Missing team_id in token" }); - } - const payload = Array.isArray(req.body) ? req.body : req.body?.events; - if (!Array.isArray(payload) || payload.length === 0) { - return res.status(400).json({ error: "events array required" }); - } - if (payload.length > 2000) { - return res.status(400).json({ error: "events array too large (max 2000)" }); - } - - client = await connectTeamClient(ctx.team_id); - const enriched = payload.map((e: Record) => ({ ...e, team_id: ctx.team_id, user_id: (ctx.user_id || e.user_id) as string | undefined })); - const result = await upsertEvents(enriched, client); - return res.json({ - message: "ingested", - rows_written: result.rowsWritten, - normalized: result.normalized, - }); - } catch (err) { - console.error("[tsdb] ingest error", err); - return res.status(500).json({ error: "ingest_failed", detail: (err as Error).message }); - } finally { - if (client) client.release(); - } -}); - -router.get("/sample", AUTH_MIDDLEWARE, async (req: Request, res: Response) => { - let client: PoolClient | undefined; - try { - const ctx = getTokenContext(req); - if (!ctx || !ctx.team_id) { - return res.status(401).json({ error: "invalid_token", detail: "Missing team_id in token" }); - } - client = await connectTeamClient(ctx.team_id); - const limit = Math.min(parseInt((req.query.limit as string) || "20", 10), 100); - const { rows } = await client.query( - 'SELECT * FROM llm_events ORDER BY "timestamp" DESC LIMIT $1', - [limit] - ); - return res.json({ rows }); - } catch (err) { - console.error("[tsdb] sample error", err); - return res.status(500).json({ error: "sample_failed", detail: (err as Error).message }); - } finally { - if (client) client.release(); - } -}); - -router.get("/counts", AUTH_MIDDLEWARE, async (req: Request, res: Response) => { - let client: PoolClient | undefined; - try { - const ctx = getTokenContext(req); - if (!ctx || !ctx.team_id) { - return res.status(401).json({ error: "invalid_token", detail: "Missing team_id in token" }); - } - client = await connectTeamClient(ctx.team_id); - const window = (req.query.window as string) || "1 day"; - const { rows } = await client.query( - 'SELECT COUNT(*)::bigint AS count FROM llm_events WHERE "timestamp" >= NOW() - $1::interval', - [window] - ); - return res.json({ window, count: Number(rows[0].count) }); - } catch (err) { - console.error("[tsdb] counts error", err); - return res.status(500).json({ error: "counts_failed", detail: (err as Error).message }); - } finally { - if (client) client.release(); - } -}); - -router.get("/health", AUTH_MIDDLEWARE, async (req: Request, res: Response) => { - let client: PoolClient | undefined; - try { - const ctx = getTokenContext(req); - if (!ctx || !ctx.team_id) { - return res.status(401).json({ status: "error", detail: "Missing team_id in token" }); - } - client = await connectTeamClient(ctx.team_id); - const { rows } = await client.query("SELECT NOW() AS now"); - return res.json({ status: "ok", now: rows[0].now }); - } catch (err) { - console.error("[tsdb] health error", err); - return res.status(500).json({ status: "error", detail: (err as Error).message }); - } finally { - if (client) client.release(); - } -}); - -// GET /tsdb/logs?start=2025-01-01T00:00:00Z&end=2025-01-02T00:00:00Z&limit=500&offset=0 -// Optional: group_by=model|agent|model,agent for aggregation -router.get("/logs", AUTH_MIDDLEWARE, async (req: Request, res: Response) => { - let poolClient: PoolClient | undefined; - try { - const ctx = getTokenContext(req); - if (!ctx || !ctx.team_id) { - return res.status(401).json({ error: "invalid_token", detail: "Missing team_id in token" }); - } - const { start, end, group_by } = req.query as { start?: string; end?: string; group_by?: string }; - const startDate = start ? new Date(start) : null; - const endDate = end ? new Date(end) : null; - if (!startDate || Number.isNaN(startDate.getTime()) || !endDate || Number.isNaN(endDate.getTime())) { - return res.status(400).json({ error: "invalid_time_window", detail: "start and end must be valid ISO dates" }); - } - - const limit = Math.min(parseInt((req.query.limit as string) || "500", 10), 5000); - const offset = Math.max(parseInt((req.query.offset as string) || "0", 10), 0); - - poolClient = await connectTeamClient(ctx.team_id); - - // Handle aggregation if group_by is specified - if (group_by) { - const validGroupFields = ["model", "agent", "provider"]; - const groupFields = group_by.split(",").map((f) => f.trim()).filter((f) => validGroupFields.includes(f)); - - if (groupFields.length === 0) { - return res.status(400).json({ - error: "invalid_group_by", - detail: `group_by must be one or more of: ${validGroupFields.join(", ")}`, - }); - } - - // Try to use continuous aggregates for better performance - // Use CA when: single group field (model or agent) and provider not requested - // Hybrid approach: CA for completed days + base table for today's partial data - const useModelCA = groupFields.length === 1 && groupFields[0] === "model"; - const useModelProviderCA = groupFields.length === 2 && groupFields.includes("model") && groupFields.includes("provider"); - const useAgentCA = groupFields.length === 1 && groupFields[0] === "agent"; - - let rows: QueryRow[]; - let usedCA = false; - - const utcDayStart = (d: Date): Date => { - const x = new Date(d); - x.setUTCHours(0, 0, 0, 0); - return x; - }; - - const addUtcDays = (d: Date, days: number): Date => { - return new Date(d.getTime() + days * 24 * 60 * 60 * 1000); - }; - - const startDayStart = utcDayStart(startDate); - const endDayStart = utcDayStart(endDate); - - const fullBucketStart = startDate.getTime() === startDayStart.getTime() - ? startDayStart - : addUtcDays(startDayStart, 1); - - const fullBucketEnd = endDayStart; - - const hasFullBuckets = fullBucketStart < fullBucketEnd; - - const partialRanges: Array<{ start: Date; end: Date }> = []; - const pushRange = (rangeStart: Date, rangeEnd: Date): void => { - if (rangeEnd.getTime() <= rangeStart.getTime()) return; - partialRanges.push({ start: rangeStart, end: rangeEnd }); - }; - - pushRange(startDate, new Date(Math.min(endDate.getTime(), fullBucketStart.getTime()))); - pushRange(new Date(Math.max(startDate.getTime(), fullBucketEnd.getTime())), endDate); - - const mergeResults = (caRows: QueryRow[], baseRows: QueryRow[], keyFields: string[]): MergedRow[] => { - const merged = new Map(); - - const addRow = (row: QueryRow): void => { - const key = keyFields.map((f) => row[f]).join("|"); - const requestCount = parseInt(row.request_count as string) || 0; - const inputTokens = parseInt(row.total_input_tokens as string) || 0; - const outputTokens = parseInt(row.total_output_tokens as string) || 0; - const totalTokens = parseInt(row.total_tokens as string) || 0; - const totalCost = parseFloat(row.total_cost as string) || 0; - const avgLatency = parseFloat(row.avg_latency_ms as string) || 0; - const firstSeen = row.first_seen as Date; - const lastSeen = row.last_seen as Date; - - const existing = merged.get(key); - if (!existing) { - merged.set(key, { - ...Object.fromEntries(keyFields.map((f) => [f, row[f]])), - request_count: requestCount, - total_input_tokens: inputTokens, - total_output_tokens: outputTokens, - total_tokens: totalTokens, - total_cost: totalCost, - avg_latency_ms: avgLatency, - latency_sum: avgLatency * requestCount, - first_seen: firstSeen, - last_seen: lastSeen, - }); - return; - } - - const newCount = existing.request_count + requestCount; - const newLatencySum = existing.latency_sum + avgLatency * requestCount; - - merged.set(key, { - ...existing, - request_count: newCount, - total_input_tokens: existing.total_input_tokens + inputTokens, - total_output_tokens: existing.total_output_tokens + outputTokens, - total_tokens: existing.total_tokens + totalTokens, - total_cost: existing.total_cost + totalCost, - avg_latency_ms: newCount > 0 ? newLatencySum / newCount : 0, - latency_sum: newLatencySum, - first_seen: existing.first_seen < firstSeen ? existing.first_seen : firstSeen, - last_seen: existing.last_seen > lastSeen ? existing.last_seen : lastSeen, - }); - }; - - for (const row of caRows) addRow(row); - for (const row of baseRows) addRow(row); - - // Convert to array and sort by cost desc - return Array.from(merged.values()) - .map(({ latency_sum: _latency_sum, ...rest }) => ({ ...rest, latency_sum: 0 })) - .sort((a, b) => b.total_cost - a.total_cost); - }; - - const getBaseAggData = async (rangeStart: Date, rangeEnd: Date, selectFields: string, groupByClause: string): Promise => { - if (rangeEnd.getTime() <= rangeStart.getTime()) return []; - - const baseSql = ` - SELECT - ${selectFields}, - COUNT(*) as request_count, - COALESCE(SUM(COALESCE(usage_input_tokens, 0)), 0) as total_input_tokens, - COALESCE(SUM(COALESCE(usage_output_tokens, 0)), 0) as total_output_tokens, - COALESCE(SUM(COALESCE(usage_total_tokens, COALESCE(usage_input_tokens, 0) + COALESCE(usage_output_tokens, 0))), 0) as total_tokens, - COALESCE(SUM(cost_total), 0) as total_cost, - COALESCE(AVG(latency_ms), 0) as avg_latency_ms, - MIN("timestamp") as first_seen, - MAX("timestamp") as last_seen - FROM llm_events - WHERE "timestamp" >= $1 AND "timestamp" <= $2 AND team_id = $3 - GROUP BY ${groupByClause} - `; - - const result = await poolClient.query(baseSql, [rangeStart.toISOString(), rangeEnd.toISOString(), String(ctx.team_id)]); - return result.rows; - }; - - if (useModelCA || useModelProviderCA) { - // Try model CA - includes provider so works for both cases - try { - const keyFields = useModelProviderCA ? ["model", "provider"] : ["model"]; - - const selectFields = useModelProviderCA ? "model, provider" : "model"; - - const baseRows = (await Promise.all( - partialRanges.map((r) => getBaseAggData(r.start, r.end, selectFields, selectFields)) - )).flat(); - - let caRows: QueryRow[] = []; - if (hasFullBuckets) { - const caSql = ` - SELECT - model, - ${useModelProviderCA ? "provider," : ""} - SUM(requests) as request_count, - COALESCE(SUM(input_tokens), 0) as total_input_tokens, - COALESCE(SUM(output_tokens), 0) as total_output_tokens, - (COALESCE(SUM(input_tokens), 0) + COALESCE(SUM(output_tokens), 0)) as total_tokens, - COALESCE(SUM(cost_total), 0) as total_cost, - COALESCE(SUM(avg_latency_ms * requests) / NULLIF(SUM(requests), 0), 0) as avg_latency_ms, - MIN(bucket) as first_seen, - MAX(bucket) as last_seen - FROM llm_events_daily_by_model_ca - WHERE bucket >= $1 AND bucket < $2 - GROUP BY model${useModelProviderCA ? ", provider" : ""} - `; - const result = await poolClient.query(caSql, [fullBucketStart.toISOString(), fullBucketEnd.toISOString()]); - caRows = result.rows; - } - - rows = mergeResults(caRows, baseRows, keyFields).slice(offset, offset + limit) as unknown as QueryRow[]; - usedCA = hasFullBuckets; - } catch (err) { - // CA not available, fall through to base table query - } - } else if (useAgentCA) { - // Try agent CA - try { - const baseRows = (await Promise.all( - partialRanges.map((r) => getBaseAggData(r.start, r.end, "agent", "agent")) - )).flat(); - - let caRows: QueryRow[] = []; - if (hasFullBuckets) { - const caSql = ` - SELECT - agent, - SUM(requests) as request_count, - COALESCE(SUM(input_tokens), 0) as total_input_tokens, - COALESCE(SUM(output_tokens), 0) as total_output_tokens, - (COALESCE(SUM(input_tokens), 0) + COALESCE(SUM(output_tokens), 0)) as total_tokens, - COALESCE(SUM(cost_total), 0) as total_cost, - COALESCE(SUM(avg_latency_ms * requests) / NULLIF(SUM(requests), 0), 0) as avg_latency_ms, - MIN(bucket) as first_seen, - MAX(bucket) as last_seen - FROM llm_events_daily_by_agent_ca - WHERE bucket >= $1 AND bucket < $2 - GROUP BY agent - `; - const result = await poolClient.query(caSql, [fullBucketStart.toISOString(), fullBucketEnd.toISOString()]); - caRows = result.rows; - } - - rows = mergeResults(caRows, baseRows, ["agent"]).slice(offset, offset + limit) as unknown as QueryRow[]; - usedCA = hasFullBuckets; - } catch (err) { - // CA not available, fall through to base table query - } - } - - // Fallback to base table query if CA not used or failed - if (!usedCA) { - const groupByClause = groupFields.join(", "); - const selectFields = groupFields.map((f) => f).join(", "); - - const aggSql = ` - SELECT - ${selectFields}, - COUNT(*) as request_count, - COALESCE(SUM(COALESCE(usage_input_tokens, 0)), 0) as total_input_tokens, - COALESCE(SUM(COALESCE(usage_output_tokens, 0)), 0) as total_output_tokens, - COALESCE(SUM(COALESCE(usage_total_tokens, COALESCE(usage_input_tokens, 0) + COALESCE(usage_output_tokens, 0))), 0) as total_tokens, - COALESCE(SUM(cost_total), 0) as total_cost, - COALESCE(AVG(latency_ms), 0) as avg_latency_ms, - MIN("timestamp") as first_seen, - MAX("timestamp") as last_seen - FROM llm_events - WHERE "timestamp" >= $1 AND "timestamp" <= $2 AND team_id = $3 - GROUP BY ${groupByClause} - ORDER BY total_cost DESC - LIMIT $4 OFFSET $5 - `; - const result = await poolClient.query(aggSql, [startDate.toISOString(), endDate.toISOString(), String(ctx.team_id), limit, offset]); - rows = result.rows; - } - - return res.json({ - window: { start: startDate.toISOString(), end: endDate.toISOString() }, - group_by: groupFields, - count: rows!.length, - source: usedCA ? "continuous_aggregate" : "base_table", - aggregations: rows!.map((row) => ({ - ...Object.fromEntries(groupFields.map((f) => [f, row[f]])), - request_count: parseInt(row.request_count as string) || 0, - total_input_tokens: parseInt(row.total_input_tokens as string) || 0, - total_output_tokens: parseInt(row.total_output_tokens as string) || 0, - total_tokens: parseInt(row.total_tokens as string) || 0, - total_cost: parseFloat(row.total_cost as string) || 0, - avg_latency_ms: parseFloat(row.avg_latency_ms as string) || 0, - first_seen: row.first_seen, - last_seen: row.last_seen, - })), - }); - } - - // Default: return raw rows with derived type and success fields - const { type: typeFilter, success: successFilter } = req.query as { type?: string; success?: string }; - - // Build WHERE conditions for optional filters - const whereConditions = [ - '"timestamp" >= $1', - '"timestamp" <= $2', - 'team_id = $3', - ]; - const params: (string | number | boolean)[] = [startDate.toISOString(), endDate.toISOString(), String(ctx.team_id)]; - - // Add type filter if specified - if (typeFilter && typeFilter !== 'all') { - if (typeFilter === 'tool_call') { - whereConditions.push('COALESCE(tool_call_count, 0) > 0'); - } else if (typeFilter === 'error') { - whereConditions.push('(finish_reason IS NULL OR finish_reason IN (\'error\', \'content_filter\'))'); - } else if (typeFilter === 'llm_request') { - whereConditions.push('COALESCE(tool_call_count, 0) = 0'); - whereConditions.push('(finish_reason IS NOT NULL AND finish_reason NOT IN (\'error\', \'content_filter\'))'); - } - } - - // Add success filter if specified - if (successFilter !== undefined && successFilter !== '') { - const isSuccess = successFilter === 'true'; - if (isSuccess) { - whereConditions.push('finish_reason IN (\'stop\', \'end_turn\', \'tool_calls\', \'length\')'); - } else { - whereConditions.push('(finish_reason IS NULL OR finish_reason NOT IN (\'stop\', \'end_turn\', \'tool_calls\', \'length\'))'); - } - } - - params.push(limit, offset); - - const sql = ` - SELECT *, - CASE - WHEN COALESCE(tool_call_count, 0) > 0 THEN 'tool_call' - WHEN finish_reason IS NULL OR finish_reason IN ('error', 'content_filter') THEN 'error' - ELSE 'llm_request' - END as derived_type, - CASE - WHEN finish_reason IN ('stop', 'end_turn', 'tool_calls', 'length') THEN true - ELSE false - END as derived_success - FROM llm_events - WHERE ${whereConditions.join(' AND ')} - ORDER BY "timestamp" DESC - LIMIT $${params.length - 1} OFFSET $${params.length} - `; - const { rows } = await poolClient.query(sql, params); - return res.json({ - window: { start: startDate.toISOString(), end: endDate.toISOString() }, - count: rows.length, - filters: { type: typeFilter || 'all', success: successFilter }, - rows, - }); - } catch (err) { - console.error("[tsdb] logs error", err); - return res.status(500).json({ error: "logs_failed", detail: (err as Error).message }); - } finally { - if (poolClient) poolClient.release(); - } -}); - -// GET /tsdb/metrics?days=30 -// Returns summary metrics with period-over-period % change -router.get("/metrics", AUTH_MIDDLEWARE, async (req: Request, res: Response) => { - let client: PoolClient | undefined; - try { - const ctx = getTokenContext(req); - if (!ctx || !ctx.team_id) { - return res.status(401).json({ error: "invalid_token", detail: "Missing team_id in token" }); - } - - const days = Math.min(parseInt((req.query.days as string) || "30", 10), 365); - - client = await connectTeamClient(ctx.team_id); - - // Calculate date ranges for current and previous periods - const now = new Date(); - const currentStart = new Date(now); - currentStart.setDate(currentStart.getDate() - days); - const previousStart = new Date(currentStart); - previousStart.setDate(previousStart.getDate() - days); - - // Query metrics for both periods in a single query using CASE statements - const metricsSql = ` - WITH period_data AS ( - SELECT - CASE - WHEN "timestamp" >= $2 THEN 'current' - ELSE 'previous' - END as period, - 1 as request, - COALESCE(usage_input_tokens, 0) as input_tokens, - COALESCE(usage_output_tokens, 0) as output_tokens, - COALESCE( - usage_total_tokens, - COALESCE(usage_input_tokens, 0) + COALESCE(usage_output_tokens, 0), - 0 - ) as total_tokens, - COALESCE(usage_cached_tokens, 0) as cached_tokens, - COALESCE(usage_reasoning_tokens, 0) as reasoning_tokens, - COALESCE(cost_total, 0) as cost, - latency_ms, - trace_id, - user_id, - CASE WHEN stream = true THEN 1 ELSE 0 END as is_streaming - FROM llm_events - WHERE "timestamp" >= $1 AND "timestamp" <= $3 AND team_id = $4 - ), - aggregated AS ( - SELECT - period, - COUNT(*) as total_requests, - COUNT(DISTINCT trace_id) as unique_traces, - COUNT(DISTINCT user_id) as unique_users, - SUM(input_tokens) as total_input_tokens, - SUM(output_tokens) as total_output_tokens, - SUM(total_tokens) as total_tokens, - SUM(cached_tokens) as cached_tokens, - SUM(reasoning_tokens) as reasoning_tokens, - SUM(cost) as total_cost, - AVG(latency_ms) as avg_latency_ms, - PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY latency_ms) as p50_latency_ms, - PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY latency_ms) as p95_latency_ms, - PERCENTILE_CONT(0.99) WITHIN GROUP (ORDER BY latency_ms) as p99_latency_ms, - MAX(latency_ms) as max_latency_ms, - SUM(is_streaming) as streaming_requests - FROM period_data - GROUP BY period - ) - SELECT * FROM aggregated - `; - - const { rows } = await client.query(metricsSql, [ - previousStart.toISOString(), - currentStart.toISOString(), - now.toISOString(), - String(ctx.team_id), - ]); - - // Parse results into current and previous periods - const current = rows.find((r) => r.period === "current") || {} as Partial; - const previous = rows.find((r) => r.period === "previous") || {} as Partial; - - // Helper to calculate % change - const pctChange = (curr: string | number | undefined, prev: string | number | undefined): number => { - const c = parseFloat(curr as string) || 0; - const p = parseFloat(prev as string) || 0; - if (p === 0) return c > 0 ? 100 : 0; - return ((c - p) / p) * 100; - }; - - // Helper to safely parse numbers - const num = (val: string | number | undefined): number => parseFloat(val as string) || 0; - const int = (val: string | number | undefined): number => parseInt(val as string) || 0; - - // Calculate derived metrics - const totalRequests = int(current.total_requests); - const totalTokens = num(current.total_tokens); - const cachedTokens = num(current.cached_tokens); - const inputTokens = num(current.total_input_tokens); - const uniqueTraces = int(current.unique_traces); - const streamingRequests = int(current.streaming_requests); - - const cacheHitRate = inputTokens > 0 ? (cachedTokens / inputTokens) * 100 : 0; - const prevCacheHitRate = num(previous.total_input_tokens) > 0 - ? (num(previous.cached_tokens) / num(previous.total_input_tokens)) * 100 - : 0; - - const streamingRate = totalRequests > 0 ? (streamingRequests / totalRequests) * 100 : 0; - const prevStreamingRate = int(previous.total_requests) > 0 - ? (int(previous.streaming_requests) / int(previous.total_requests)) * 100 - : 0; - - const avgCallsPerTrace = uniqueTraces > 0 ? totalRequests / uniqueTraces : 0; - const prevAvgCallsPerTrace = int(previous.unique_traces) > 0 - ? int(previous.total_requests) / int(previous.unique_traces) - : 0; - - const totalCost = num(current.total_cost); - const costPer1kTokens = totalTokens > 0 ? (totalCost / (totalTokens / 1000)) : 0; - const prevTotalTokens = num(previous.total_tokens); - const prevCostPer1kTokens = prevTotalTokens > 0 - ? (num(previous.total_cost) / (prevTotalTokens / 1000)) - : 0; - - const metrics = { - period: { - days, - current: { start: currentStart.toISOString(), end: now.toISOString() }, - previous: { start: previousStart.toISOString(), end: currentStart.toISOString() }, - }, - volume: { - total_requests: { - value: totalRequests, - unit: "requests", - change_pct: pctChange(current.total_requests, previous.total_requests), - }, - unique_traces: { - value: uniqueTraces, - unit: "traces", - change_pct: pctChange(current.unique_traces, previous.unique_traces), - }, - unique_users: { - value: int(current.unique_users), - unit: "users", - change_pct: pctChange(current.unique_users, previous.unique_users), - }, - avg_calls_per_trace: { - value: Math.round(avgCallsPerTrace * 100) / 100, - unit: "calls/trace", - change_pct: pctChange(avgCallsPerTrace, prevAvgCallsPerTrace), - }, - }, - tokens: { - total_input_tokens: { - value: int(current.total_input_tokens), - unit: "tokens", - change_pct: pctChange(current.total_input_tokens, previous.total_input_tokens), - }, - total_output_tokens: { - value: int(current.total_output_tokens), - unit: "tokens", - change_pct: pctChange(current.total_output_tokens, previous.total_output_tokens), - }, - total_tokens: { - value: int(totalTokens), - unit: "tokens", - change_pct: pctChange(current.total_tokens, previous.total_tokens), - }, - cached_tokens: { - value: int(cachedTokens), - unit: "tokens", - change_pct: pctChange(current.cached_tokens, previous.cached_tokens), - }, - reasoning_tokens: { - value: int(current.reasoning_tokens), - unit: "tokens", - change_pct: pctChange(current.reasoning_tokens, previous.reasoning_tokens), - }, - cache_hit_rate: { - value: Math.round(cacheHitRate * 100) / 100, - unit: "%", - change_pct: pctChange(cacheHitRate, prevCacheHitRate), - }, - avg_tokens_per_request: { - value: totalRequests > 0 ? Math.round(totalTokens / totalRequests) : 0, - unit: "tokens/req", - change_pct: pctChange( - totalRequests > 0 ? totalTokens / totalRequests : 0, - int(previous.total_requests) > 0 ? prevTotalTokens / int(previous.total_requests) : 0 - ), - }, - }, - performance: { - avg_latency_ms: { - value: Math.round(num(current.avg_latency_ms) * 100) / 100, - unit: "ms", - change_pct: pctChange(current.avg_latency_ms, previous.avg_latency_ms), - }, - p50_latency_ms: { - value: Math.round(num(current.p50_latency_ms) * 100) / 100, - unit: "ms", - change_pct: pctChange(current.p50_latency_ms, previous.p50_latency_ms), - }, - p95_latency_ms: { - value: Math.round(num(current.p95_latency_ms) * 100) / 100, - unit: "ms", - change_pct: pctChange(current.p95_latency_ms, previous.p95_latency_ms), - }, - p99_latency_ms: { - value: Math.round(num(current.p99_latency_ms) * 100) / 100, - unit: "ms", - change_pct: pctChange(current.p99_latency_ms, previous.p99_latency_ms), - }, - max_latency_ms: { - value: Math.round(num(current.max_latency_ms) * 100) / 100, - unit: "ms", - change_pct: pctChange(current.max_latency_ms, previous.max_latency_ms), - }, - }, - cost: { - total_cost: { - value: Math.round(totalCost * 100) / 100, - unit: "USD", - change_pct: pctChange(current.total_cost, previous.total_cost), - }, - avg_cost_per_request: { - value: totalRequests > 0 ? Math.round((totalCost / totalRequests) * 10000) / 10000 : 0, - unit: "USD/req", - change_pct: pctChange( - totalRequests > 0 ? totalCost / totalRequests : 0, - int(previous.total_requests) > 0 ? num(previous.total_cost) / int(previous.total_requests) : 0 - ), - }, - cost_per_1k_tokens: { - value: Math.round(costPer1kTokens * 10000) / 10000, - unit: "USD/1k tokens", - change_pct: pctChange(costPer1kTokens, prevCostPer1kTokens), - }, - }, - usage_patterns: { - streaming_rate: { - value: Math.round(streamingRate * 100) / 100, - unit: "%", - change_pct: pctChange(streamingRate, prevStreamingRate), - }, - }, - }; - - return res.json(metrics); - } catch (err) { - console.error("[tsdb] metrics error", err); - return res.status(500).json({ error: "metrics_failed", detail: (err as Error).message }); - } finally { - if (client) client.release(); - } -}); - -// POST /tsdb/refresh-aggregates -// Manually refresh all continuous aggregates to ensure data is up-to-date -router.post("/refresh-aggregates", AUTH_MIDDLEWARE, async (req: Request, res: Response) => { - let client: PoolClient | undefined; - try { - const ctx = getTokenContext(req); - if (!ctx || !ctx.team_id) { - return res.status(401).json({ error: "invalid_token", detail: "Missing team_id in token" }); - } - - client = await connectTeamClient(ctx.team_id); - - const results: Array<{ ca: string; status: string; error?: string }> = []; - - // Refresh all CAs from beginning of time to now - const cas = [ - "llm_events_daily_ca", - "llm_events_daily_by_model_ca", - "llm_events_daily_by_agent_ca", - ]; - - for (const ca of cas) { - try { - await client.query(`CALL refresh_continuous_aggregate('${ca}', NULL, NOW())`); - results.push({ ca, status: "refreshed" }); - } catch (err) { - results.push({ ca, status: "error", error: (err as Error).message }); - } - } - - return res.json({ - message: "Continuous aggregates refresh completed", - results, - refreshed_at: new Date().toISOString(), - }); - } catch (err) { - console.error("[tsdb] refresh-aggregates error", err); - return res.status(500).json({ error: "refresh_failed", detail: (err as Error).message }); - } finally { - if (client) client.release(); - } -}); - -// ==================== PRICING CRUD ENDPOINTS ==================== - -// GET /tsdb/pricing - List all pricing -// Optional: ?group_by=provider to group by provider -router.get("/pricing", AUTH_MIDDLEWARE, async (req: Request, res: Response) => { - try { - const { group_by } = req.query; - - if (group_by === "provider") { - const pricing = await pricingService.getPricingByProvider(); - return res.json({ pricing, grouped_by: "provider" }); - } - - const pricing = await pricingService.getAllPricing(); - return res.json({ pricing, count: Object.keys(pricing).length }); - } catch (err) { - console.error("[tsdb] pricing list error", err); - return res.status(500).json({ error: "pricing_list_failed", detail: (err as Error).message }); - } -}); - -// GET /tsdb/pricing/:model - Get specific model pricing -router.get("/pricing/:model", AUTH_MIDDLEWARE, async (req: Request, res: Response) => { - try { - const { model } = req.params; - const { provider } = req.query; - - const pricing = await pricingService.getModelPricing(model, provider as string | undefined); - return res.json({ pricing }); - } catch (err) { - console.error("[tsdb] pricing get error", err); - return res.status(500).json({ error: "pricing_get_failed", detail: (err as Error).message }); - } -}); - -// POST /tsdb/pricing - Add new model pricing -router.post("/pricing", AUTH_MIDDLEWARE, async (req: Request, res: Response) => { - try { - const ctx = getTokenContext(req); - const { model, provider, input_per_1m, output_per_1m, cached_input_per_1m, aliases } = req.body; - - if (!model) { - return res.status(400).json({ error: "model is required" }); - } - if (input_per_1m === undefined || output_per_1m === undefined) { - return res.status(400).json({ error: "input_per_1m and output_per_1m are required" }); - } - - const result = await pricingService.upsertPricing( - model, - { - provider, - input_per_1m, - output_per_1m, - cached_input_per_1m: cached_input_per_1m ?? input_per_1m * 0.5, - aliases: aliases || [], - }, - ctx?.user_id - ); - - return res.json({ message: "pricing_created", pricing: result }); - } catch (err) { - console.error("[tsdb] pricing create error", err); - return res.status(500).json({ error: "pricing_create_failed", detail: (err as Error).message }); - } -}); - -// PUT /tsdb/pricing/:model - Update model pricing -router.put("/pricing/:model", AUTH_MIDDLEWARE, async (req: Request, res: Response) => { - try { - const ctx = getTokenContext(req); - const { model } = req.params; - const { provider, input_per_1m, output_per_1m, cached_input_per_1m, aliases } = req.body; - - const result = await pricingService.upsertPricing( - model, - { - provider, - input_per_1m, - output_per_1m, - cached_input_per_1m, - aliases, - }, - ctx?.user_id - ); - - return res.json({ message: "pricing_updated", pricing: result }); - } catch (err) { - console.error("[tsdb] pricing update error", err); - return res.status(500).json({ error: "pricing_update_failed", detail: (err as Error).message }); - } -}); - -// DELETE /tsdb/pricing/:model - Remove model pricing -router.delete("/pricing/:model", AUTH_MIDDLEWARE, async (req: Request, res: Response) => { - try { - const { model } = req.params; - const deleted = await pricingService.deletePricing(model); - - if (!deleted) { - return res.status(404).json({ error: "pricing_not_found", model }); - } - - return res.json({ message: "pricing_deleted", model }); - } catch (err) { - console.error("[tsdb] pricing delete error", err); - return res.status(500).json({ error: "pricing_delete_failed", detail: (err as Error).message }); - } -}); - -// POST /tsdb/pricing/seed - Seed default pricing to DB -router.post("/pricing/seed", AUTH_MIDDLEWARE, async (req: Request, res: Response) => { - try { - const ctx = getTokenContext(req); - const { overwrite } = req.body; - - const result = await pricingService.seedDefaultPricing(ctx?.user_id, overwrite === true); - - return res.json({ - message: "pricing_seeded", - ...result, - }); - } catch (err) { - console.error("[tsdb] pricing seed error", err); - return res.status(500).json({ error: "pricing_seed_failed", detail: (err as Error).message }); - } -}); - -// POST /tsdb/pricing/refresh - Force refresh pricing cache -router.post("/pricing/refresh", AUTH_MIDDLEWARE, async (_req: Request, res: Response) => { - try { - await pricingService.loadPricingFromDb(true); - const pricing = await pricingService.getAllPricing(); - - return res.json({ - message: "cache_refreshed", - count: Object.keys(pricing).length, - refreshed_at: new Date().toISOString(), - }); - } catch (err) { - console.error("[tsdb] pricing refresh error", err); - return res.status(500).json({ error: "pricing_refresh_failed", detail: (err as Error).message }); - } -}); - -router.get("/analytics-wide", AUTH_MIDDLEWARE, async (req: Request, res: Response) => { - let client: PoolClient | undefined; - try { - const ctx = getTokenContext(req); - if (!ctx || !ctx.team_id) { - return res.status(401).json({ error: "invalid_token", detail: "Missing team_id in token" }); - } - - const windowLabel = (req.query.window as string) || "this_month"; - - client = await connectTeamClient(ctx.team_id); - - const analytics = await buildAnalytics({ - windowLabel, - client, - resolution: "day", - }); - - return res.json({ analytics }); - } catch (err) { - console.error("[tsdb] analytics-wide error", err); - return res.status(500).json({ error: "analytics_failed", detail: (err as Error).message }); - } finally { - if (client) client.release(); - } -}); - -router.get("/analytics-narrow", AUTH_MIDDLEWARE, async (req: Request, res: Response) => { - let client: PoolClient | undefined; - try { - const ctx = getTokenContext(req); - if (!ctx || !ctx.team_id) { - return res.status(401).json({ error: "invalid_token", detail: "Missing team_id in token" }); - } - - client = await connectTeamClient(ctx.team_id); - - const analytics = await buildAnalytics({ - windowLabel: "today", - client, - resolution: "hour", - }); - - return res.json({ analytics }); - } catch (err) { - console.error("[tsdb] analytics-narrow error", err); - return res.status(500).json({ error: "analytics_failed", detail: (err as Error).message }); - } finally { - if (client) client.release(); - } -}); - -// POST /tsdb/recalculate-costs - Recalculate historical costs with current pricing -router.post("/recalculate-costs", AUTH_MIDDLEWARE, async (req: Request, res: Response) => { - let poolClient: PoolClient | undefined; - try { - const ctx = getTokenContext(req); - if (!ctx || !ctx.team_id) { - return res.status(401).json({ error: "invalid_token", detail: "Missing team_id in token" }); - } - - const { start, end, batch_size = 1000 } = req.body; - - if (!start || !end) { - return res.status(400).json({ error: "start and end dates are required" }); - } - - const startDate = new Date(start); - const endDate = new Date(end); - - if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) { - return res.status(400).json({ error: "invalid_dates", detail: "start and end must be valid ISO dates" }); - } - - if (endDate < startDate) { - return res.status(400).json({ error: "invalid_range", detail: "end must be after start" }); - } - - poolClient = await connectTeamClient(ctx.team_id); - - // Ensure pricing is loaded - await pricingService.loadPricingFromDb(true); - - const results: { - updated: number; - processed: number; - errors: Array<{ trace_id?: string; call_sequence?: number; batch?: number; error?: string; warning?: string }>; - batches: number; - } = { - updated: 0, - processed: 0, - errors: [], - batches: 0, - }; - - const startTime = Date.now(); - let offset = 0; - let hasMore = true; - - // Process in batches - while (hasMore) { - // Fetch batch of events - const selectSql = ` - SELECT - "timestamp", - trace_id, - call_sequence, - model, - provider, - usage_input_tokens, - usage_output_tokens, - usage_cached_tokens, - cost_total - FROM llm_events - WHERE "timestamp" >= $1 AND "timestamp" <= $2 AND team_id = $3 - ORDER BY "timestamp" - LIMIT $4 OFFSET $5 - `; - - const { rows } = await poolClient.query(selectSql, [ - startDate.toISOString(), - endDate.toISOString(), - String(ctx.team_id), - batch_size, - offset, - ]); - - if (rows.length === 0) { - hasMore = false; - break; - } - - results.batches++; - - // Calculate new costs and prepare updates - const updates: Array<{ timestamp: Date; trace_id: string; call_sequence: number; new_cost: number }> = []; - for (const row of rows) { - try { - const costResult = pricingService.calculateCostSync({ - model: row.model || "", - provider: row.provider, - input_tokens: row.usage_input_tokens || 0, - output_tokens: row.usage_output_tokens || 0, - cached_tokens: row.usage_cached_tokens || 0, - }); - - // Only update if cost changed - const oldCost = parseFloat(row.cost_total as string) || 0; - const newCost = costResult.total; - - if (Math.abs(newCost - oldCost) > 0.000001) { - updates.push({ - timestamp: row.timestamp, - trace_id: row.trace_id, - call_sequence: row.call_sequence, - new_cost: newCost, - }); - } - - results.processed++; - } catch (err) { - results.errors.push({ - trace_id: row.trace_id, - call_sequence: row.call_sequence, - error: (err as Error).message, - }); - } - } - - // Apply batch updates - if (updates.length > 0) { - // Use a single UPDATE with CASE for efficiency - const updateSql = ` - UPDATE llm_events - SET cost_total = updates.new_cost - FROM (VALUES ${updates.map((_, i) => `($${i * 4 + 1}::timestamptz, $${i * 4 + 2}::text, $${i * 4 + 3}::integer, $${i * 4 + 4}::numeric)`).join(", ")}) AS updates(ts, tid, cs, new_cost) - WHERE llm_events."timestamp" = updates.ts - AND llm_events.trace_id = updates.tid - AND llm_events.call_sequence = updates.cs - `; - - const updateValues = updates.flatMap((u) => [u.timestamp, u.trace_id, u.call_sequence, u.new_cost]); - - try { - await poolClient.query(updateSql, updateValues); - results.updated += updates.length; - } catch (err) { - results.errors.push({ batch: results.batches, error: (err as Error).message }); - } - } - - offset += batch_size; - - // Safety check - stop if taking too long (5 minutes) - if (Date.now() - startTime > 5 * 60 * 1000) { - results.errors.push({ warning: "Timeout reached after 5 minutes. Partial recalculation completed." }); - hasMore = false; - } - } - - // Refresh continuous aggregates after recalculation - const caRefreshResults: Array<{ ca: string; status: string; error?: string }> = []; - const cas = ["llm_events_daily_ca", "llm_events_daily_by_model_ca", "llm_events_daily_by_agent_ca"]; - - for (const ca of cas) { - try { - await poolClient.query(`CALL refresh_continuous_aggregate('${ca}', $1::timestamptz, $2::timestamptz)`, [ - startDate.toISOString(), - endDate.toISOString(), - ]); - caRefreshResults.push({ ca, status: "refreshed" }); - } catch (err) { - caRefreshResults.push({ ca, status: "error", error: (err as Error).message }); - } - } - - return res.json({ - message: "recalculation_complete", - period: { start: startDate.toISOString(), end: endDate.toISOString() }, - stats: { - processed: results.processed, - updated: results.updated, - batches: results.batches, - duration_ms: Date.now() - startTime, - }, - continuous_aggregates: caRefreshResults, - errors: results.errors.slice(0, 10), // Limit error output - error_count: results.errors.length, - }); - } catch (err) { - console.error("[tsdb] recalculate-costs error", err); - return res.status(500).json({ error: "recalculate_failed", detail: (err as Error).message }); - } finally { - if (poolClient) poolClient.release(); - } -}); - -export default router; diff --git a/hive/src/controllers/user.controller.ts b/hive/src/controllers/user.controller.ts deleted file mode 100644 index d962840f..00000000 --- a/hive/src/controllers/user.controller.ts +++ /dev/null @@ -1,626 +0,0 @@ -/** - * User Controller - * - * Handles user authentication endpoints including login-v2. - */ - -import { Router, Request, Response, NextFunction } from "express"; -import config from "../config"; - -const router = Router(); - -/** - * Extract token from Authorization header - * Supports: "jwt ", "Bearer ", or raw "" - */ -function extractToken(authHeader: string): string { - if (authHeader.startsWith("jwt ")) { - return authHeader.slice(4); - } - if (authHeader.startsWith("Bearer ")) { - return authHeader.slice(7); - } - return authHeader; -} - -// Email validation regex -const EMAIL_REGEX = - /[\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?/; - -/** - * POST /user/login-v2 - * - * Authenticate a user with email and password. - * Returns a JWT token on success. - */ -router.post( - "/login-v2", - async (req: Request, res: Response, _next: NextFunction) => { - try { - let { email } = req.body; - const { password } = req.body; - - // Validate required fields - if ( - !email || - typeof email !== "string" || - !password || - typeof password !== "string" - ) { - return res.status(400).json({ - success: false, - msg: "Email and password are required", - }); - } - - // Validate email format - if (!EMAIL_REGEX.test(email)) { - return res.status(400).json({ - success: false, - msg: "Please enter a valid email", - }); - } - - // Trim email - email = email.trim().toLowerCase(); - - // Validate password length - if (password.length < 6) { - return res.status(400).json({ - success: false, - msg: "Password must be at least 6 characters", - }); - } - - // Get userDbService from app.locals - const userDbService = req.app.locals.userDbService; - if (!userDbService) { - console.error("[UserController] userDbService not found in app.locals"); - return res.status(500).json({ - success: false, - msg: "Internal server error", - }); - } - - // Attempt login - const result = await userDbService.login(email, password, { - jwtSecret: config.jwt.secret, - expiresIn: config.jwt.expiresIn, - }); - - console.log( - `[UserController] login-v2: User ${email} logged in successfully` - ); - - // Return success response - res.json({ - success: true, - token: result.token, - email: result.email, - firstname: result.firstname, - lastname: result.lastname, - name: result.name, - current_team_id: result.current_team_id, - create_time: result.created_at, - }); - } catch (err: unknown) { - const error = err as { message?: string; code?: string }; - console.error("[UserController] login-v2 error:", error.message); - - // Handle specific error codes - if ( - error.code === "USER_NOT_FOUND" || - error.code === "INVALID_CREDENTIALS" - ) { - return res.status(401).json({ - success: false, - msg: "Invalid email or password", - }); - } - - if (error.code === "OAUTH_REQUIRED") { - return res.status(400).json({ - success: false, - msg: error.message, - }); - } - - if (error.code === "ACCOUNT_DISABLED") { - return res.status(403).json({ - success: false, - msg: "Your account has been disabled", - }); - } - - // Generic error - return res.status(500).json({ - success: false, - msg: "Login failed. Please try again.", - }); - } - } -); - -/** - * POST /user/register - * - * Register a new user account. - * Returns a JWT token on success. - */ -router.post("/register", async (req: Request, res: Response) => { - try { - let { email } = req.body; - const { password, name, firstname, lastname } = req.body; - - // Validate required fields - if ( - !email || - typeof email !== "string" || - !password || - typeof password !== "string" - ) { - return res.status(400).json({ - success: false, - msg: "Email and password are required", - }); - } - - // Validate email format - if (!EMAIL_REGEX.test(email)) { - return res.status(400).json({ - success: false, - msg: "Please enter a valid email", - }); - } - - // Trim and lowercase email - email = email.trim().toLowerCase(); - - // Validate password length - if (password.length < 8) { - return res.status(400).json({ - success: false, - msg: "Password must be at least 8 characters", - }); - } - - // Get userDbService from app.locals - const userDbService = req.app.locals.userDbService; - if (!userDbService) { - console.error("[UserController] userDbService not found in app.locals"); - return res.status(500).json({ - success: false, - msg: "Internal server error", - }); - } - - // Attempt registration - const result = await userDbService.register( - { email, password, name, firstname, lastname }, - { - jwtSecret: config.jwt.secret, - expiresIn: config.jwt.expiresIn, - defaultTeamId: 1, // Default to team 1 for local dev - } - ); - - console.log( - `[UserController] register: User ${email} registered successfully` - ); - - // Return success response - res.status(201).json({ - success: true, - token: result.token, - email: result.email, - name: result.name, - firstname: result.firstname, - lastname: result.lastname, - current_team_id: result.current_team_id, - create_time: result.created_at, - }); - } catch (err: unknown) { - const error = err as { message?: string; code?: string }; - console.error("[UserController] register error:", error.message); - - // Handle specific error codes - if (error.code === "EMAIL_EXISTS") { - return res.status(409).json({ - success: false, - msg: "Email already registered", - }); - } - - // Generic error - return res.status(500).json({ - success: false, - msg: "Registration failed. Please try again.", - }); - } -}); - -/** - * GET /user/profile - * - * Get current user profile. - * Requires authentication. - */ -router.get("/profile", async (req: Request, res: Response) => { - try { - const authHeader = req.headers.authorization; - if (!authHeader) { - return res.status(401).json({ - success: false, - msg: "No token provided", - }); - } - - const userDbService = req.app.locals.userDbService; - const user = await userDbService.findByToken(extractToken(authHeader)); - - if (!user) { - return res.status(401).json({ - success: false, - msg: "Invalid token", - }); - } - - // Return in format expected by frontend - res.json({ - data: { - firstname: user.firstname || "", - lastname: user.lastname || "", - email: user.email, - company_name: user.company_name || null, - profile_img_url: user.avatar_url || null, - roleId: user.role_id || 1, - user_id: String(user.id), - team_id: String(user.current_team_id || 1), - roles: user.roles || ["user"], - }, - }); - } catch (err: unknown) { - const error = err as { message?: string }; - console.error("[UserController] /profile error:", error.message); - res.status(500).json({ - success: false, - msg: "Failed to get user profile", - }); - } -}); - -/** - * PUT /user/profile - * - * Update current user profile. - * Requires authentication. - */ -router.put("/profile", async (req: Request, res: Response) => { - try { - const authHeader = req.headers.authorization; - if (!authHeader) { - return res.status(401).json({ - success: false, - msg: "No token provided", - }); - } - - const userDbService = req.app.locals.userDbService; - const user = await userDbService.findByToken(extractToken(authHeader)); - - if (!user) { - return res.status(401).json({ - success: false, - msg: "Invalid token", - }); - } - - const { firstname, lastname } = req.body; - - // Update user profile (basic implementation) - if (userDbService.updateProfile) { - await userDbService.updateProfile(user.id, { firstname, lastname }); - } - - res.json({ message: "Profile updated successfully" }); - } catch (err: unknown) { - const error = err as { message?: string }; - console.error("[UserController] PUT /profile error:", error.message); - res.status(500).json({ - success: false, - msg: "Failed to update profile", - }); - } -}); - -/** - * GET /user/me - * - * Get current user info from token. - * Requires authentication. - */ -router.get("/me", async (req: Request, res: Response) => { - try { - const authHeader = req.headers.authorization; - if (!authHeader) { - return res.status(401).json({ - success: false, - msg: "No token provided", - }); - } - - const userDbService = req.app.locals.userDbService; - const user = await userDbService.findByToken(extractToken(authHeader)); - - if (!user) { - return res.status(401).json({ - success: false, - msg: "Invalid token", - }); - } - - res.json({ - success: true, - user: { - id: user.id, - email: user.email, - name: user.name, - firstname: user.firstname, - lastname: user.lastname, - current_team_id: user.current_team_id, - avatar_url: user.avatar_url, - }, - }); - } catch (err: unknown) { - const error = err as { message?: string }; - console.error("[UserController] /me error:", error.message); - res.status(500).json({ - success: false, - msg: "Failed to get user info", - }); - } -}); - -/** - * GET /user/get-dev-tokens - * - * Get all developer API tokens for the current user. - * Requires authentication. - */ -router.get("/get-dev-tokens", async (req: Request, res: Response) => { - try { - const authHeader = req.headers.authorization; - if (!authHeader) { - return res.status(401).json({ - success: false, - msg: "No token provided", - }); - } - - const userDbService = req.app.locals.userDbService; - const user = await userDbService.findByToken(extractToken(authHeader)); - - if (!user) { - return res.status(401).json({ - success: false, - msg: "Invalid token", - }); - } - - const tokens = await userDbService.getDevTokens(user); - - res.json({ - success: true, - data: tokens, - }); - } catch (err: unknown) { - const error = err as { message?: string }; - console.error("[UserController] /get-dev-tokens error:", error.message); - res.status(500).json({ - success: false, - msg: "Failed to get API tokens", - }); - } -}); - -/** - * POST /user/generate-dev-token - * - * Generate a new developer API token. - * Requires authentication. - */ -router.post("/generate-dev-token", async (req: Request, res: Response) => { - try { - const authHeader = req.headers.authorization; - if (!authHeader) { - return res.status(401).json({ - success: false, - msg: "No token provided", - }); - } - - const userDbService = req.app.locals.userDbService; - const user = await userDbService.findByToken(extractToken(authHeader)); - - if (!user) { - return res.status(401).json({ - success: false, - msg: "Invalid token", - }); - } - - const { label, ttl } = req.body; - - const tokenResult = await userDbService.generateDevToken(user, { - label, - ttl, - jwtSecret: config.jwt.secret, - }); - - console.log( - `[UserController] generate-dev-token: Created token for user ${user.id}` - ); - - res.status(201).json({ - success: true, - data: tokenResult, - }); - } catch (err: unknown) { - const error = err as { message?: string }; - console.error("[UserController] /generate-dev-token error:", error.message); - res.status(500).json({ - success: false, - msg: "Failed to generate API token", - }); - } -}); - -// ============================================================================= -// UI Settings Endpoints -// ============================================================================= - -/** - * Default UI settings for new users - */ -const DEFAULT_UI_SETTINGS = { - sidebarCollapsed: false, - performanceDashboardTimeRange: "today", -}; - -/** - * GET /user/settings - * - * Get user UI settings from preferences column. - * Returns defaults if no settings exist. - */ -router.get("/settings", async (req: Request, res: Response) => { - try { - const authHeader = req.headers.authorization; - if (!authHeader) { - return res.status(401).json({ - success: false, - msg: "No token provided", - }); - } - - const userDbService = req.app.locals.userDbService; - const user = await userDbService.findByToken(extractToken(authHeader)); - - if (!user) { - return res.status(401).json({ - success: false, - msg: "Invalid token", - }); - } - - // Extract UI settings from preferences, merge with defaults - const preferences = user.preferences || {}; - const uiSettings = { - sidebarCollapsed: - preferences.sidebarCollapsed ?? DEFAULT_UI_SETTINGS.sidebarCollapsed, - performanceDashboardTimeRange: - preferences.performanceDashboardTimeRange ?? - DEFAULT_UI_SETTINGS.performanceDashboardTimeRange, - }; - - res.json({ - success: true, - data: uiSettings, - }); - } catch (err: unknown) { - const error = err as { message?: string }; - console.error("[UserController] GET /settings error:", error.message); - res.status(500).json({ - success: false, - msg: "Failed to get settings", - }); - } -}); - -/** - * PUT /user/settings - * - * Update user UI settings in preferences column. - * Supports partial updates - merges with existing preferences. - */ -router.put("/settings", async (req: Request, res: Response) => { - try { - const authHeader = req.headers.authorization; - if (!authHeader) { - return res.status(401).json({ - success: false, - msg: "No token provided", - }); - } - - const userDbService = req.app.locals.userDbService; - const user = await userDbService.findByToken(extractToken(authHeader)); - - if (!user) { - return res.status(401).json({ - success: false, - msg: "Invalid token", - }); - } - - const { sidebarCollapsed, performanceDashboardTimeRange } = req.body; - - // Build update object with only provided fields - const updates: Record = {}; - if (typeof sidebarCollapsed === "boolean") { - updates.sidebarCollapsed = sidebarCollapsed; - } - if (performanceDashboardTimeRange !== undefined) { - updates.performanceDashboardTimeRange = performanceDashboardTimeRange; - } - - // Merge with existing preferences - const currentPreferences = user.preferences || {}; - const newPreferences = { ...currentPreferences, ...updates }; - - // Update in database - use pgPool for Postgres, mysqlPool for MySQL - const pgPool = req.app.locals.pgPool; - const mysqlPool = req.app.locals.mysqlPool; - - if (pgPool) { - // PostgreSQL - use JSONB - await pgPool.query( - "UPDATE users SET preferences = $1, updated_at = NOW() WHERE id = $2", - [JSON.stringify(newPreferences), user.id] - ); - } else if (mysqlPool) { - // MySQL - use JSON column - await mysqlPool.query( - "UPDATE user SET preferences = ?, updated_at = NOW() WHERE id = ?", - [JSON.stringify(newPreferences), user.id] - ); - } else { - console.warn( - "[UserController] PUT /settings: No database pool available, settings not persisted" - ); - } - - // Return updated settings - const uiSettings = { - sidebarCollapsed: - newPreferences.sidebarCollapsed ?? DEFAULT_UI_SETTINGS.sidebarCollapsed, - performanceDashboardTimeRange: - newPreferences.performanceDashboardTimeRange ?? - DEFAULT_UI_SETTINGS.performanceDashboardTimeRange, - }; - - res.json({ - success: true, - data: uiSettings, - }); - } catch (err: unknown) { - const error = err as { message?: string }; - console.error("[UserController] PUT /settings error:", error.message); - res.status(500).json({ - success: false, - msg: "Failed to update settings", - }); - } -}); - -export default router; diff --git a/hive/src/index.ts b/hive/src/index.ts deleted file mode 100644 index 41b9e0e5..00000000 --- a/hive/src/index.ts +++ /dev/null @@ -1,120 +0,0 @@ -/** - * Aden Hive - DevTool Backend Entry Point - * - * LLM observability and control plane service. - */ - -import "dotenv/config"; - -import http from "http"; -import { MongoClient } from "mongodb"; -import app from "./app"; -import config from "./config"; -import { initializeSockets, setUserDbService } from "./sockets/control.socket"; - -const PORT = process.env.PORT || 4000; - -// Declare globals for MongoDB (used by services) -// eslint-disable-next-line no-var -declare global { - // eslint-disable-next-line no-var - var _ACHO_MG_DB: MongoClient; - // eslint-disable-next-line no-var - var _ACHO_MDB_CONFIG: { ERP_DBNAME: string; DBNAME: string }; - // eslint-disable-next-line no-var - var _ACHO_MDB_COLLECTIONS: { - ADEN_CONTROL_POLICIES: string; - ADEN_CONTROL_CONTENT: string; - LLM_PRICING: string; - }; -} - -/** - * Initialize MongoDB connection - */ -async function initMongoDB(): Promise { - if (!config.mongodb.url) { - console.warn( - "[MongoDB] No MONGODB_URL configured, skipping MongoDB initialization" - ); - return; - } - - try { - const client = new MongoClient(config.mongodb.url); - await client.connect(); - - // Set global MongoDB client and config - global._ACHO_MG_DB = client; - global._ACHO_MDB_CONFIG = { - ERP_DBNAME: config.mongodb.erpDbName, - DBNAME: config.mongodb.dbName, - }; - global._ACHO_MDB_COLLECTIONS = { - ADEN_CONTROL_POLICIES: "aden_control_policies", - ADEN_CONTROL_CONTENT: "aden_control_content", - LLM_PRICING: "llm_pricing", - }; - - console.log("[MongoDB] Connected successfully"); - } catch (error) { - console.error("[MongoDB] Connection error:", error); - throw error; - } -} - -// Create HTTP server -const server = http.createServer(app); - -/** - * Start the server - */ -async function start(): Promise { - // Initialize MongoDB - await initMongoDB(); - - // Pass userDbService to socket layer for JWT verification - if (app.locals.userDbService) { - setUserDbService(app.locals.userDbService, config.jwt.secret); - } - - // Initialize WebSockets - const { controlEmitter } = await initializeSockets(server); - - // Make control emitter available for policy updates - app.locals.controlEmitter = controlEmitter; - console.log("[Aden Hive] WebSocket initialized"); - - // Start server - server.listen(PORT, () => { - console.log(`[Aden Hive] Server running on port ${PORT}`); - console.log( - `[Aden Hive] Environment: ${process.env.NODE_ENV || "development"}` - ); - }); -} - -// Start the application -start().catch((error) => { - console.error("[Aden Hive] Failed to start:", error); - process.exit(1); -}); - -// Graceful shutdown -process.on("SIGTERM", () => { - console.log("[Aden Hive] SIGTERM received, shutting down gracefully"); - server.close(() => { - console.log("[Aden Hive] Server closed"); - process.exit(0); - }); -}); - -process.on("SIGINT", () => { - console.log("[Aden Hive] SIGINT received, shutting down gracefully"); - server.close(() => { - console.log("[Aden Hive] Server closed"); - process.exit(0); - }); -}); - -export default server; diff --git a/hive/src/mcp/index.ts b/hive/src/mcp/index.ts deleted file mode 100644 index 97674d46..00000000 --- a/hive/src/mcp/index.ts +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Aden Hive MCP Server - * - * Model Context Protocol server for LLM governance. - * Exposes 19 tools: - * - * Budget Tools (6): - * - hive_budget_get, hive_budget_reset, hive_budget_validate - * - hive_budget_rule_create, hive_budget_rule_update, hive_budget_rule_delete - * - * Agent Status Tools (3): - * - hive_agents_list, hive_agent_health_check, hive_agents_summary - * - * Analytics Tools (5): - * - hive_analytics_wide, hive_analytics_narrow, hive_insights - * - hive_metrics, hive_logs - * - * Policy Tools (5): - * - hive_policies_list, hive_policy_get, hive_policy_create - * - hive_policy_update, hive_policy_clear - * - * Usage: - * import { createMcpRouter } from './mcp'; - * app.use('/mcp', createMcpRouter(getControlEmitter)); - */ - -// Server creation -export { createHiveMcpServer, TOOL_CATALOG } from "./server"; -export type { HiveMcpServerOptions } from "./server"; - -// HTTP transport -export { - createMcpRouter, - getActiveMcpSessionCount, - getTeamMcpSessions, -} from "./transport/http"; - -// API client for direct usage -export { createApiClient } from "./utils/api-client"; -export type { ApiClient, ApiContext } from "./utils/api-client"; - -// Response helpers -export { - createSuccessResponse, - createErrorResponse, - handleToolError, -} from "./utils/response-helpers"; - -// Schema helpers -export { - idSchema, - dateSchema, - dateTimeSchema, - amountSchema, - budgetTypeSchema, - limitActionSchema, - analyticsWindowSchema, - validationContextSchema, - budgetAlertSchema, - budgetNotificationsSchema, - paginationSchema, -} from "./utils/schema-helpers"; diff --git a/hive/src/mcp/server.ts b/hive/src/mcp/server.ts deleted file mode 100644 index cc2e6d6e..00000000 --- a/hive/src/mcp/server.ts +++ /dev/null @@ -1,90 +0,0 @@ -/** - * Aden Hive MCP Server - * - * MCP server with tools for: - * - Cost control (budget management) - * - Agent status (fleet monitoring) - * - Analytics (insights, metrics, logs) - * - Policy management - */ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { createApiClient, type ApiContext } from "./utils/api-client"; -import { registerBudgetTools } from "./tools/budget"; -import { registerAgentTools, type ControlEmitter } from "./tools/agents"; -import { registerAnalyticsTools } from "./tools/analytics"; -import { registerPolicyTools } from "./tools/policies"; - -export interface HiveMcpServerOptions { - context: ApiContext; - getControlEmitter?: () => ControlEmitter | undefined; -} - -/** - * Create and configure the Aden Hive MCP server - */ -export function createHiveMcpServer(options: HiveMcpServerOptions): McpServer { - const { context, getControlEmitter } = options; - - // Create MCP server - const server = new McpServer({ - name: "aden-hive", - version: "1.0.0", - }); - - // Create API client bound to team context - const api = createApiClient(context); - - // Register all tool categories - registerBudgetTools(server, api); - registerAgentTools(server, api, getControlEmitter || (() => undefined)); - registerAnalyticsTools(server, api); - registerPolicyTools(server, api); - - console.log( - `[MCP] Aden Hive server created with ${19} tools for team ${context.teamId}` - ); - - return server; -} - -/** - * Tool categories and counts for reference - */ -export const TOOL_CATALOG = { - budget: { - count: 6, - tools: [ - "hive_budget_get", - "hive_budget_reset", - "hive_budget_validate", - "hive_budget_rule_create", - "hive_budget_rule_update", - "hive_budget_rule_delete", - ], - }, - agents: { - count: 3, - tools: ["hive_agents_list", "hive_agent_health_check", "hive_agents_summary"], - }, - analytics: { - count: 5, - tools: [ - "hive_analytics_wide", - "hive_analytics_narrow", - "hive_insights", - "hive_metrics", - "hive_logs", - ], - }, - policies: { - count: 5, - tools: [ - "hive_policies_list", - "hive_policy_get", - "hive_policy_create", - "hive_policy_update", - "hive_policy_clear", - ], - }, - total: 19, -}; diff --git a/hive/src/mcp/tools/agents.ts b/hive/src/mcp/tools/agents.ts deleted file mode 100644 index a6bbe36f..00000000 --- a/hive/src/mcp/tools/agents.ts +++ /dev/null @@ -1,197 +0,0 @@ -/** - * Agent Status MCP Tools - * - * Tools for monitoring connected SDK agent instances: - * - hive_agents_list: List all connected SDK instances - * - hive_agent_health_check: Check health of specific agent - * - hive_agents_summary: Get fleet health overview - */ -import { z } from "zod"; -import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import type { ApiClient } from "../utils/api-client"; -import { - createSuccessResponse, - handleToolError, -} from "../utils/response-helpers"; - -export interface ControlEmitter { - getConnectedCount: (teamId: string) => number; - getConnectedInstances: (teamId: string) => Array<{ - instance_id: string; - agent?: string; - policy_id?: string | null; - connected_at: string; - last_heartbeat: string; - }>; -} - -export function registerAgentTools( - server: McpServer, - api: ApiClient, - getControlEmitter: () => ControlEmitter | undefined -) { - // ==================== hive_agents_list ==================== - server.tool( - "hive_agents_list", - "Get list of all connected SDK agent instances with health status and connection details", - { - includeMetrics: z - .boolean() - .default(false) - .describe("Include per-agent metrics (connection duration, heartbeat lag)"), - }, - async (params) => { - try { - const controlEmitter = getControlEmitter(); - const result = api.agents.getList(controlEmitter); - - if (params.includeMetrics && result.instances) { - const now = Date.now(); - const enrichedInstances = (result.instances as Array<{ - instance_id: string; - connected_at: string; - last_heartbeat: string; - }>).map((instance) => { - const connectedAt = new Date(instance.connected_at).getTime(); - const lastHeartbeat = new Date(instance.last_heartbeat).getTime(); - - return { - ...instance, - metrics: { - connection_duration_ms: now - connectedAt, - connection_duration_seconds: Math.round((now - connectedAt) / 1000), - heartbeat_lag_ms: now - lastHeartbeat, - heartbeat_lag_seconds: Math.round((now - lastHeartbeat) / 1000), - is_healthy: now - lastHeartbeat < 60000, - }, - }; - }); - - return createSuccessResponse({ - ...result, - instances: enrichedInstances, - }); - } - - return createSuccessResponse(result); - } catch (error) { - return handleToolError(error, "hive_agents_list"); - } - } - ); - - // ==================== hive_agent_health_check ==================== - server.tool( - "hive_agent_health_check", - "Check health of a specific agent by instance ID or agent name. Returns health status, last heartbeat, and connection details.", - { - instanceId: z - .string() - .optional() - .describe("SDK instance ID to check"), - agentName: z - .string() - .optional() - .describe("Agent name to filter (returns all instances with this name)"), - }, - async (params) => { - try { - if (!params.instanceId && !params.agentName) { - return handleToolError( - new Error("Either instanceId or agentName is required"), - "hive_agent_health_check" - ); - } - - const controlEmitter = getControlEmitter(); - const result = api.agents.getList(controlEmitter); - - if (!result.instances || result.instances.length === 0) { - return createSuccessResponse({ - found: false, - message: "No agents connected", - query: params, - }); - } - - const now = Date.now(); - const STALE_THRESHOLD_MS = 60000; // 60 seconds - - // Filter instances based on query - const instances = (result.instances as Array<{ - instance_id: string; - agent?: string; - connected_at: string; - last_heartbeat: string; - }>).filter((instance) => { - if (params.instanceId && instance.instance_id === params.instanceId) { - return true; - } - if (params.agentName && instance.agent === params.agentName) { - return true; - } - return false; - }); - - if (instances.length === 0) { - return createSuccessResponse({ - found: false, - message: params.instanceId - ? `Instance ${params.instanceId} not found` - : `No instances found for agent ${params.agentName}`, - query: params, - total_connected: result.count, - }); - } - - // Enrich with health status - const healthResults = instances.map((instance) => { - const lastHeartbeat = new Date(instance.last_heartbeat).getTime(); - const heartbeatLag = now - lastHeartbeat; - const isHealthy = heartbeatLag < STALE_THRESHOLD_MS; - - return { - instance_id: instance.instance_id, - agent_name: instance.agent || "unknown", - status: isHealthy ? "healthy" : "unhealthy", - last_heartbeat: instance.last_heartbeat, - last_heartbeat_ago_seconds: Math.round(heartbeatLag / 1000), - connected_at: instance.connected_at, - connection_duration_seconds: Math.round( - (now - new Date(instance.connected_at).getTime()) / 1000 - ), - health_threshold_seconds: STALE_THRESHOLD_MS / 1000, - }; - }); - - return createSuccessResponse({ - found: true, - count: healthResults.length, - instances: healthResults, - summary: { - healthy: healthResults.filter((h) => h.status === "healthy").length, - unhealthy: healthResults.filter((h) => h.status === "unhealthy").length, - }, - }); - } catch (error) { - return handleToolError(error, "hive_agent_health_check"); - } - } - ); - - // ==================== hive_agents_summary ==================== - server.tool( - "hive_agents_summary", - "Get summary of agent fleet health: total active, healthy count, unhealthy count, and breakdown by agent name", - {}, - async () => { - try { - const controlEmitter = getControlEmitter(); - const result = api.agents.getSummary(controlEmitter); - return createSuccessResponse(result); - } catch (error) { - return handleToolError(error, "hive_agents_summary"); - } - } - ); -} diff --git a/hive/src/mcp/tools/analytics.ts b/hive/src/mcp/tools/analytics.ts deleted file mode 100644 index 7dc38dab..00000000 --- a/hive/src/mcp/tools/analytics.ts +++ /dev/null @@ -1,169 +0,0 @@ -/** - * Analytics MCP Tools - * - * Tools for querying analytics and insights: - * - hive_analytics_wide: Dashboard analytics with daily resolution - * - hive_analytics_narrow: Hourly analytics for today - * - hive_insights: Actionable insights and anomalies - * - hive_metrics: Summary metrics with period-over-period change - * - hive_logs: Raw or aggregated event logs - */ -import { z } from "zod"; -import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import type { ApiClient } from "../utils/api-client"; -import { - createSuccessResponse, - handleToolError, -} from "../utils/response-helpers"; -import { analyticsWindowSchema, dateTimeSchema } from "../utils/schema-helpers"; - -export function registerAnalyticsTools(server: McpServer, api: ApiClient) { - // ==================== hive_analytics_wide ==================== - server.tool( - "hive_analytics_wide", - "Get dashboard analytics with daily resolution. Use for trend analysis over days/weeks/months. Returns volume, cost, tokens, and performance data points by day.", - { - window: analyticsWindowSchema.describe( - "Time window: all_time, this_month, this_week, last_2_weeks, or today" - ), - }, - async (params) => { - try { - const result = await api.analytics.getWide(params.window); - return createSuccessResponse(result); - } catch (error) { - return handleToolError(error, "hive_analytics_wide"); - } - } - ); - - // ==================== hive_analytics_narrow ==================== - server.tool( - "hive_analytics_narrow", - "Get hourly analytics for today. Use for intraday monitoring, detecting recent spikes, and real-time cost tracking.", - {}, - async () => { - try { - const result = await api.analytics.getNarrow(); - return createSuccessResponse(result); - } catch (error) { - return handleToolError(error, "hive_analytics_narrow"); - } - } - ); - - // ==================== hive_insights ==================== - server.tool( - "hive_insights", - "Get actionable insights: cost spikes, anomalies, trends, cache efficiency, and recommendations. Critical for autonomous monitoring and cost control.", - { - days: z - .number() - .min(1) - .max(90) - .default(30) - .describe("Analysis period in days (1-90)"), - }, - async (params) => { - try { - const result = await api.analytics.getInsights(params.days); - return createSuccessResponse(result); - } catch (error) { - return handleToolError(error, "hive_insights"); - } - } - ); - - // ==================== hive_metrics ==================== - server.tool( - "hive_metrics", - "Get summary metrics with period-over-period percentage change. Good for quick health checks and comparing current vs previous period.", - { - days: z - .number() - .min(1) - .max(365) - .default(30) - .describe("Period in days for current window and comparison"), - }, - async (params) => { - try { - const result = await api.analytics.getMetrics(params.days); - return createSuccessResponse(result); - } catch (error) { - return handleToolError(error, "hive_metrics"); - } - } - ); - - // ==================== hive_logs ==================== - server.tool( - "hive_logs", - "Query raw or aggregated event logs. Use for investigation, drill-down, and detailed analysis. Supports grouping by model, agent, or provider.", - { - start: dateTimeSchema.describe("Start time (ISO 8601 format)"), - end: dateTimeSchema.describe("End time (ISO 8601 format)"), - groupBy: z - .enum(["model", "agent", "provider", "model,agent", "model,provider"]) - .optional() - .describe( - "Aggregate by field(s). If not specified, returns raw log rows." - ), - limit: z - .number() - .min(1) - .max(5000) - .default(500) - .describe("Maximum rows/aggregations to return"), - offset: z - .number() - .min(0) - .default(0) - .describe("Number of rows to skip (for pagination)"), - }, - async (params) => { - try { - // Validate date range - const startDate = new Date(params.start); - const endDate = new Date(params.end); - - if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) { - return handleToolError( - new Error("Invalid date format. Use ISO 8601 format."), - "hive_logs" - ); - } - - if (endDate < startDate) { - return handleToolError( - new Error("End date must be after start date"), - "hive_logs" - ); - } - - // Warn if range is too large - const rangeDays = - (endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24); - if (rangeDays > 90 && !params.groupBy) { - console.warn( - `[MCP] hive_logs: Large date range (${rangeDays.toFixed( - 0 - )} days) without aggregation may be slow` - ); - } - - const result = await api.analytics.getLogs({ - start: params.start, - end: params.end, - groupBy: params.groupBy, - limit: params.limit, - offset: params.offset, - }); - - return createSuccessResponse(result); - } catch (error) { - return handleToolError(error, "hive_logs"); - } - } - ); -} diff --git a/hive/src/mcp/tools/budget.ts b/hive/src/mcp/tools/budget.ts deleted file mode 100644 index 06c4f3d3..00000000 --- a/hive/src/mcp/tools/budget.ts +++ /dev/null @@ -1,335 +0,0 @@ -/** - * Budget MCP Tools - * - * Tools for cost control and budget management: - * - hive_budget_get: Get budget status - * - hive_budget_reset: Reset budget spend - * - hive_budget_validate: Validate request against budgets - * - hive_budget_rule_create: Create budget rule - * - hive_budget_rule_update: Update budget rule - * - hive_budget_rule_delete: Delete budget rule - */ -import { z } from "zod"; -import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import type { ApiClient } from "../utils/api-client"; -import { - createSuccessResponse, - handleToolError, -} from "../utils/response-helpers"; -import { - idSchema, - budgetTypeSchema, - limitActionSchema, - validationContextSchema, - budgetAlertSchema, - budgetNotificationsSchema, -} from "../utils/schema-helpers"; - -export function registerBudgetTools(server: McpServer, api: ApiClient) { - // ==================== hive_budget_get ==================== - server.tool( - "hive_budget_get", - "Get budget status including spend, limit, burn rate, and projected spend for a specific budget ID", - { - budgetId: idSchema.describe("Budget ID to query"), - }, - async (params) => { - try { - const result = await api.budget.getStatus(params.budgetId); - return createSuccessResponse(result); - } catch (error) { - return handleToolError(error, "hive_budget_get"); - } - } - ); - - // ==================== hive_budget_reset ==================== - server.tool( - "hive_budget_reset", - "Reset a budget spend counter to zero. Use when starting new billing cycle or after resolving overage.", - { - budgetId: idSchema.describe("Budget ID to reset"), - reason: z - .string() - .optional() - .describe("Reason for reset (for audit trail)"), - }, - async (params) => { - try { - const result = await api.budget.reset(params.budgetId); - return createSuccessResponse({ - ...result, - reason: params.reason, - reset_at: new Date().toISOString(), - }); - } catch (error) { - return handleToolError(error, "hive_budget_reset"); - } - } - ); - - // ==================== hive_budget_validate ==================== - server.tool( - "hive_budget_validate", - "Validate if a request should be allowed based on budget constraints. Returns allow/throttle/degrade/block decision with authoritative spend data.", - { - budgetId: z - .string() - .optional() - .describe("Specific budget ID to validate against"), - estimatedCost: z - .number() - .min(0) - .describe("Estimated cost of the request in USD"), - context: validationContextSchema - .optional() - .describe( - "Context for multi-budget matching (agent, tenant_id, customer_id, feature, tags)" - ), - localSpend: z - .number() - .optional() - .describe("Local spend tracked by SDK (for drift detection)"), - }, - async (params) => { - try { - const result = await api.budget.validate({ - budgetId: params.budgetId, - estimatedCost: params.estimatedCost, - context: params.context, - localSpend: params.localSpend, - }); - return createSuccessResponse(result); - } catch (error) { - return handleToolError(error, "hive_budget_validate"); - } - } - ); - - // ==================== hive_budget_rule_create ==================== - server.tool( - "hive_budget_rule_create", - "Create a new budget rule within a policy. Budget rules define spending limits and actions when exceeded.", - { - policyId: z - .string() - .default("default") - .describe('Policy ID (use "default" for default policy)'), - id: idSchema.describe("Unique budget rule ID"), - name: z.string().min(1).describe("Human-readable budget name"), - type: budgetTypeSchema.describe("Budget scope type"), - limit: z.number().min(0).describe("Budget limit in USD"), - limitAction: limitActionSchema - .default("kill") - .describe("Action when limit exceeded"), - degradeToModel: z - .string() - .optional() - .describe('Target model for degradation (required when limitAction is "degrade")'), - degradeToProvider: z - .string() - .optional() - .describe('Target provider for degradation (required when limitAction is "degrade")'), - tags: z - .array(z.string()) - .optional() - .describe('Tags for tag-type budgets (required when type is "tag")'), - alerts: z - .array(budgetAlertSchema) - .default([ - { threshold: 80, enabled: true }, - { threshold: 95, enabled: true }, - ]) - .describe("Alert thresholds as percentage of limit"), - notifications: budgetNotificationsSchema - .default({ - inApp: true, - email: false, - emailRecipients: [], - webhook: false, - }) - .describe("Notification settings"), - }, - async (params) => { - try { - // Validate degradation requirements - if (params.limitAction === "degrade") { - if (!params.degradeToModel || !params.degradeToProvider) { - return handleToolError( - new Error( - "degradeToModel and degradeToProvider are required when limitAction is 'degrade'" - ), - "hive_budget_rule_create" - ); - } - } - - // Validate tag requirements - if (params.type === "tag") { - if (!params.tags || params.tags.length === 0) { - return handleToolError( - new Error("tags array is required when type is 'tag'"), - "hive_budget_rule_create" - ); - } - } - - const result = await api.policy.addBudgetRule(params.policyId, { - id: params.id, - name: params.name, - type: params.type, - limit: params.limit, - spent: 0, - limitAction: params.limitAction, - degradeToModel: params.degradeToModel, - degradeToProvider: params.degradeToProvider, - tags: params.tags, - alerts: params.alerts, - notifications: params.notifications, - }); - - return createSuccessResponse({ - success: true, - budget_id: params.id, - policy: result, - }); - } catch (error) { - return handleToolError(error, "hive_budget_rule_create"); - } - } - ); - - // ==================== hive_budget_rule_update ==================== - server.tool( - "hive_budget_rule_update", - "Update an existing budget rule. Only provided fields will be updated.", - { - policyId: z - .string() - .default("default") - .describe('Policy ID (use "default" for default policy)'), - budgetId: idSchema.describe("Budget rule ID to update"), - name: z.string().optional().describe("New budget name"), - limit: z.number().min(0).optional().describe("New budget limit in USD"), - limitAction: limitActionSchema.optional().describe("New action when limit exceeded"), - degradeToModel: z - .string() - .optional() - .describe("New target model for degradation"), - degradeToProvider: z - .string() - .optional() - .describe("New target provider for degradation"), - alerts: z - .array(budgetAlertSchema) - .optional() - .describe("New alert thresholds"), - }, - async (params) => { - try { - // Get current policy to find and update the budget - const policy = await api.policy.get(params.policyId); - - if (!policy) { - return handleToolError( - new Error("Policy not found"), - "hive_budget_rule_update" - ); - } - - const budgets = policy.budgets || []; - const budgetIndex = budgets.findIndex( - (b: { id: string }) => b.id === params.budgetId - ); - - if (budgetIndex === -1) { - return handleToolError( - new Error(`Budget ${params.budgetId} not found in policy`), - "hive_budget_rule_update" - ); - } - - // Update the budget with new values - const updatedBudget = { - ...budgets[budgetIndex], - ...(params.name && { name: params.name }), - ...(params.limit !== undefined && { limit: params.limit }), - ...(params.limitAction && { limitAction: params.limitAction }), - ...(params.degradeToModel && { degradeToModel: params.degradeToModel }), - ...(params.degradeToProvider && { degradeToProvider: params.degradeToProvider }), - ...(params.alerts && { alerts: params.alerts }), - }; - - budgets[budgetIndex] = updatedBudget; - - const result = await api.policy.update(params.policyId, { budgets }); - - return createSuccessResponse({ - success: true, - budget_id: params.budgetId, - updated_fields: Object.keys(params).filter( - (k) => - k !== "policyId" && - k !== "budgetId" && - params[k as keyof typeof params] !== undefined - ), - policy: result, - }); - } catch (error) { - return handleToolError(error, "hive_budget_rule_update"); - } - } - ); - - // ==================== hive_budget_rule_delete ==================== - server.tool( - "hive_budget_rule_delete", - "Delete a budget rule from a policy", - { - policyId: z - .string() - .default("default") - .describe('Policy ID (use "default" for default policy)'), - budgetId: idSchema.describe("Budget rule ID to delete"), - }, - async (params) => { - try { - // Get current policy to remove the budget - const policy = await api.policy.get(params.policyId); - - if (!policy) { - return handleToolError( - new Error("Policy not found"), - "hive_budget_rule_delete" - ); - } - - const budgets = policy.budgets || []; - const budgetIndex = budgets.findIndex( - (b: { id: string }) => b.id === params.budgetId - ); - - if (budgetIndex === -1) { - return handleToolError( - new Error(`Budget ${params.budgetId} not found in policy`), - "hive_budget_rule_delete" - ); - } - - // Remove the budget - budgets.splice(budgetIndex, 1); - - const result = await api.policy.update(params.policyId, { budgets }); - - return createSuccessResponse({ - success: true, - deleted_budget_id: params.budgetId, - remaining_budgets: budgets.length, - policy: result, - }); - } catch (error) { - return handleToolError(error, "hive_budget_rule_delete"); - } - } - ); -} diff --git a/hive/src/mcp/tools/policies.ts b/hive/src/mcp/tools/policies.ts deleted file mode 100644 index 06001642..00000000 --- a/hive/src/mcp/tools/policies.ts +++ /dev/null @@ -1,224 +0,0 @@ -/** - * Policy Management MCP Tools - * - * Tools for managing control policies: - * - hive_policies_list: List all policies - * - hive_policy_get: Get specific policy with rules - * - hive_policy_create: Create new policy - * - hive_policy_update: Update policy - * - hive_policy_clear: Clear all rules from policy - */ -import { z } from "zod"; -import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import type { ApiClient } from "../utils/api-client"; -import { - createSuccessResponse, - handleToolError, -} from "../utils/response-helpers"; - -export function registerPolicyTools(server: McpServer, api: ApiClient) { - // ==================== hive_policies_list ==================== - server.tool( - "hive_policies_list", - "List all policies for the team. Returns policy IDs, names, and rule counts.", - { - limit: z - .number() - .min(1) - .max(100) - .default(100) - .describe("Maximum policies to return"), - offset: z - .number() - .min(0) - .default(0) - .describe("Number of policies to skip"), - }, - async (params) => { - try { - const policies = await api.policy.list({ - limit: params.limit, - offset: params.offset, - }); - - // Summarize policies - const summary = (policies as unknown as Array<{ - _id?: string; - id?: string; - name?: string; - budgets?: unknown[]; - throttles?: unknown[]; - blocks?: unknown[]; - degradations?: unknown[]; - }>).map((p) => ({ - id: p._id || p.id || "unknown", - name: p.name || "Unnamed Policy", - rule_counts: { - budgets: p.budgets?.length || 0, - throttles: p.throttles?.length || 0, - blocks: p.blocks?.length || 0, - degradations: p.degradations?.length || 0, - }, - })); - - return createSuccessResponse({ - count: policies.length, - policies: summary, - }); - } catch (error) { - return handleToolError(error, "hive_policies_list"); - } - } - ); - - // ==================== hive_policy_get ==================== - server.tool( - "hive_policy_get", - 'Get a specific policy with all rules (budgets, throttles, blocks, degradations). Use "default" to get the team\'s default policy.', - { - policyId: z - .string() - .default("default") - .describe('Policy ID or "default" for team default'), - }, - async (params) => { - try { - const policy = await api.policy.get(params.policyId); - - if (!policy) { - return handleToolError( - new Error(`Policy ${params.policyId} not found`), - "hive_policy_get" - ); - } - - return createSuccessResponse(policy); - } catch (error) { - return handleToolError(error, "hive_policy_get"); - } - } - ); - - // ==================== hive_policy_create ==================== - server.tool( - "hive_policy_create", - "Create a new policy for the team. New policies start empty (no rules).", - { - name: z.string().min(1).describe("Policy name"), - }, - async (params) => { - try { - const policy = await api.policy.create(params.name); - - return createSuccessResponse({ - success: true, - message: "Policy created", - policy, - }); - } catch (error) { - return handleToolError(error, "hive_policy_create"); - } - } - ); - - // ==================== hive_policy_update ==================== - server.tool( - "hive_policy_update", - "Update a policy's name or replace all rules. For individual rule changes, use budget/throttle/block rule tools.", - { - policyId: z - .string() - .default("default") - .describe('Policy ID or "default" for team default'), - name: z.string().optional().describe("New policy name"), - budgets: z - .array(z.any()) - .optional() - .describe("Complete budgets array (replaces all budgets)"), - throttles: z - .array(z.any()) - .optional() - .describe("Complete throttles array (replaces all throttles)"), - blocks: z - .array(z.any()) - .optional() - .describe("Complete blocks array (replaces all blocks)"), - degradations: z - .array(z.any()) - .optional() - .describe("Complete degradations array (replaces all degradations)"), - }, - async (params) => { - try { - // Only pass defined fields - const updates: { - name?: string; - budgets?: unknown[]; - throttles?: unknown[]; - blocks?: unknown[]; - degradations?: unknown[]; - } = {}; - - if (params.name !== undefined) updates.name = params.name; - if (params.budgets !== undefined) updates.budgets = params.budgets; - if (params.throttles !== undefined) updates.throttles = params.throttles; - if (params.blocks !== undefined) updates.blocks = params.blocks; - if (params.degradations !== undefined) - updates.degradations = params.degradations; - - if (Object.keys(updates).length === 0) { - return handleToolError( - new Error("No updates provided"), - "hive_policy_update" - ); - } - - const policy = await api.policy.update(params.policyId, updates); - - return createSuccessResponse({ - success: true, - updated_fields: Object.keys(updates), - policy, - }); - } catch (error) { - return handleToolError(error, "hive_policy_update"); - } - } - ); - - // ==================== hive_policy_clear ==================== - server.tool( - "hive_policy_clear", - "Clear all rules from a policy (budgets, throttles, blocks, degradations). The policy itself is preserved.", - { - policyId: z - .string() - .default("default") - .describe('Policy ID or "default" for team default'), - confirm: z - .boolean() - .describe("Set to true to confirm clearing all rules"), - }, - async (params) => { - try { - if (!params.confirm) { - return createSuccessResponse({ - warning: - "This will delete ALL rules from the policy. Set confirm=true to proceed.", - policy_id: params.policyId, - }); - } - - const policy = await api.policy.clear(params.policyId); - - return createSuccessResponse({ - success: true, - message: "All rules cleared from policy", - policy, - }); - } catch (error) { - return handleToolError(error, "hive_policy_clear"); - } - } - ); -} diff --git a/hive/src/mcp/transport/http.ts b/hive/src/mcp/transport/http.ts deleted file mode 100644 index fd30f6f5..00000000 --- a/hive/src/mcp/transport/http.ts +++ /dev/null @@ -1,238 +0,0 @@ -/** - * HTTP/SSE Transport for Aden Hive MCP Server - * - * Provides HTTP-based transport for autonomous LLM agents: - * - GET /mcp - SSE stream for server-to-client messages - * - POST /mcp/message - Client-to-server messages - */ -import express, { Request, Response, Router } from "express"; -import passport from "passport"; -import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; -import { createHiveMcpServer, type HiveMcpServerOptions } from "../server"; -import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; - -interface AuthenticatedRequest extends Request { - user?: { - id: string; - current_team_id: string; - }; -} - -interface McpSession { - server: McpServer; - transport: SSEServerTransport; - teamId: string; - userId: string; - createdAt: Date; -} - -// Active MCP sessions by session ID -const sessions = new Map(); - -/** - * Create MCP HTTP router - */ -export function createMcpRouter( - getControlEmitter?: HiveMcpServerOptions["getControlEmitter"] -): Router { - const router = express.Router(); - - // All MCP routes require authentication - const authMiddleware = passport.authenticate("jwt", { session: false }); - - /** - * GET /mcp - * SSE endpoint - establishes persistent connection for server-to-client messages - */ - router.get( - "/", - authMiddleware, - async (req: AuthenticatedRequest, res: Response) => { - const teamId = req.user?.current_team_id; - const userId = req.user?.id; - - if (!teamId) { - res.status(401).json({ error: "Team ID required" }); - return; - } - - // Set custom headers (SSE headers are set by the transport) - res.setHeader("X-Accel-Buffering", "no"); - - // Create MCP server for this session - const server = createHiveMcpServer({ - context: { - teamId, - userId, - }, - getControlEmitter, - }); - - // Create SSE transport - it generates its own sessionId internally - const transport = new SSEServerTransport("/mcp/message", res); - - // Get the SDK's session ID (used in query params for POST requests) - const sdkSessionId = transport.sessionId; - - console.log(`[MCP] New SSE connection: session=${sdkSessionId}, team=${teamId}`); - - // Store session by the SDK's session ID - sessions.set(sdkSessionId, { - server, - transport, - teamId, - userId: userId || "unknown", - createdAt: new Date(), - }); - - // Connect server to transport - await server.connect(transport); - - // Handle client disconnect - req.on("close", () => { - console.log(`[MCP] SSE connection closed: session=${sdkSessionId}`); - sessions.delete(sdkSessionId); - server.close(); - }); - } - ); - - /** - * POST /mcp/message - * Receives messages from client - */ - // Note: Do NOT use express.json() here - handlePostMessage reads the raw body stream - router.post( - "/message", - authMiddleware, - async (req: AuthenticatedRequest, res: Response) => { - // SDK passes session ID as query parameter: /mcp/message?sessionId=xxx - const sessionId = req.query.sessionId as string; - - if (!sessionId) { - res.status(400).json({ error: "sessionId query parameter required" }); - return; - } - - const session = sessions.get(sessionId); - - if (!session) { - res.status(404).json({ - error: "Session not found", - hint: "Establish SSE connection first via GET /mcp", - }); - return; - } - - // Verify team ID matches - if (session.teamId !== req.user?.current_team_id) { - res.status(403).json({ error: "Session team mismatch" }); - return; - } - - try { - // Handle the message through the transport - await session.transport.handlePostMessage(req, res); - } catch (error) { - console.error(`[MCP] Error handling message:`, error); - res.status(500).json({ - error: "Failed to process message", - details: error instanceof Error ? error.message : "Unknown error", - }); - } - } - ); - - /** - * GET /mcp/sessions - * List active MCP sessions (admin/debug endpoint) - */ - router.get( - "/sessions", - authMiddleware, - (req: AuthenticatedRequest, res: Response) => { - const teamId = req.user?.current_team_id; - - // Only show sessions for the requesting team - const teamSessions = Array.from(sessions.entries()) - .filter(([, session]) => session.teamId === teamId) - .map(([id, session]) => ({ - session_id: id, - team_id: session.teamId, - user_id: session.userId, - created_at: session.createdAt.toISOString(), - age_seconds: Math.round( - (Date.now() - session.createdAt.getTime()) / 1000 - ), - })); - - res.json({ - count: teamSessions.length, - sessions: teamSessions, - }); - } - ); - - /** - * DELETE /mcp/sessions/:sessionId - * Close a specific MCP session - */ - router.delete( - "/sessions/:sessionId", - authMiddleware, - (req: AuthenticatedRequest, res: Response) => { - const { sessionId } = req.params; - const teamId = req.user?.current_team_id; - - const session = sessions.get(sessionId); - - if (!session) { - res.status(404).json({ error: "Session not found" }); - return; - } - - // Verify team ID matches - if (session.teamId !== teamId) { - res.status(403).json({ error: "Cannot close session from another team" }); - return; - } - - // Close the session - session.server.close(); - sessions.delete(sessionId); - - res.json({ - success: true, - message: `Session ${sessionId} closed`, - }); - } - ); - - /** - * GET /mcp/health - * Health check endpoint - */ - router.get("/health", (_req: Request, res: Response) => { - res.json({ - status: "healthy", - active_sessions: sessions.size, - timestamp: new Date().toISOString(), - }); - }); - - return router; -} - -/** - * Get count of active MCP sessions - */ -export function getActiveMcpSessionCount(): number { - return sessions.size; -} - -/** - * Get active sessions for a specific team - */ -export function getTeamMcpSessions(teamId: string): McpSession[] { - return Array.from(sessions.values()).filter((s) => s.teamId === teamId); -} diff --git a/hive/src/mcp/utils/api-client.ts b/hive/src/mcp/utils/api-client.ts deleted file mode 100644 index 04953c58..00000000 --- a/hive/src/mcp/utils/api-client.ts +++ /dev/null @@ -1,610 +0,0 @@ -/** - * Internal API client for MCP tools - * - * This client makes direct calls to the control and tsdb services - * rather than HTTP calls, since we're running inside the same process. - */ -import controlService from "../../services/control/control_service"; -import * as tsdbService from "../../services/tsdb/tsdb_service"; -import { buildAnalytics } from "../../services/tsdb/analytics_service"; -import { getTeamPool, buildSchemaName } from "../../services/tsdb/team_context"; -import type { PoolClient } from "pg"; - -export interface ApiContext { - teamId: string; - userId?: string; -} - -export interface BudgetRule { - id: string; - name?: string; - type?: string; - tags?: string[]; - limit?: number; - spent?: number; - limitAction?: string; - degradeToModel?: string; - degradeToProvider?: string; - alerts?: Array<{ threshold: number; enabled: boolean }>; - notifications?: { - inApp: boolean; - email: boolean; - emailRecipients: string[]; - webhook: boolean; - }; -} - -export interface ValidationContext { - agent?: string; - tenant_id?: string; - customer_id?: string; - feature?: string; - tags?: string[]; -} - -/** - * Create an API client bound to a specific team context - */ -export function createApiClient(context: ApiContext) { - const userContext = { - user_id: context.userId || "mcp-agent", - team_id: context.teamId, - }; - - return { - // ==================== Budget Operations ==================== - budget: { - /** - * Get budget status by ID - */ - async getStatus(budgetId: string) { - return controlService.getBudgetStatus(budgetId); - }, - - /** - * Reset budget spend to zero - */ - async reset(budgetId: string) { - await controlService.resetBudget(budgetId); - return { success: true, id: budgetId }; - }, - - /** - * Validate a request against budgets - */ - async validate(params: { - budgetId?: string; - estimatedCost: number; - context?: ValidationContext; - localSpend?: number; - }) { - // Get the policy to validate against - const policy = await controlService.getPolicy( - context.teamId, - null, - userContext - ); - - if (!policy) { - return { - allowed: true, - action: "allow", - reason: "No policy found", - budgets_checked: [], - }; - } - - // Multi-budget validation using context - if (params.context && typeof params.context === "object") { - const matchingBudgets = controlService.findMatchingBudgetsForContext( - policy.budgets || [], - params.context - ); - - if (matchingBudgets.length === 0) { - return { - allowed: true, - action: "allow", - reason: "No budgets match the provided context", - authoritative_spend: 0, - budget_limit: 0, - usage_percent: 0, - projected_percent: 0, - budgets_checked: [], - }; - } - - return controlService.validateMultipleBudgets( - matchingBudgets, - params.estimatedCost, - params.localSpend - ); - } - - // Single budget validation - if (params.budgetId) { - const budget = policy.budgets?.find( - (b: { id: string }) => b.id === params.budgetId - ); - if (!budget) { - return { - allowed: true, - action: "allow", - reason: "Budget not found in policy", - budgets_checked: [], - }; - } - - return controlService.validateMultipleBudgets( - [budget], - params.estimatedCost, - params.localSpend - ); - } - - return { - allowed: true, - action: "allow", - reason: "No budget_id or context provided", - budgets_checked: [], - }; - }, - }, - - // ==================== Policy Operations ==================== - policy: { - /** - * Get all policies for the team - */ - async list(pagination?: { limit?: number; offset?: number }) { - return controlService.getPoliciesByTeam(context.teamId, { - limit: pagination?.limit || 100, - offset: pagination?.offset || 0, - }); - }, - - /** - * Get a specific policy - */ - async get(policyId: string | null) { - const resolvedId = - policyId === "default" || !policyId ? null : policyId; - return controlService.getPolicy(context.teamId, resolvedId, userContext); - }, - - /** - * Create a new policy - */ - async create(name: string) { - return controlService.updatePolicy( - context.teamId, - null, - { name }, - userContext - ); - }, - - /** - * Update a policy - */ - async update( - policyId: string | null, - updates: { - name?: string; - budgets?: unknown[]; - throttles?: unknown[]; - blocks?: unknown[]; - degradations?: unknown[]; - } - ) { - const resolvedId = - policyId === "default" || !policyId ? null : policyId; - return controlService.updatePolicy( - context.teamId, - resolvedId, - updates as Record, - userContext - ); - }, - - /** - * Clear all rules from a policy - */ - async clear(policyId: string | null) { - const resolvedId = - policyId === "default" || !policyId ? null : policyId; - return controlService.clearPolicy( - context.teamId, - resolvedId, - userContext - ); - }, - - /** - * Delete a policy - */ - async delete(policyId: string) { - return controlService.deletePolicy( - context.teamId, - policyId, - userContext - ); - }, - - /** - * Add a budget rule to a policy - */ - async addBudgetRule(policyId: string | null, rule: BudgetRule) { - const resolvedId = - policyId === "default" || !policyId ? null : policyId; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return controlService.addBudgetRule( - context.teamId, - resolvedId, - rule as any, - userContext - ); - }, - }, - - // ==================== Analytics Operations ==================== - analytics: { - /** - * Get wide analytics (daily resolution) - */ - async getWide(window: string = "this_month") { - const pool = await getTeamPool(context.teamId); - const schema = buildSchemaName(context.teamId); - const client = await pool.connect(); - - try { - await client.query(`SET search_path TO ${schema}, public`); - await tsdbService.ensureSchema(client); - - return buildAnalytics({ - windowLabel: window, - client, - resolution: "day", - }); - } finally { - client.release(); - } - }, - - /** - * Get narrow analytics (hourly resolution for today) - */ - async getNarrow() { - const pool = await getTeamPool(context.teamId); - const schema = buildSchemaName(context.teamId); - const client = await pool.connect(); - - try { - await client.query(`SET search_path TO ${schema}, public`); - await tsdbService.ensureSchema(client); - - return buildAnalytics({ - windowLabel: "today", - client, - resolution: "hour", - }); - } finally { - client.release(); - } - }, - - /** - * Get actionable insights - */ - async getInsights(days: number = 30) { - const pool = await getTeamPool(context.teamId); - const schema = buildSchemaName(context.teamId); - const client = await pool.connect(); - - try { - await client.query(`SET search_path TO ${schema}, public`); - await tsdbService.ensureSchema(client); - - // Use the insights generation logic from tsdb controller - // This is a simplified version - full implementation would mirror the controller - return this._generateInsights(client, days); - } finally { - client.release(); - } - }, - - /** - * Get summary metrics with period-over-period change - */ - async getMetrics(days: number = 30) { - const pool = await getTeamPool(context.teamId); - const schema = buildSchemaName(context.teamId); - const client = await pool.connect(); - - try { - await client.query(`SET search_path TO ${schema}, public`); - await tsdbService.ensureSchema(client); - - return this._generateMetrics(client, days); - } finally { - client.release(); - } - }, - - /** - * Get logs (raw or aggregated) - */ - async getLogs(params: { - start: string; - end: string; - groupBy?: string; - limit?: number; - offset?: number; - }) { - const pool = await getTeamPool(context.teamId); - const schema = buildSchemaName(context.teamId); - const client = await pool.connect(); - - try { - await client.query(`SET search_path TO ${schema}, public`); - await tsdbService.ensureSchema(client); - - return this._getLogs(client, params); - } finally { - client.release(); - } - }, - - // Internal helper methods - async _generateInsights(client: PoolClient, days: number) { - // Simplified insights generation - const now = new Date(); - const periodStart = new Date(now); - periodStart.setDate(periodStart.getDate() - days); - - const { rows } = await client.query( - ` - SELECT - COUNT(*) as total_requests, - COALESCE(SUM(cost_total), 0) as total_cost, - COALESCE(AVG(latency_ms), 0) as avg_latency - FROM llm_events - WHERE "timestamp" >= $1 AND "timestamp" <= $2 - `, - [periodStart.toISOString(), now.toISOString()] - ); - - const stats = rows[0]; - const insights = []; - - // Basic usage summary insight - insights.push({ - id: "usage_snapshot", - severity: "summary", - title: "Period usage summary", - description: `${parseInt(stats.total_requests).toLocaleString()} requests totaling $${parseFloat(stats.total_cost).toFixed(2)} over the last ${days} days.`, - metric: { - total_requests: parseInt(stats.total_requests), - total_cost: parseFloat(stats.total_cost), - }, - }); - - return { - period: { days, start: periodStart.toISOString(), end: now.toISOString() }, - insights, - summary: { - total: insights.length, - critical: insights.filter((i) => i.severity === "critical").length, - warning: insights.filter((i) => i.severity === "warning").length, - info: insights.filter((i) => i.severity === "info").length, - }, - }; - }, - - async _generateMetrics(client: PoolClient, days: number) { - const now = new Date(); - const currentStart = new Date(now); - currentStart.setDate(currentStart.getDate() - days); - - const { rows } = await client.query( - ` - SELECT - COUNT(*) as total_requests, - COUNT(DISTINCT trace_id) as unique_traces, - COALESCE(SUM(usage_input_tokens), 0) as total_input_tokens, - COALESCE(SUM(usage_output_tokens), 0) as total_output_tokens, - COALESCE(SUM(cost_total), 0) as total_cost, - COALESCE(AVG(latency_ms), 0) as avg_latency_ms - FROM llm_events - WHERE "timestamp" >= $1 AND "timestamp" <= $2 - `, - [currentStart.toISOString(), now.toISOString()] - ); - - const stats = rows[0]; - - return { - period: { days, start: currentStart.toISOString(), end: now.toISOString() }, - volume: { - total_requests: parseInt(stats.total_requests), - unique_traces: parseInt(stats.unique_traces), - }, - tokens: { - total_input_tokens: parseInt(stats.total_input_tokens), - total_output_tokens: parseInt(stats.total_output_tokens), - }, - cost: { - total_cost: parseFloat(stats.total_cost), - }, - performance: { - avg_latency_ms: parseFloat(stats.avg_latency_ms), - }, - }; - }, - - async _getLogs( - client: PoolClient, - params: { - start: string; - end: string; - groupBy?: string; - limit?: number; - offset?: number; - } - ) { - const { start, end, groupBy, limit = 500, offset = 0 } = params; - - if (groupBy) { - const validFields = ["model", "agent", "provider"]; - const groupFields = groupBy - .split(",") - .map((f) => f.trim()) - .filter((f) => validFields.includes(f)); - - if (groupFields.length > 0) { - const selectFields = groupFields.join(", "); - const { rows } = await client.query( - ` - SELECT - ${selectFields}, - COUNT(*) as request_count, - COALESCE(SUM(cost_total), 0) as total_cost - FROM llm_events - WHERE "timestamp" >= $1 AND "timestamp" <= $2 - GROUP BY ${selectFields} - ORDER BY total_cost DESC - LIMIT $3 OFFSET $4 - `, - [start, end, limit, offset] - ); - - return { - window: { start, end }, - group_by: groupFields, - count: rows.length, - aggregations: rows, - }; - } - } - - // Raw logs - const { rows } = await client.query( - ` - SELECT * - FROM llm_events - WHERE "timestamp" >= $1 AND "timestamp" <= $2 - ORDER BY "timestamp" DESC - LIMIT $3 OFFSET $4 - `, - [start, end, limit, offset] - ); - - return { - window: { start, end }, - count: rows.length, - rows, - }; - }, - }, - - // ==================== Agent Status Operations ==================== - agents: { - /** - * Get connected agent instances - * This requires access to the controlEmitter which is set on the Express app - */ - getList(controlEmitter?: { - getConnectedCount: (teamId: string) => number; - getConnectedInstances: (teamId: string) => unknown[]; - }) { - if (!controlEmitter) { - return { - active: false, - count: 0, - instances: [], - timestamp: new Date().toISOString(), - error: "WebSocket not initialized", - }; - } - - const count = controlEmitter.getConnectedCount(context.teamId); - const instances = controlEmitter.getConnectedInstances(context.teamId); - - return { - active: count > 0, - count, - instances, - timestamp: new Date().toISOString(), - }; - }, - - /** - * Get agent fleet summary - */ - getSummary(controlEmitter?: { - getConnectedCount: (teamId: string) => number; - getConnectedInstances: (teamId: string) => Array<{ - instance_id: string; - agent?: string; - last_heartbeat: string; - }>; - }) { - if (!controlEmitter) { - return { - total_active: 0, - healthy: 0, - unhealthy: 0, - stale_connections: 0, - by_agent_name: {}, - timestamp: new Date().toISOString(), - error: "WebSocket not initialized", - }; - } - - const instances = controlEmitter.getConnectedInstances(context.teamId); - const now = Date.now(); - const STALE_THRESHOLD_MS = 60000; // 60 seconds - - let healthy = 0; - let unhealthy = 0; - const byAgentName: Record< - string, - { count: number; healthy: number; unhealthy: number } - > = {}; - - for (const instance of instances) { - const lastHeartbeat = new Date(instance.last_heartbeat).getTime(); - const isHealthy = now - lastHeartbeat < STALE_THRESHOLD_MS; - - if (isHealthy) { - healthy++; - } else { - unhealthy++; - } - - const agentName = instance.agent || "unknown"; - if (!byAgentName[agentName]) { - byAgentName[agentName] = { count: 0, healthy: 0, unhealthy: 0 }; - } - byAgentName[agentName].count++; - if (isHealthy) { - byAgentName[agentName].healthy++; - } else { - byAgentName[agentName].unhealthy++; - } - } - - return { - total_active: instances.length, - healthy, - unhealthy, - stale_connections: unhealthy, - by_agent_name: byAgentName, - timestamp: new Date().toISOString(), - }; - }, - }, - }; -} - -export type ApiClient = ReturnType; diff --git a/hive/src/mcp/utils/response-helpers.ts b/hive/src/mcp/utils/response-helpers.ts deleted file mode 100644 index 1ef37fa4..00000000 --- a/hive/src/mcp/utils/response-helpers.ts +++ /dev/null @@ -1,65 +0,0 @@ -/** - * MCP response formatting helpers - */ - -export interface MCPResponse { - [key: string]: unknown; - content: Array<{ - type: "text"; - text: string; - }>; - isError?: boolean; -} - -/** - * Create a successful MCP response - */ -export function createSuccessResponse(data: unknown): MCPResponse { - return { - content: [ - { - type: "text", - text: JSON.stringify(data, null, 2), - }, - ], - }; -} - -/** - * Create an error MCP response - */ -export function createErrorResponse( - error: string, - details?: unknown -): MCPResponse { - const errorData = { - error, - ...(details && { details }), - }; - - return { - content: [ - { - type: "text", - text: JSON.stringify(errorData, null, 2), - }, - ], - isError: true, - }; -} - -/** - * Handle tool errors consistently - */ -export function handleToolError(error: unknown, toolName: string): MCPResponse { - console.error(`[MCP] Error in ${toolName}:`, error); - - if (error instanceof Error) { - return createErrorResponse(error.message, { - tool: toolName, - stack: process.env.NODE_ENV === "development" ? error.stack : undefined, - }); - } - - return createErrorResponse("Unknown error occurred", { tool: toolName }); -} diff --git a/hive/src/mcp/utils/schema-helpers.ts b/hive/src/mcp/utils/schema-helpers.ts deleted file mode 100644 index 3a6b1d38..00000000 --- a/hive/src/mcp/utils/schema-helpers.ts +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Zod schema helpers for MCP tools - */ -import { z } from "zod"; - -// Basic types -export const idSchema = z.string().min(1).describe("Unique identifier"); -export const dateSchema = z - .string() - .regex(/^\d{4}-\d{2}-\d{2}$/) - .describe("Date in YYYY-MM-DD format"); -export const dateTimeSchema = z - .string() - .datetime() - .describe("ISO 8601 datetime string"); -export const amountSchema = z.number().describe("Monetary amount in USD"); - -// Budget types -export const budgetTypeSchema = z - .enum(["global", "agent", "tenant", "customer", "feature", "tag"]) - .describe("Type of budget scope"); - -export const limitActionSchema = z - .enum(["kill", "throttle", "degrade"]) - .describe("Action when budget limit exceeded"); - -// Pagination -export const paginationSchema = z.object({ - limit: z - .number() - .min(1) - .max(1000) - .default(100) - .describe("Max items to return"), - offset: z.number().min(0).default(0).describe("Number of items to skip"), -}); - -// Analytics window -export const analyticsWindowSchema = z - .enum(["all_time", "this_month", "this_week", "last_2_weeks", "today"]) - .default("this_month") - .describe("Time window for analytics data"); - -// Budget validation context -export const validationContextSchema = z - .object({ - agent: z.string().optional().describe("Agent name for agent-type budgets"), - tenant_id: z - .string() - .optional() - .describe("Tenant ID for tenant-type budgets"), - customer_id: z - .string() - .optional() - .describe("Customer ID for customer-type budgets"), - feature: z.string().optional().describe("Feature name for feature-type budgets"), - tags: z.array(z.string()).optional().describe("Tags for tag-type budgets"), - }) - .describe("Context for multi-budget matching"); - -// Budget alert configuration -export const budgetAlertSchema = z.object({ - threshold: z - .number() - .min(0) - .max(100) - .describe("Alert threshold as percentage of limit"), - enabled: z.boolean().describe("Whether alert is enabled"), -}); - -// Budget notifications configuration -export const budgetNotificationsSchema = z.object({ - inApp: z.boolean().default(true).describe("Enable in-app notifications"), - email: z.boolean().default(false).describe("Enable email notifications"), - emailRecipients: z - .array(z.string().email()) - .default([]) - .describe("Email recipients"), - webhook: z.boolean().default(false).describe("Enable webhook notifications"), -}); diff --git a/hive/src/middleware/error-handler.middleware.ts b/hive/src/middleware/error-handler.middleware.ts deleted file mode 100644 index 6add4754..00000000 --- a/hive/src/middleware/error-handler.middleware.ts +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Global Error Handler Middleware - * - * Handles all errors and sends consistent JSON responses. - */ - -import { Request, Response, NextFunction } from 'express'; - -interface HttpError extends Error { - status?: number; - statusCode?: number; -} - -/** - * Error handler middleware - * @param {Error} err - Error object - * @param {Object} req - Express request - * @param {Object} res - Express response - * @param {Function} next - Next middleware - */ -// eslint-disable-next-line @typescript-eslint/no-unused-vars -function errorHandler(err: HttpError, req: Request, res: Response, _next: NextFunction): void { - // Log error - console.error('[Error]', { - message: err.message, - status: err.status || err.statusCode || 500, - path: req.path, - method: req.method, - stack: process.env.NODE_ENV === 'development' ? err.stack : undefined, - }); - - // Get status code - const status = err.status || err.statusCode || 500; - - // Send error response - res.status(status).json({ - error: err.name || 'Error', - message: err.message || 'An unexpected error occurred', - status, - ...(process.env.NODE_ENV === 'development' && { stack: err.stack }), - }); -} - -export { errorHandler }; diff --git a/hive/src/routes.ts b/hive/src/routes.ts deleted file mode 100644 index eaed4283..00000000 --- a/hive/src/routes.ts +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Route Definitions - * - * Central route registration for all DevTool APIs. - */ - -import express from 'express'; - -// Controllers -import tsdbController from './controllers/tsdb.controller'; -import controlController from './controllers/control.controller'; -import quickstartController from './controllers/quickstart.controller'; -import userController from './controllers/user.controller'; -import iamController from './controllers/iam.controller'; - -const router = express.Router(); - -// ============================================================================= -// User Routes - Authentication and user management -// ============================================================================= -router.use('/user', userController); - -// ============================================================================= -// IAM Routes - Identity and Access Management -// ============================================================================= -router.use('/iam', iamController); - -// ============================================================================= -// TSDB Routes - Time Series Database for LLM metrics -// ============================================================================= -router.use('/tsdb', tsdbController); - -// ============================================================================= -// Control Routes - SDK control plane -// ============================================================================= -router.use('/v1/control', controlController); - -// ============================================================================= -// Quickstart Routes - SDK documentation generation -// ============================================================================= -router.use('/quickstart', quickstartController); - -export default router; diff --git a/hive/src/services/control/control_service.ts b/hive/src/services/control/control_service.ts deleted file mode 100644 index a7ee69a3..00000000 --- a/hive/src/services/control/control_service.ts +++ /dev/null @@ -1,2067 +0,0 @@ -/** - * Aden Control Service - * - * Manages control policies and events for the Aden SDK. - * Provides policy management, event storage, and budget tracking. - */ - -import { randomUUID } from "crypto"; -import * as tsdbService from "../tsdb/tsdb_service"; -import pricingService from "../tsdb/pricing_service"; -import { getTeamPool, buildSchemaName } from "../tsdb/team_context"; -// TODO: Integrate mail service from @aden/administration -// import mailService from "../mail_service/mail_service"; -import llmEventBatcher from "./llm_event_batcher"; -import { registerHttpAgent } from "./control_sockets"; - -// In-memory budget tracking (could be moved to Redis for distributed tracking) -// Map: budget_id -> { spent: number, lastReset: Date } -const budgetTracker = new Map(); - -// Notification cooldown tracking to prevent spam -// Map: "budget_id:alert_type:threshold" -> timestamp -const notificationCooldowns = new Map(); -const NOTIFICATION_COOLDOWN_MS = 15 * 60 * 1000; // 15 minutes - -interface MongoCollection { - find: (query: Record) => { toArray: () => Promise; sort: (sort: Record) => { skip: (n: number) => { limit: (n: number) => { toArray: () => Promise } } } }; - findOne: (query: Record) => Promise; - insertOne: (doc: Record) => Promise; - updateOne: (query: Record, update: Record, options?: Record) => Promise; - deleteOne: (query: Record) => Promise<{ deletedCount: number }>; -} - -declare const _ACHO_MG_DB: { db: (name: string) => { collection: (name: string) => MongoCollection } }; -declare const _ACHO_MDB_CONFIG: { ERP_DBNAME: string }; -declare const _ACHO_MDB_COLLECTIONS: { ADEN_CONTROL_POLICIES: string; ADEN_CONTROL_CONTENT: string }; -declare const _GLOBAL_CONST: { ARP_URL: string }; - -interface UserContext { - user_id?: string; - team_id?: string | number; -} - -interface Budget { - id: string; - name: string; - type: string; - limit: number; - spent?: number; - limitAction?: string; - degradeToModel?: string; - degradeToProvider?: string; - tagCategory?: string; - tags?: string[]; - alerts?: Array<{ threshold: number; enabled: boolean }>; - notifications?: { - email?: boolean; - emailRecipients?: string[]; - webhook?: boolean; - webhookUrl?: string; - }; - analytics?: { - burnRate: number; - projectedSpend: number; - daysUntilLimit: number | null; - usagePercent: number; - projectedPercent: number; - status: string; - period: { - daysInMonth: number; - daysElapsed: number; - daysRemaining: number; - startOfMonth: string; - endOfMonth: string; - }; - }; -} - -interface Policy { - id: string; - team_id: string | number; - name: string; - version: string; - budgets: Budget[]; - throttles: unknown[]; - blocks: unknown[]; - degradations: unknown[]; - alerts: unknown[]; - created_at: string; - updated_at: string; - created_by?: string; - updated_by?: string; -} - -interface ContentCapture { - system_prompt?: string; - messages?: unknown[]; - tools?: unknown[]; - params?: Record; - response_content?: string; - finish_reason?: string; - choice_count?: number; - has_images?: boolean; - image_urls?: string[]; -} - -interface MetricData { - provider?: string; - model?: string; - total_tokens?: number; - input_tokens?: number; - output_tokens?: number; - cached_tokens?: number; - reasoning_tokens?: number; - agent?: string; - metadata?: Record; - trace_id?: string; - span_id?: string; - request_id?: string; - call_sequence?: number; - stream?: boolean; - agent_stack?: string[]; - latency_ms?: number; - content_capture?: ContentCapture; -} - -interface Event { - event_type: string; - timestamp?: string; - trace_id?: string; - data?: MetricData; - action?: string; - original_model?: string; - provider?: string; - reason?: string; - budget_id?: string; - policy_id?: string; - agent?: string; - agent_name?: string; - sdk_instance_id?: string; - status?: string; - requests_since_last?: number; - message?: string; - stack?: string; -} - -/** - * Get the MongoDB collection for control policies - * @returns MongoDB collection - */ -function getPolicyCollection(): MongoCollection { - return _ACHO_MG_DB - .db(_ACHO_MDB_CONFIG.ERP_DBNAME) - .collection(_ACHO_MDB_COLLECTIONS.ADEN_CONTROL_POLICIES); -} - -/** - * Calculate actual spend and burn rate analytics for a budget from TSDB data - * Uses hybrid CA + base table approach for lowest latency - */ -async function calculateBudgetAnalyticsFromTsdb(teamId: string | number, budget: Budget): Promise<{ - spent: number; - burnRate: number; - projectedSpend: number; - daysUntilLimit: number | null; - usagePercent: number; - projectedPercent: number; - status: string; - source: string; - period: { - daysInMonth: number; - daysElapsed: number; - daysRemaining: number; - startOfMonth: string; - endOfMonth: string; - }; -}> { - const now = new Date(); - const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1); - const endOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0); - const daysInMonth = endOfMonth.getDate(); - const daysElapsed = Math.max( - 1, - Math.floor((now.getTime() - startOfMonth.getTime()) / (1000 * 60 * 60 * 24)) + 1 - ); - const daysRemaining = daysInMonth - daysElapsed + 1; - - // Today's midnight for CA vs base table split - const todayMidnight = new Date(); - todayMidnight.setUTCHours(0, 0, 0, 0); - - try { - const pool = await getTeamPool(teamId); - const schema = buildSchemaName(teamId); - const client = await pool.connect(); - - try { - // Explicitly set search_path to team schema before querying - await client.query(`SET search_path TO ${schema}, public`); - await tsdbService.ensureSchema(client); - - let spent = 0; - const usedCA = false; - - // Determine which CA to use based on budget type - // Note: CA (continuous aggregates) are disabled for now because: - // 1. Team-specific schemas don't have CA tables populated - // 2. CA tables need to be refreshed periodically - // TODO: Enable CA once aggregation is set up per-team - const canUseGlobalCA = false; // Disabled: CA not populated in team schemas - const canUseAgentCA = false; // Disabled: agent may be in metadata->>'agent' - - // --- Query CA for historical data (before today) --- - if (startOfMonth < todayMidnight) { - if (canUseGlobalCA) { - // Use daily CA for global budgets - try { - const caSql = ` - SELECT COALESCE(SUM(cost_total), 0) as total_cost - FROM llm_events_daily_ca - WHERE bucket >= $1 AND bucket < $2 - `; - const caResult = await client.query(caSql, [ - startOfMonth.toISOString(), - todayMidnight.toISOString(), - ]); - spent += parseFloat(caResult.rows[0]?.total_cost) || 0; - } catch (caErr) { - // CA not available, will fall back to base table - } - } else if (canUseAgentCA) { - // Use agent CA for agent budgets - try { - const caSql = ` - SELECT COALESCE(SUM(cost_total), 0) as total_cost - FROM llm_events_daily_by_agent_ca - WHERE bucket >= $1 AND bucket < $2 AND agent = $3 - `; - const caResult = await client.query(caSql, [ - startOfMonth.toISOString(), - todayMidnight.toISOString(), - budget.name, - ]); - spent += parseFloat(caResult.rows[0]?.total_cost) || 0; - } catch (caErr) { - // CA not available, will fall back to base table - } - } - } - - // --- Query base table for today's data (always) + historical if CA failed --- - const baseTableStart = usedCA ? todayMidnight : startOfMonth; - - const conditions = [`team_id = $1`, `"timestamp" >= $2`, `"timestamp" <= $3`]; - const values: unknown[] = [String(teamId), baseTableStart, now]; - const paramIndex = 4; - - // Apply budget-specific filter based on budget type - const budgetFilter = getBudgetFilter(budget, paramIndex); - if (budgetFilter) { - conditions.push(budgetFilter.condition); - values.push(budgetFilter.value); - } - - const baseSql = ` - SELECT COALESCE(SUM(cost_total), 0) as total_cost - FROM llm_events - WHERE ${conditions.join(" AND ")} - `; - - console.log(`[Aden Control] Budget analytics query for team ${teamId}, schema ${schema}:`); - console.log(`[Aden Control] SQL: ${baseSql}`); - console.log(`[Aden Control] Values:`, values); - - // Debug: check row count and cost - const countResult = await client.query(`SELECT COUNT(*) as cnt FROM llm_events WHERE team_id = $1`, [String(teamId)]); - console.log(`[Aden Control] Total rows in llm_events for team ${teamId}: ${countResult.rows[0]?.cnt}`); - - // Debug: check total cost regardless of timestamp filter - const debugResult = await client.query(`SELECT SUM(cost_total) as total, MIN("timestamp") as min_ts, MAX("timestamp") as max_ts FROM llm_events WHERE team_id = $1`, [String(teamId)]); - console.log(`[Aden Control] All-time cost: $${debugResult.rows[0]?.total}, timestamps: ${debugResult.rows[0]?.min_ts} to ${debugResult.rows[0]?.max_ts}`); - - const baseResult = await client.query(baseSql, values); - console.log(`[Aden Control] Result:`, baseResult.rows[0]); - - spent += parseFloat(baseResult.rows[0]?.total_cost) || 0; - console.log(`[Aden Control] Total spent for budget ${budget.name}: $${spent}`); - - // Calculate burn rate analytics - const burnRate = daysElapsed > 0 ? spent / daysElapsed : 0; - const projectedSpend = burnRate * daysInMonth; - const remaining = Math.max(0, budget.limit - spent); - const daysUntilLimit = burnRate > 0 ? remaining / burnRate : Infinity; - const usagePercent = budget.limit > 0 ? (spent / budget.limit) * 100 : 0; - const projectedPercent = - budget.limit > 0 ? (projectedSpend / budget.limit) * 100 : 0; - - // Determine status based on projected spend and current usage - let status = "healthy"; - if (usagePercent >= 100) { - status = "exceeded"; - } else if (projectedPercent >= 100 || daysUntilLimit <= daysRemaining) { - status = "at_risk"; - } else if (usagePercent >= 80 || projectedPercent >= 80) { - status = "warning"; - } - - return { - spent, - burnRate, - projectedSpend, - daysUntilLimit: daysUntilLimit === Infinity ? null : daysUntilLimit, - usagePercent, - projectedPercent, - status, - source: usedCA ? "hybrid_ca" : "base_table", - period: { - daysInMonth, - daysElapsed, - daysRemaining, - startOfMonth: startOfMonth.toISOString(), - endOfMonth: endOfMonth.toISOString(), - }, - }; - } finally { - client.release(); - } - } catch (error) { - console.error( - `[Aden Control] Failed to calculate budget analytics from TSDB:`, - (error as Error).message - ); - // Fall back to in-memory tracker with minimal analytics - const tracker = budgetTracker.get(budget.id); - const spent = tracker?.spent ?? budget.spent ?? 0; - const burnRate = daysElapsed > 0 ? spent / daysElapsed : 0; - const projectedSpend = burnRate * daysInMonth; - - return { - spent, - burnRate, - projectedSpend, - daysUntilLimit: burnRate > 0 ? Math.max(0, budget.limit - spent) / burnRate : null, - usagePercent: budget.limit > 0 ? (spent / budget.limit) * 100 : 0, - projectedPercent: budget.limit > 0 ? (projectedSpend / budget.limit) * 100 : 0, - status: "unknown", - source: "fallback", - period: { - daysInMonth, - daysElapsed, - daysRemaining, - startOfMonth: startOfMonth.toISOString(), - endOfMonth: endOfMonth.toISOString(), - }, - }; - } -} - -/** - * Get policy for a team by policy ID - */ -async function getPolicy(teamId: string | number | null, policyId: string | null = null, userContext: UserContext | null = null): Promise { - if (!teamId) { - teamId = userContext?.team_id ?? null; - } - if (!teamId) { - throw new Error("team_id is required to get policy"); - } - - // Use "default" as the actual policy ID when not specified - const actualPolicyId = policyId || "default"; - - const collection = getPolicyCollection(); - let policyDoc = await collection.findOne({ team_id: teamId, id: actualPolicyId }) as Policy & { _id?: unknown } | null; - - if (!policyDoc) { - // Create empty policy with the specified ID - const newPolicy: Policy & { _id?: unknown } = { - id: actualPolicyId, - team_id: teamId, - name: actualPolicyId === "default" ? "Default Policy" : "New Policy", - version: randomUUID().slice(0, 8), - budgets: [], - throttles: [], - blocks: [], - degradations: [], - alerts: [], - created_at: new Date().toISOString(), - updated_at: new Date().toISOString(), - ...(userContext?.user_id && { created_by: userContext.user_id }), - }; - await collection.insertOne(newPolicy as unknown as Record); - policyDoc = newPolicy; - } - - // Remove MongoDB _id from response - const { _id, ...policy } = policyDoc; - - // Enrich budget rules with actual spend and analytics from TSDB - if (policy.budgets && policy.budgets.length > 0) { - policy.budgets = await Promise.all( - policy.budgets.map(async (budget) => { - const analytics = await calculateBudgetAnalyticsFromTsdb(teamId!, budget); - return { - ...budget, - spent: analytics.spent, - analytics: { - burnRate: analytics.burnRate, - projectedSpend: analytics.projectedSpend, - daysUntilLimit: analytics.daysUntilLimit, - usagePercent: analytics.usagePercent, - projectedPercent: analytics.projectedPercent, - status: analytics.status, - period: analytics.period, - }, - }; - }) - ); - } - - return policy as Policy; -} - -/** - * Update policy for a team (or create new if policyId is null) - */ -async function updatePolicy(teamId: string | number | null, policyId: string | null, policyUpdate: Partial, userContext: UserContext | null = null): Promise { - if (!teamId) { - teamId = userContext?.team_id ?? null; - } - if (!teamId) { - throw new Error("team_id is required to update policy"); - } - - // Use "default" as the actual policy ID when not specified - const actualPolicyId = policyId || "default"; - - const collection = getPolicyCollection(); - - const updateFields = { - ...policyUpdate, - version: randomUUID().slice(0, 8), - updated_at: new Date().toISOString(), - ...(userContext?.user_id && { updated_by: userContext.user_id }), - }; - - // Build setOnInsert with only fields NOT in policyUpdate to avoid MongoDB conflicts - // Fields in both $set and $setOnInsert cause "would create a conflict" errors - const defaultName = actualPolicyId === "default" ? "Default Policy" : "New Policy"; - const setOnInsert: Record = { - id: actualPolicyId, - team_id: teamId, - ...(!policyUpdate.name && { name: defaultName }), - ...(!("budgets" in policyUpdate) && { budgets: [] }), - ...(!("throttles" in policyUpdate) && { throttles: [] }), - ...(!("blocks" in policyUpdate) && { blocks: [] }), - ...(!("degradations" in policyUpdate) && { degradations: [] }), - ...(!("alerts" in policyUpdate) && { alerts: [] }), - created_at: new Date().toISOString(), - ...(userContext?.user_id && { created_by: userContext.user_id }), - }; - - await collection.updateOne( - { team_id: teamId, id: actualPolicyId }, - { - $set: updateFields, - $setOnInsert: setOnInsert, - }, - { upsert: true } - ); - - // Return the updated policy - return getPolicy(teamId, actualPolicyId); -} - -/** - * Transform a metric event to TSDB format - */ -function transformMetricToTsdbEvent(event: Event, teamId: string | number, policyId: string | null): Record { - const data = event.data || {}; - const now = new Date(); - // Extract agent - metadata.agent takes precedence over top-level agent - const effectiveAgent = (data.metadata?.agent as string) || data.agent || null; - - // Calculate cost for real-time streaming - const cost = pricingService.calculateCostSync({ - model: data.model || "", - provider: data.provider, - input_tokens: data.input_tokens || 0, - output_tokens: data.output_tokens || 0, - cached_tokens: data.cached_tokens || 0, - }).total; - - return { - timestamp: event.timestamp || now.toISOString(), - team_id: String(teamId), - user_id: (data.metadata?.user_id as string) || null, - trace_id: data.trace_id || event.trace_id || randomUUID(), - span_id: data.span_id || null, - request_id: data.request_id || null, - provider: data.provider || null, - call_sequence: data.call_sequence ?? 0, - model: data.model || "", - stream: Boolean(data.stream), - agent: effectiveAgent, - agent_name: event.agent_name || null, - agent_stack: data.agent_stack || [], - latency_ms: data.latency_ms || null, - usage: { - input_tokens: data.input_tokens || 0, - output_tokens: data.output_tokens || 0, - total_tokens: data.total_tokens || 0, - cached_tokens: data.cached_tokens || 0, - reasoning_tokens: data.reasoning_tokens || 0, - }, - cost_total: cost, - metadata: { - ...data.metadata, - policy_id: policyId, - event_type: event.event_type, - }, - // Layer 0 content capture (if enabled in SDK) - content_capture: data.content_capture || null, - }; -} - -/** - * Process incoming events from SDK - */ -async function processEvents(teamId: string | number | null, policyId: string | null, events: Event[], userContext: UserContext | null = null): Promise { - if (!teamId) { - teamId = userContext?.team_id ?? null; - } - if (!teamId) { - throw new Error("team_id is required to process events"); - } - - const tsdbEvents: Record[] = []; - - for (const event of events) { - // Process specific event types - switch (event.event_type) { - case "metric": - await processMetricEvent(teamId, policyId, event, userContext); - // Transform and collect metric events for TSDB - tsdbEvents.push(transformMetricToTsdbEvent(event, teamId, policyId)); - break; - case "control": - await processControlEvent(teamId, event, policyId); - break; - case "heartbeat": - await processHeartbeatEvent(teamId, policyId, event); - break; - case "error": - await processErrorEvent(teamId, event); - break; - } - } - - // Store metric events in TSDB if we have team context - if (tsdbEvents.length > 0) { - try { - const pool = await getTeamPool(teamId); - const schema = buildSchemaName(teamId); - const client = await pool.connect(); - try { - // Explicitly set search_path to team schema before inserting - await client.query(`CREATE SCHEMA IF NOT EXISTS ${schema}`); - await client.query(`SET search_path TO ${schema}, public`); - await tsdbService.ensureSchema(client); - const result = await tsdbService.upsertEvents(tsdbEvents as unknown[], client); - console.log( - `[Aden Control] Stored ${result.rowsWritten} events in TSDB for team ${teamId}` - ); - - // Push to real-time WebSocket stream - if (result.rowsWritten > 0) { - llmEventBatcher.add(teamId, tsdbEvents as unknown[]); - } - } finally { - client.release(); - } - } catch (error) { - console.error(`[Aden Control] Failed to store events in TSDB:`, (error as Error).message); - } - } -} - -/** - * Process a metric event - update budget tracking - * Updates spend for all matching budgets based on their type - */ -async function processMetricEvent(teamId: string | number, policyId: string | null, event: Event, userContext: UserContext | null = null): Promise { - const metricData = event.data; - if (!metricData) return; - - // Calculate cost from tokens (simplified pricing) - const cost = estimateCost(metricData); - - // Get the policy to find matching budgets - const policy = await getPolicy(teamId, policyId, userContext); - let budgetUpdated = false; - - if (policy.budgets && policy.budgets.length > 0) { - for (const budget of policy.budgets) { - // Determine if this metric applies to this budget based on type - const shouldApply = matchesBudgetType(budget, metricData); - - if (shouldApply) { - const tracker = budgetTracker.get(budget.id) || { - spent: 0, - lastReset: new Date(), - }; - tracker.spent += cost; - budgetTracker.set(budget.id, tracker); - budgetUpdated = true; - - // Check if budget alerts should be triggered - checkBudgetAlerts(budget, tracker.spent, teamId, policyId); - } - } - } - - // Push updated policy with new spend to SDK via WebSocket - if (budgetUpdated && (global as unknown as Record)._ADEN_CONTROL_EMITTER) { - const updatedPolicy = await getPolicy(teamId, policyId); - ((global as unknown as Record)._ADEN_CONTROL_EMITTER as { emitPolicyUpdate: (teamId: string | number, policyId: string | null, policy: Policy) => void }).emitPolicyUpdate(teamId, policyId, updatedPolicy); - } - - console.log( - `[Aden Control] Metric: ${metricData.provider}/${metricData.model} - ${ - metricData.total_tokens - } tokens, $${cost.toFixed(6)}` - ); -} - -/** - * Check if a metric event matches a budget's type criteria - */ -function matchesBudgetType(budget: Budget, metricData: MetricData): boolean { - const metadata = metricData.metadata || {}; - // metadata.agent takes precedence over top-level agent - const effectiveAgent = (metadata.agent as string) || metricData.agent; - - switch (budget.type) { - case "global": - // Global budgets apply to all metrics - return true; - - case "agent": - // Agent budgets apply when agent name matches (from top-level or metadata) - return !!effectiveAgent && budget.name === effectiveAgent; - - case "tenant": - // Tenant budgets apply when tenant_id matches - return !!metadata.tenant_id && budget.name === metadata.tenant_id; - - case "customer": - // Customer budgets apply when customer_id matches - return !!metadata.customer_id && budget.name === metadata.customer_id; - - case "feature": - // Feature budgets apply when feature name matches - return !!metadata.feature && budget.name === metadata.feature; - - case "tag": { - // Tag budgets apply when the tagCategory value matches budget name - if (!budget.tagCategory || !metadata.tags) return false; - const tagValue = (metadata.tags as Record)[budget.tagCategory]; - return !!tagValue && budget.name === tagValue; - } - - default: - return false; - } -} - -/** - * Send budget notifications via configured channels (email, webhook) - * Includes cooldown logic to prevent notification spam. - */ -async function sendBudgetNotifications(budget: Budget, alertData: Record, alertType: string = "threshold"): Promise { - const notifications = budget.notifications; - if (!notifications) { - console.log( - `[Aden Control] No notifications configured for budget ${budget.name} (${budget.id})` - ); - return false; - } - - // Check if any notification channel is enabled - if (!notifications.email && !notifications.webhook) { - console.log( - `[Aden Control] Notifications disabled for budget ${budget.name} (email: ${notifications.email}, webhook: ${notifications.webhook})` - ); - return false; - } - - // Check cooldown to prevent spam - const cooldownKey = `${budget.id}:${alertType}:${ - alertData.threshold || alertData.action || "default" - }`; - const lastSent = notificationCooldowns.get(cooldownKey); - const now = Date.now(); - - if (lastSent && now - lastSent < NOTIFICATION_COOLDOWN_MS) { - console.log( - `[Aden Control] Notification for budget ${budget.name} (${alertType}) skipped - cooldown active` - ); - return false; - } - - const { spent, limit, threshold, action } = alertData as { spent: number; limit: number; threshold?: number; action?: string }; - const spentPercentage = limit > 0 ? ((spent / limit) * 100).toFixed(1) : "0"; - - // Determine alert severity color - const isLimitAction = alertType === "limit_action"; - const alertColor = isLimitAction - ? "#dc2626" - : parseFloat(spentPercentage) >= 90 - ? "#f59e0b" - : "#3b82f6"; - const alertBgColor = isLimitAction - ? "#fef2f2" - : parseFloat(spentPercentage) >= 90 - ? "#fffbeb" - : "#eff6ff"; - - // Build notification content - let title: string, description: string; - if (isLimitAction) { - title = "Budget Limit Triggered"; - description = `The budget ${budget.name} has exceeded its limit and triggered a control action.`; - } else { - title = "Budget Threshold Alert"; - description = `The budget ${budget.name} has reached ${threshold}% of its limit.`; - } - - // Email subject and content prepared for future email notification implementation - const _subject = isLimitAction - ? `[Aden] Budget "${budget.name}" - ${(action || "").toUpperCase()}` - : `[Aden] Budget "${budget.name}" at ${spentPercentage}%`; - - const _htmlContent = ` - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - -
- - ${isLimitAction ? action : "Alert"} - -
-

${title}

-
-

${description}

-
-
- - - - - - - -
- ${spentPercentage}% - of budget used -
-
-
-
-
-
- - - - - - - - - - - ${alertData.model ? ` - - - - ` : ""} -
- - - - - -
Spent$${(spent || 0).toFixed(4)}
-
- - - - - -
Limit$${(limit || 0).toFixed(2)}
-
- - - - - -
Budget Type${budget.type}
-
- - - - - -
Model${alertData.model}
-
-
- - - - -
- - View Cost Control Center - -
-
-

- Sent by Aden Cost Control -

-
-
- -`; - - // Send email notifications - if (notifications.email) { - if (!notifications.emailRecipients?.length) { - console.log( - `[Aden Control] Email enabled but no recipients configured for budget ${budget.name}` - ); - } else { - // TODO: Re-enable when mailService is integrated from @aden/administration - console.log( - `[Aden Control] Email notification skipped (mail service not configured) for budget ${budget.name}` - ); - } - } - - // Send webhook notifications - if (notifications.webhook && notifications.webhookUrl) { - try { - const response = await fetch(notifications.webhookUrl, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - type: "budget_alert", - alert_type: alertType, - budget_id: budget.id, - budget_name: budget.name, - budget_type: budget.type, - ...alertData, - timestamp: new Date().toISOString(), - }), - }); - if (!response.ok) { - console.error(`[Aden Control] Webhook returned ${response.status}`); - } else { - console.log(`[Aden Control] Sent webhook notification for budget ${budget.name}`); - } - } catch (err) { - console.error(`[Aden Control] Failed to send webhook notification:`, (err as Error).message); - } - } - - // Record cooldown timestamp - notificationCooldowns.set(cooldownKey, now); - return true; -} - -/** - * Check budget alerts and emit notifications if thresholds are crossed - */ -async function checkBudgetAlerts(budget: Budget, currentSpent: number, teamId: string | number, policyId: string | null): Promise { - if (!budget.alerts || !budget.alerts.length || !budget.limit) return; - - const spentPercentage = (currentSpent / budget.limit) * 100; - - for (const alert of budget.alerts) { - if (!alert.enabled) continue; - if (spentPercentage >= alert.threshold) { - const alertData = { - budget_id: budget.id, - budget_name: budget.name, - threshold: alert.threshold, - current_percentage: spentPercentage, - spent: currentSpent, - limit: budget.limit, - }; - - // Emit alert event via WebSocket (inApp notification) - if ((global as unknown as Record)._ADEN_CONTROL_EMITTER) { - ((global as unknown as Record)._ADEN_CONTROL_EMITTER as { emitAlert: (teamId: string | number, policyId: string | null, alert: Record) => void }).emitAlert(teamId, policyId, { - ...alertData, - notifications: budget.notifications, - }); - } - - // Send email/webhook notifications - await sendBudgetNotifications(budget, alertData, "threshold"); - } - } -} - -/** - * Estimate cost from metric data using unified pricing service - */ -function estimateCost(metricData: MetricData): number { - const result = pricingService.calculateCostSync({ - model: metricData.model || "", - provider: metricData.provider, - input_tokens: metricData.input_tokens || 0, - output_tokens: metricData.output_tokens || 0, - cached_tokens: metricData.cached_tokens || 0, - }); - return result.total; -} - -/** - * Process a control event - log control decisions and send notifications - */ -async function processControlEvent(teamId: string | number, event: Event, policyId: string | null = null): Promise { - console.log( - `[Aden Control] Control action: ${event.action} on ${event.provider}/${ - event.original_model - }${event.reason ? ` - ${event.reason}` : ""}` - ); - - // Check if this is a budget-related control action - const isBudgetAction = - event.budget_id || - event.reason?.includes("budget") || - ["kill", "throttle", "degrade", "block"].includes(event.action || ""); - - // Fall back to default policy if not provided - const effectivePolicyId = policyId || event.policy_id || "default"; - - console.log( - `[Aden Control] Control event notification check: isBudgetAction=${isBudgetAction}, policyId=${effectivePolicyId}, budget_id=${event.budget_id}` - ); - - if (isBudgetAction) { - try { - // Get the policy to find the budget - const policy = await getPolicy(teamId, effectivePolicyId); - console.log( - `[Aden Control] Found policy with ${policy?.budgets?.length || 0} budgets` - ); - - if (policy?.budgets?.length) { - // Find matching budget by ID or by type/name - let budget = event.budget_id - ? policy.budgets.find((b) => b.id === event.budget_id) - : null; - - // If no budget_id, try to find by context (agent, etc.) - if (!budget && event.agent) { - budget = policy.budgets.find( - (b) => b.type === "agent" && b.name === event.agent - ); - } - - // Fallback to global budget - if (!budget) { - budget = policy.budgets.find((b) => b.type === "global"); - } - - console.log( - `[Aden Control] Budget lookup result: ${ - budget ? `found "${budget.name}" (${budget.id})` : "not found" - }` - ); - - if (budget) { - const alertData = { - action: event.action, - reason: event.reason, - model: event.original_model, - provider: event.provider, - spent: budget.spent || 0, - limit: budget.limit || 0, - }; - - console.log( - `[Aden Control] Sending notification for budget "${ - budget.name - }", notifications: ${JSON.stringify(budget.notifications)}` - ); - await sendBudgetNotifications(budget, alertData, "limit_action"); - } - } - } catch (err) { - console.error( - `[Aden Control] Failed to send control event notifications:`, - (err as Error).message, - (err as Error).stack - ); - } - } else { - console.log( - `[Aden Control] Skipping notification: isBudgetAction=${isBudgetAction}, policyId=${ - policyId || "null" - }` - ); - } -} - -/** - * Process a heartbeat event - track SDK health - */ -async function processHeartbeatEvent( - teamId: string | number, - policyId: string | null, - event: Event -): Promise { - console.log( - `[Aden Control] Heartbeat from ${event.agent_name || event.sdk_instance_id}: ${event.status}, ${event.requests_since_last} requests` - ); - - // Register/update HTTP agent tracking - if (event.sdk_instance_id) { - registerHttpAgent( - teamId, - event.sdk_instance_id, - event.policy_id || policyId, - event.agent_name || null, - event.status || "unknown" - ); - } -} - -/** - * Process an error event - */ -async function processErrorEvent(teamId: string | number, event: Event): Promise { - console.error(`[Aden Control] Error from SDK: ${event.message}`, event.stack); -} - -/** - * Get events for a team (for dashboard) - */ -async function getEvents(teamId: string | number, policyId: string | null = null, options: { limit?: number; offset?: number; start_date?: string; end_date?: string } = {}): Promise { - const { limit = 100, offset = 0, start_date, end_date } = options; - - if (!teamId) { - console.warn(`[Aden Control] No team_id provided, returning empty events`); - return []; - } - - try { - const pool = await getTeamPool(teamId); - const schema = buildSchemaName(teamId); - const client = await pool.connect(); - - try { - await client.query(`SET search_path TO ${schema}, public`); - await tsdbService.ensureSchema(client); - - // Build query with filters - const conditions = [`team_id = $1`]; - const values: unknown[] = [String(teamId)]; - let paramIndex = 2; - - // Filter by policy_id in metadata if provided - if (policyId) { - conditions.push(`metadata->>'policy_id' = $${paramIndex}`); - values.push(policyId); - paramIndex++; - } - - if (start_date) { - conditions.push(`"timestamp" >= $${paramIndex}`); - values.push(new Date(start_date)); - paramIndex++; - } - - if (end_date) { - conditions.push(`"timestamp" <= $${paramIndex}`); - values.push(new Date(end_date)); - paramIndex++; - } - - const sql = ` - SELECT - "timestamp", - trace_id, - span_id, - provider, - model, - agent, - latency_ms, - usage_input_tokens as input_tokens, - usage_output_tokens as output_tokens, - usage_total_tokens as total_tokens, - cost_total, - metadata - FROM llm_events - WHERE ${conditions.join(" AND ")} - ORDER BY "timestamp" DESC - LIMIT $${paramIndex} OFFSET $${paramIndex + 1} - `; - - values.push(limit, offset); - - const result = await client.query(sql, values); - - return result.rows.map((row: Record) => ({ - timestamp: row.timestamp, - trace_id: row.trace_id, - span_id: row.span_id, - provider: row.provider, - model: row.model, - agent: row.agent, - latency_ms: row.latency_ms, - input_tokens: row.input_tokens, - output_tokens: row.output_tokens, - total_tokens: row.total_tokens, - cost_usd: row.cost_total, - metadata: row.metadata, - })); - } finally { - client.release(); - } - } catch (error) { - console.error(`[Aden Control] Failed to get events from TSDB:`, (error as Error).message); - return []; - } -} - -/** - * Get metrics summary for a team (for dashboard analytics) - */ -async function getMetricsSummary(teamId: string | number, options: { start_date?: string; end_date?: string; group_by?: string } = {}): Promise<{ - total_requests: number; - total_cost: number; - total_input_tokens: number; - total_output_tokens: number; - total_tokens: number; - breakdown_by_model: Array<{ model: string; provider: string; requests: number; cost: number; tokens: number }>; -}> { - const { start_date, end_date } = options; - - if (!teamId) { - return { total_requests: 0, total_cost: 0, total_input_tokens: 0, total_output_tokens: 0, total_tokens: 0, breakdown_by_model: [] }; - } - - try { - const pool = await getTeamPool(teamId); - const schema = buildSchemaName(teamId); - const client = await pool.connect(); - - try { - await client.query(`SET search_path TO ${schema}, public`); - await tsdbService.ensureSchema(client); - - const conditions = [`team_id = $1`]; - const values: unknown[] = [String(teamId)]; - let paramIndex = 2; - - if (start_date) { - conditions.push(`"timestamp" >= $${paramIndex}`); - values.push(new Date(start_date)); - paramIndex++; - } - - if (end_date) { - conditions.push(`"timestamp" <= $${paramIndex}`); - values.push(new Date(end_date)); - paramIndex++; - } - - // Get totals - const totalsSql = ` - SELECT - COUNT(*) as total_requests, - COALESCE(SUM(cost_total), 0) as total_cost, - COALESCE(SUM(usage_input_tokens), 0) as total_input_tokens, - COALESCE(SUM(usage_output_tokens), 0) as total_output_tokens, - COALESCE(SUM(usage_total_tokens), 0) as total_tokens - FROM llm_events - WHERE ${conditions.join(" AND ")} - `; - - const totalsResult = await client.query(totalsSql, values); - const totals = totalsResult.rows[0] || {}; - - // Get breakdown by model - const breakdownSql = ` - SELECT - model, - provider, - COUNT(*) as requests, - COALESCE(SUM(cost_total), 0) as cost, - COALESCE(SUM(usage_total_tokens), 0) as tokens - FROM llm_events - WHERE ${conditions.join(" AND ")} - GROUP BY model, provider - ORDER BY cost DESC - LIMIT 20 - `; - - const breakdownResult = await client.query(breakdownSql, values); - - return { - total_requests: parseInt(totals.total_requests) || 0, - total_cost: parseFloat(totals.total_cost) || 0, - total_input_tokens: parseInt(totals.total_input_tokens) || 0, - total_output_tokens: parseInt(totals.total_output_tokens) || 0, - total_tokens: parseInt(totals.total_tokens) || 0, - breakdown_by_model: breakdownResult.rows.map((row: Record) => ({ - model: row.model as string, - provider: row.provider as string, - requests: parseInt(row.requests as string) || 0, - cost: parseFloat(row.cost as string) || 0, - tokens: parseInt(row.tokens as string) || 0, - })), - }; - } finally { - client.release(); - } - } catch (error) { - console.error(`[Aden Control] Failed to get metrics summary:`, (error as Error).message); - return { total_requests: 0, total_cost: 0, total_input_tokens: 0, total_output_tokens: 0, total_tokens: 0, breakdown_by_model: [] }; - } -} - -/** - * Get budget status for a budget ID - */ -async function getBudgetStatus(budgetId: string): Promise<{ id: string; spent: number; last_reset: string | null }> { - const tracker = budgetTracker.get(budgetId); - return { - id: budgetId, - spent: tracker?.spent || 0, - last_reset: tracker?.lastReset?.toISOString() || null, - }; -} - -/** - * Reset budget for a budget ID - */ -async function resetBudget(budgetId: string): Promise { - budgetTracker.set(budgetId, { spent: 0, lastReset: new Date() }); -} - -/** - * Add a budget rule to a policy - */ -async function addBudgetRule(teamId: string | number, policyId: string | null, rule: Budget, userContext: UserContext | null = null): Promise { - const policy = await getPolicy(teamId, policyId, userContext); - policy.budgets = policy.budgets || []; - policy.budgets.push(rule); - return updatePolicy(teamId, policyId, { budgets: policy.budgets }, userContext); -} - -/** - * Add a throttle rule to a policy - */ -async function addThrottleRule(teamId: string | number, policyId: string | null, rule: unknown, userContext: UserContext | null = null): Promise { - const policy = await getPolicy(teamId, policyId, userContext); - policy.throttles = policy.throttles || []; - policy.throttles.push(rule); - return updatePolicy(teamId, policyId, { throttles: policy.throttles }, userContext); -} - -/** - * Add a block rule to a policy - */ -async function addBlockRule(teamId: string | number, policyId: string | null, rule: unknown, userContext: UserContext | null = null): Promise { - const policy = await getPolicy(teamId, policyId, userContext); - policy.blocks = policy.blocks || []; - policy.blocks.push(rule); - return updatePolicy(teamId, policyId, { blocks: policy.blocks }, userContext); -} - -/** - * Add a degradation rule to a policy - */ -async function addDegradeRule(teamId: string | number, policyId: string | null, rule: unknown, userContext: UserContext | null = null): Promise { - const policy = await getPolicy(teamId, policyId, userContext); - policy.degradations = policy.degradations || []; - policy.degradations.push(rule); - return updatePolicy( - teamId, - policyId, - { degradations: policy.degradations }, - userContext - ); -} - -/** - * Add an alert rule to a policy - */ -async function addAlertRule(teamId: string | number, policyId: string | null, rule: unknown, userContext: UserContext | null = null): Promise { - const policy = await getPolicy(teamId, policyId, userContext); - policy.alerts = policy.alerts || []; - policy.alerts.push(rule); - return updatePolicy(teamId, policyId, { alerts: policy.alerts }, userContext); -} - -/** - * Clear all rules from a policy - */ -async function clearPolicy(teamId: string | number, policyId: string | null, userContext: UserContext | null = null): Promise { - return updatePolicy( - teamId, - policyId, - { - budgets: [], - throttles: [], - blocks: [], - degradations: [], - alerts: [], - }, - userContext - ); -} - -/** - * Delete a policy - */ -async function deletePolicy(teamId: string | number | null, policyId: string | null, userContext: UserContext | null = null): Promise { - if (!teamId) { - teamId = userContext?.team_id ?? null; - } - if (!teamId) { - throw new Error("team_id is required to delete policy"); - } - if (!policyId) { - throw new Error("policy_id is required to delete policy"); - } - - const collection = getPolicyCollection(); - const result = await collection.deleteOne({ team_id: teamId, id: policyId }); - - if (result.deletedCount === 0) { - throw new Error("Policy not found"); - } - - return true; -} - -/** - * Get all policies for a team - */ -async function getPoliciesByTeam(teamId: string | number, options: { limit?: number; offset?: number } = {}): Promise { - const { limit = 100, offset = 0 } = options; - const collection = getPolicyCollection(); - - const policies = await collection - .find({ team_id: teamId }) - .sort({ updated_at: -1 }) - .skip(offset) - .limit(limit) - .toArray() as (Policy & { _id?: unknown })[]; - - // Enrich each policy's budgets with actual spend and analytics from TSDB - const enrichedPolicies = await Promise.all( - policies.map(async ({ _id, ...policy }) => { - if (policy.budgets && policy.budgets.length > 0) { - policy.budgets = await Promise.all( - policy.budgets.map(async (budget) => { - const analytics = await calculateBudgetAnalyticsFromTsdb(teamId, budget); - return { - ...budget, - spent: analytics.spent, - analytics: { - burnRate: analytics.burnRate, - projectedSpend: analytics.projectedSpend, - daysUntilLimit: analytics.daysUntilLimit, - usagePercent: analytics.usagePercent, - projectedPercent: analytics.projectedPercent, - status: analytics.status, - period: analytics.period, - }, - }; - }) - ); - } - return policy as Policy; - }) - ); - - return enrichedPolicies; -} - -/** - * Get usage breakdown for dashboard analytics - */ -async function getUsageBreakdown(teamId: string | number, options: { days?: number; context_id?: string; budget?: Budget } = {}): Promise<{ - daily: Array<{ date: Date; cost: number; requests: number; tokens: number }>; - by_model: Array<{ model: string; provider: string; cost: number; requests: number; tokens: number }>; - by_feature: Array<{ feature: string; cost: number; requests: number; tokens: number; percentage: number }>; -}> { - const { days = 7, context_id, budget } = options; - - if (!teamId) { - return { daily: [], by_model: [], by_feature: [] }; - } - - try { - const pool = await getTeamPool(teamId); - const schema = buildSchemaName(teamId); - const client = await pool.connect(); - - try { - await client.query(`SET search_path TO ${schema}, public`); - await tsdbService.ensureSchema(client); - - const startDate = new Date(); - startDate.setDate(startDate.getDate() - days); - - const conditions = [`team_id = $1`, `"timestamp" >= $2`]; - const values: unknown[] = [String(teamId), startDate]; - let paramIndex = 3; - - // Apply budget-specific filter based on budget type - if (budget) { - const budgetFilter = getBudgetFilter(budget, paramIndex); - if (budgetFilter) { - conditions.push(budgetFilter.condition); - values.push(budgetFilter.value); - paramIndex++; - } - } else if (context_id) { - // Fallback to context_id filter - conditions.push(`metadata->>'context_id' = $${paramIndex}`); - values.push(context_id); - paramIndex++; - } - - // Daily usage breakdown - const dailySql = ` - SELECT - DATE_TRUNC('day', "timestamp") as date, - COALESCE(SUM(cost_total), 0) as cost, - COUNT(*) as requests, - COALESCE(SUM(usage_total_tokens), 0) as tokens - FROM llm_events - WHERE ${conditions.join(" AND ")} - GROUP BY DATE_TRUNC('day', "timestamp") - ORDER BY date DESC - LIMIT ${days} - `; - const dailyResult = await client.query(dailySql, values); - - // Usage by model - const byModelSql = ` - SELECT - model, - provider, - COALESCE(SUM(cost_total), 0) as cost, - COUNT(*) as requests, - COALESCE(SUM(usage_total_tokens), 0) as tokens - FROM llm_events - WHERE ${conditions.join(" AND ")} - GROUP BY model, provider - ORDER BY cost DESC - LIMIT 10 - `; - const byModelResult = await client.query(byModelSql, values); - - // Usage by feature (from metadata) - const byFeatureSql = ` - SELECT - COALESCE(metadata->>'feature', agent, 'unknown') as feature, - COALESCE(SUM(cost_total), 0) as cost, - COUNT(*) as requests, - COALESCE(SUM(usage_total_tokens), 0) as tokens - FROM llm_events - WHERE ${conditions.join(" AND ")} - GROUP BY COALESCE(metadata->>'feature', agent, 'unknown') - ORDER BY cost DESC - LIMIT 10 - `; - const byFeatureResult = await client.query(byFeatureSql, values); - - // Calculate totals for percentages - const totalCost = byFeatureResult.rows.reduce( - (sum: number, row: Record) => sum + parseFloat((row.cost as string) || "0"), - 0 - ); - - return { - daily: dailyResult.rows - .map((row: Record) => ({ - date: row.date as Date, - cost: parseFloat(row.cost as string) || 0, - requests: parseInt(row.requests as string) || 0, - tokens: parseInt(row.tokens as string) || 0, - })) - .reverse(), - by_model: byModelResult.rows.map((row: Record) => ({ - model: row.model as string, - provider: row.provider as string, - cost: parseFloat(row.cost as string) || 0, - requests: parseInt(row.requests as string) || 0, - tokens: parseInt(row.tokens as string) || 0, - })), - by_feature: byFeatureResult.rows.map((row: Record) => ({ - feature: row.feature as string, - cost: parseFloat(row.cost as string) || 0, - requests: parseInt(row.requests as string) || 0, - tokens: parseInt(row.tokens as string) || 0, - percentage: totalCost > 0 ? ((parseFloat(row.cost as string) || 0) / totalCost) * 100 : 0, - })), - }; - } finally { - client.release(); - } - } catch (error) { - console.error(`[Aden Control] Failed to get usage breakdown:`, (error as Error).message); - return { daily: [], by_model: [], by_feature: [] }; - } -} - -/** - * Get SQL filter condition for a budget based on its type - */ -function getBudgetFilter(budget: Budget, paramIndex: number): { condition: string; value: unknown } | null { - switch (budget.type) { - case "global": - // Global budgets apply to all events - no filter needed - return null; - - case "agent": - // Agent budgets filter by agent column OR metadata.agent (for legacy data) - return { - condition: `(agent = $${paramIndex} OR metadata->>'agent' = $${paramIndex})`, - value: budget.name, - }; - - case "tenant": - // Tenant budgets filter by tenant_id in metadata - return { condition: `metadata->>'tenant_id' = $${paramIndex}`, value: budget.name }; - - case "customer": - // Customer budgets filter by customer_id in metadata - return { - condition: `metadata->>'customer_id' = $${paramIndex}`, - value: budget.name, - }; - - case "feature": - // Feature budgets filter by feature in metadata or agent - return { - condition: `(metadata->>'feature' = $${paramIndex} OR agent = $${paramIndex})`, - value: budget.name, - }; - - case "tag": - // Tag budgets filter by tags array matching - if (budget.tags && budget.tags.length > 0) { - // Match if any of the budget's tags are in the event's tags array - return { - condition: `metadata->'tags' ?| $${paramIndex}`, - value: budget.tags, - }; - } - return null; - - default: - return null; - } -} - -/** - * Get rate metrics for dashboard analytics - */ -async function getRateMetrics(teamId: string | number, options: { days?: number; context_id?: string; budget?: Budget } = {}): Promise<{ - peak_rate: number; - p95_rate: number; - avg_rate: number; - min_rate: number; - max_burst: number; -}> { - const { days = 30, context_id, budget } = options; - - if (!teamId) { - return { - peak_rate: 0, - p95_rate: 0, - avg_rate: 0, - min_rate: 0, - max_burst: 0, - }; - } - - try { - const pool = await getTeamPool(teamId); - const schema = buildSchemaName(teamId); - const client = await pool.connect(); - - try { - await client.query(`SET search_path TO ${schema}, public`); - await tsdbService.ensureSchema(client); - - const startDate = new Date(); - startDate.setDate(startDate.getDate() - days); - - const conditions = [`team_id = $1`, `"timestamp" >= $2`]; - const values: unknown[] = [String(teamId), startDate]; - let paramIndex = 3; - - // Apply budget-specific filter based on budget type - if (budget) { - const budgetFilter = getBudgetFilter(budget, paramIndex); - if (budgetFilter) { - conditions.push(budgetFilter.condition); - values.push(budgetFilter.value); - paramIndex++; - } - } else if (context_id) { - conditions.push(`metadata->>'context_id' = $${paramIndex}`); - values.push(context_id); - paramIndex++; - } - - // Calculate requests per second in 1-minute buckets - const ratesSql = ` - WITH minute_buckets AS ( - SELECT - DATE_TRUNC('minute', "timestamp") as minute, - COUNT(*) as requests - FROM llm_events - WHERE ${conditions.join(" AND ")} - GROUP BY DATE_TRUNC('minute', "timestamp") - ) - SELECT - MAX(requests / 60.0) as peak_rate, - PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY requests / 60.0) as p95_rate, - AVG(requests / 60.0) as avg_rate, - MIN(requests / 60.0) as min_rate - FROM minute_buckets - `; - const ratesResult = await client.query(ratesSql, values); - const rates = ratesResult.rows[0] || {}; - - // Calculate max burst in 5-second windows - const burstSql = ` - WITH five_second_buckets AS ( - SELECT - DATE_TRUNC('second', "timestamp") - - (EXTRACT(SECOND FROM "timestamp")::integer % 5) * INTERVAL '1 second' as bucket, - COUNT(*) as requests - FROM llm_events - WHERE ${conditions.join(" AND ")} - GROUP BY DATE_TRUNC('second', "timestamp") - - (EXTRACT(SECOND FROM "timestamp")::integer % 5) * INTERVAL '1 second' - ) - SELECT MAX(requests) as max_burst - FROM five_second_buckets - `; - const burstResult = await client.query(burstSql, values); - const maxBurst = burstResult.rows[0]?.max_burst || 0; - - return { - peak_rate: parseFloat(rates.peak_rate) || 0, - p95_rate: parseFloat(rates.p95_rate) || 0, - avg_rate: parseFloat(rates.avg_rate) || 0, - min_rate: parseFloat(rates.min_rate) || 0, - max_burst: parseInt(maxBurst) || 0, - }; - } finally { - client.release(); - } - } catch (error) { - console.error(`[Aden Control] Failed to get rate metrics:`, (error as Error).message); - return { - peak_rate: 0, - p95_rate: 0, - avg_rate: 0, - min_rate: 0, - max_burst: 0, - }; - } -} - -/** - * Get detailed budget info including spend tracking - */ -async function getBudgetDetails(teamId: string | number, policyId: string | null, budgetId: string): Promise { - const policy = await getPolicy(teamId, policyId); - const budget = policy.budgets?.find((b) => b.id === budgetId); - - if (!budget) { - return null; - } - - // Get real-time tracker status - const tracker = budgetTracker.get(budgetId); - const spent = tracker?.spent ?? budget.spent ?? 0; - - return { - ...budget, - spent, - }; -} - -interface BudgetContext { - agent?: string; - metadata?: Record; - tenant_id?: string; - customer_id?: string; - feature?: string; - tags?: string[]; -} - -/** - * Find all budgets that match a given context - * Used for multi-budget validation to check ALL applicable budgets - */ -function findMatchingBudgetsForContext(budgets: Budget[], context: BudgetContext = {}): Budget[] { - if (!budgets || !Array.isArray(budgets)) return []; - - // metadata.agent takes precedence over top-level agent - const metadata = context.metadata || {}; - const effectiveAgent = (metadata.agent as string) || context.agent; - - return budgets.filter((budget) => { - switch (budget.type) { - case "global": - // Global budgets always match - return true; - - case "agent": - // Agent budgets match when agent name matches (from top-level or metadata) - return !!effectiveAgent && budget.name === effectiveAgent; - - case "tenant": - // Tenant budgets match when tenant_id matches - return !!context.tenant_id && budget.name === context.tenant_id; - - case "customer": - // Customer budgets match when customer_id matches - return !!context.customer_id && budget.name === context.customer_id; - - case "feature": - // Feature budgets match when feature name matches - return !!context.feature && budget.name === context.feature; - - case "tag": - // Tag budgets match when any budget tag is in context tags - if (!budget.tags || !context.tags) return false; - return budget.tags.some((t) => context.tags!.includes(t)); - - default: - return false; - } - }); -} - -interface BudgetValidationResult { - budget_id: string; - budget_name: string; - budget_type: string; - allowed: boolean; - action: string; - reason: string | null; - authoritative_spend: number; - budget_limit: number; - usage_percent: number; - projected_percent: number; - degrade_to_model: string | null; - degrade_to_provider: string | null; -} - -interface MultiValidationResult { - allowed: boolean; - action: string; - reason: string | undefined; - authoritative_spend: number; - budget_limit: number; - usage_percent: number; - projected_percent: number; - degrade_to_model: string | undefined; - degrade_to_provider: string | undefined; - restricting_budget_id: string | undefined; - restricting_budget_name: string | undefined; - budgets_checked: BudgetValidationResult[]; -} - -/** - * Validate multiple budgets and return the most restrictive result - */ -function validateMultipleBudgets(budgets: Budget[], estimatedCost: number, localSpend: number | null = null): MultiValidationResult { - if (!budgets || budgets.length === 0) { - return { - allowed: true, - action: "allow", - reason: "No budgets to validate", - authoritative_spend: 0, - budget_limit: 0, - usage_percent: 0, - projected_percent: 0, - degrade_to_model: undefined, - degrade_to_provider: undefined, - restricting_budget_id: undefined, - restricting_budget_name: undefined, - budgets_checked: [], - }; - } - - // Action priority (higher = more restrictive) - const actionPriority: Record = { allow: 0, throttle: 1, degrade: 2, block: 3 }; - - let mostRestrictiveResult: BudgetValidationResult | null = null; - const budgetsChecked: BudgetValidationResult[] = []; - - for (const budget of budgets) { - // Calculate projected spend - const tsdbSpend = budget.spent || 0; - const authoritativeSpend = - typeof localSpend === "number" && localSpend > tsdbSpend ? localSpend : tsdbSpend; - const projectedSpend = authoritativeSpend + estimatedCost; - const usagePercent = budget.limit > 0 ? (authoritativeSpend / budget.limit) * 100 : 0; - const projectedPercent = budget.limit > 0 ? (projectedSpend / budget.limit) * 100 : 0; - - // Determine action for this budget - let allowed = true; - let action = "allow"; - let reason: string | null = null; - let degradeToModel: string | null = null; - let degradeToProvider: string | null = null; - - if (projectedPercent >= 100) { - const limitAction = budget.limitAction || "kill"; - - switch (limitAction) { - case "kill": - allowed = false; - action = "block"; - reason = `Budget "${budget.name}" exceeded: $${projectedSpend.toFixed(4)} > $${ - budget.limit - } (${projectedPercent.toFixed(1)}%)`; - break; - case "degrade": - allowed = true; - action = "degrade"; - reason = `Budget "${budget.name}" at limit, degrading model`; - degradeToModel = budget.degradeToModel || null; - degradeToProvider = budget.degradeToProvider || null; - break; - case "throttle": - allowed = true; - action = "throttle"; - reason = `Budget "${budget.name}" at limit, throttling`; - break; - default: - allowed = false; - action = "block"; - reason = `Budget "${budget.name}" exceeded with unknown action`; - } - } else if ( - projectedPercent >= 90 && - budget.limitAction === "degrade" && - budget.degradeToModel - ) { - allowed = true; - action = "degrade"; - reason = `Budget "${budget.name}" approaching limit (${projectedPercent.toFixed( - 1 - )}%), pre-emptive degradation`; - degradeToModel = budget.degradeToModel; - degradeToProvider = budget.degradeToProvider || null; - } - - const budgetResult: BudgetValidationResult = { - budget_id: budget.id, - budget_name: budget.name, - budget_type: budget.type, - allowed, - action, - reason, - authoritative_spend: authoritativeSpend, - budget_limit: budget.limit, - usage_percent: usagePercent, - projected_percent: projectedPercent, - degrade_to_model: degradeToModel, - degrade_to_provider: degradeToProvider, - }; - - budgetsChecked.push(budgetResult); - - // Track most restrictive result - if ( - !mostRestrictiveResult || - actionPriority[action] > actionPriority[mostRestrictiveResult.action] - ) { - mostRestrictiveResult = budgetResult; - } - } - - return { - allowed: mostRestrictiveResult?.allowed ?? true, - action: mostRestrictiveResult?.action ?? "allow", - reason: mostRestrictiveResult?.reason ?? undefined, - authoritative_spend: mostRestrictiveResult?.authoritative_spend ?? 0, - budget_limit: mostRestrictiveResult?.budget_limit ?? 0, - usage_percent: mostRestrictiveResult?.usage_percent ?? 0, - projected_percent: mostRestrictiveResult?.projected_percent ?? 0, - degrade_to_model: mostRestrictiveResult?.degrade_to_model ?? undefined, - degrade_to_provider: mostRestrictiveResult?.degrade_to_provider ?? undefined, - restricting_budget_id: mostRestrictiveResult?.budget_id, - restricting_budget_name: mostRestrictiveResult?.budget_name, - budgets_checked: budgetsChecked, - }; -} - -// ============================================================================= -// Content Storage (for Layer 0 content capture) -// ============================================================================= - -interface ContentItem { - content_id: string; - content_hash: string; - content: string; - byte_size: number; -} - -/** - * Get the MongoDB collection for content storage - */ -function getContentCollection(): MongoCollection { - return _ACHO_MG_DB - .db(_ACHO_MDB_CONFIG.ERP_DBNAME) - .collection(_ACHO_MDB_COLLECTIONS.ADEN_CONTROL_CONTENT); -} - -/** - * Store large content items from SDK - * Used by Layer 0 content capture for storing content that exceeds max_content_bytes threshold - */ -async function storeContent(teamId: string | number, items: ContentItem[]): Promise<{ stored: number }> { - if (!items || items.length === 0) { - return { stored: 0 }; - } - - const collection = getContentCollection(); - const now = new Date().toISOString(); - - let stored = 0; - for (const item of items) { - try { - await collection.updateOne( - { content_id: item.content_id, team_id: teamId }, - { - $set: { - content_hash: item.content_hash, - content: item.content, - byte_size: item.byte_size, - updated_at: now, - }, - $setOnInsert: { - content_id: item.content_id, - team_id: teamId, - created_at: now, - }, - }, - { upsert: true } - ); - stored++; - } catch (error) { - console.error(`[Aden Control] Failed to store content ${item.content_id}:`, (error as Error).message); - } - } - - console.log(`[Aden Control] Stored ${stored}/${items.length} content items for team ${teamId}`); - return { stored }; -} - -/** - * Retrieve content by ID - */ -async function getContent(teamId: string | number, contentId: string): Promise { - const collection = getContentCollection(); - const doc = await collection.findOne({ content_id: contentId, team_id: teamId }) as (ContentItem & { _id?: unknown }) | null; - - if (!doc) { - return null; - } - - const { _id, ...content } = doc; - return content as ContentItem; -} - -export default { - getPolicy, - updatePolicy, - deletePolicy, - processEvents, - getEvents, - getMetricsSummary, - getUsageBreakdown, - getRateMetrics, - getBudgetStatus, - getBudgetDetails, - resetBudget, - addBudgetRule, - addThrottleRule, - addBlockRule, - addDegradeRule, - addAlertRule, - clearPolicy, - getPoliciesByTeam, - findMatchingBudgetsForContext, - validateMultipleBudgets, - storeContent, - getContent, -}; diff --git a/hive/src/services/control/control_sockets.ts b/hive/src/services/control/control_sockets.ts deleted file mode 100644 index 0f954e8f..00000000 --- a/hive/src/services/control/control_sockets.ts +++ /dev/null @@ -1,733 +0,0 @@ -/** - * Aden Control Sockets - * - * WebSocket namespace for real-time control plane communication. - * Handles: - * - SDK connections and authentication - * - Real-time policy updates - * - Event ingestion - * - Heartbeat monitoring - */ - -import jwt from "jsonwebtoken"; -// Note: userDB.findSaltByToken will be injected via initialization -import controlService from "./control_service"; -import llmEventBatcher from "./llm_event_batcher"; -import type { Server, Socket, Namespace } from "socket.io"; - -interface UserDbService { - findSaltByToken: (token: string) => Promise; -} - -let userDbService: UserDbService | null = null; -let jwtSecret: string = ""; - -/** - * Set user DB service for JWT verification - * @param service - User DB service with findSaltByToken method - * @param secret - JWT secret for token verification - */ -function setUserDbService(service: UserDbService, secret?: string): void { - userDbService = service; - if (secret) { - jwtSecret = secret; - } -} - -interface InstanceInfo { - socket: Socket; - instanceId: string; - policyId: string | null; - connectedAt: Date; - lastHeartbeat: Date; -} - -// HTTP-only agents (no socket connection) -interface HttpInstanceInfo { - instanceId: string; - policyId: string | null; - agentName: string | null; - status: string; - firstSeen: Date; - lastHeartbeat: Date; -} - -// Track connected SDK instances (WebSocket) -// teamId -> Map -const connectedInstances = new Map>(); - -// Track HTTP-only SDK instances (no WebSocket, identified by heartbeats) -// teamId -> Map -const httpInstances = new Map>(); - -// TTL for HTTP agents (remove if no heartbeat for this duration) -const HTTP_AGENT_TTL_MS = 60000; // 60 seconds - -// Store the control emitter globally for agent status broadcasts -let globalControlEmitter: ControlEmitterInner | null = null; - -// Track which teams have active subscriptions for agent status (team -> subscriber count) -const teamSubscriberCounts = new Map(); - -// Helper to get teams with active subscribers -function getTeamsWithSubscribers(): string[] { - return Array.from(teamSubscriberCounts.entries()) - .filter(([, count]) => count > 0) - .map(([teamId]) => teamId); -} - -// Interval for periodic agent status broadcasts -let agentStatusInterval: ReturnType | null = null; - -/** - * Register or update an HTTP-only agent from heartbeat - * Called from control_service when processing heartbeat events - */ -function registerHttpAgent( - teamId: string | number, - instanceId: string, - policyId: string | null, - agentName: string | null, - status: string -): void { - const teamKey = String(teamId); - - // Check if this instance is already connected via WebSocket - const wsInstances = connectedInstances.get(teamKey); - if (wsInstances) { - for (const info of wsInstances.values()) { - if (info.instanceId === instanceId) { - // Already tracked via WebSocket, just update heartbeat there - info.lastHeartbeat = new Date(); - return; - } - } - } - - // Track as HTTP-only agent - if (!httpInstances.has(teamKey)) { - httpInstances.set(teamKey, new Map()); - } - - const existing = httpInstances.get(teamKey)!.get(instanceId); - if (existing) { - // Update existing - existing.lastHeartbeat = new Date(); - existing.status = status; - existing.policyId = policyId; - existing.agentName = agentName; - } else { - // New HTTP agent - httpInstances.get(teamKey)!.set(instanceId, { - instanceId, - policyId, - agentName, - status, - firstSeen: new Date(), - lastHeartbeat: new Date(), - }); - console.log( - `[Aden Control] HTTP agent registered: ${agentName || instanceId.slice(0, 8)}... (team: ${teamKey})` - ); - - // Broadcast updated agent status to subscribers - broadcastAgentStatus(teamKey); - } -} - -/** - * Clean up stale HTTP agents that haven't sent heartbeats - */ -function cleanupStaleHttpAgents(): void { - const now = Date.now(); - const teamsWithRemovedAgents: string[] = []; - - for (const [teamId, instances] of httpInstances) { - let removed = false; - for (const [instanceId, info] of instances) { - if (now - info.lastHeartbeat.getTime() > HTTP_AGENT_TTL_MS) { - instances.delete(instanceId); - removed = true; - console.log( - `[Aden Control] HTTP agent expired: ${instanceId.slice(0, 8)}... (team: ${teamId})` - ); - } - } - - if (removed) { - teamsWithRemovedAgents.push(teamId); - } - - // Clean up empty team maps - if (instances.size === 0) { - httpInstances.delete(teamId); - } - } - - // Broadcast updated status to teams that had agents removed - for (const teamId of teamsWithRemovedAgents) { - broadcastAgentStatus(teamId); - } -} - -// Run cleanup every 30 seconds -setInterval(cleanupStaleHttpAgents, 30000); - -/** - * Get agent status for a team - */ -function getAgentStatusForTeam(teamId: string): { - type: string; - active: boolean; - count: number; - instances: Array<{ - instance_id: string; - policy_id: string | null; - agent_name: string | null; - connected_at: string; - last_heartbeat: string; - connection_type: "websocket" | "http"; - status?: string; - }>; - timestamp: string; -} { - const wsInstances = connectedInstances.get(teamId); - const httpInsts = httpInstances.get(teamId); - - const instances: Array<{ - instance_id: string; - policy_id: string | null; - agent_name: string | null; - connected_at: string; - last_heartbeat: string; - connection_type: "websocket" | "http"; - status?: string; - }> = []; - - // Add WebSocket-connected instances - if (wsInstances) { - for (const info of wsInstances.values()) { - instances.push({ - instance_id: info.instanceId, - policy_id: info.policyId, - agent_name: null, - connected_at: info.connectedAt.toISOString(), - last_heartbeat: info.lastHeartbeat.toISOString(), - connection_type: "websocket", - }); - } - } - - // Add HTTP-only instances - if (httpInsts) { - for (const info of httpInsts.values()) { - instances.push({ - instance_id: info.instanceId, - policy_id: info.policyId, - agent_name: info.agentName, - connected_at: info.firstSeen.toISOString(), - last_heartbeat: info.lastHeartbeat.toISOString(), - connection_type: "http", - status: info.status, - }); - } - } - - const count = instances.length; - - return { - type: "agent-status", - active: count > 0, - count, - instances, - timestamp: new Date().toISOString(), - }; -} - -/** - * Broadcast agent status to all subscribed clients for a team - */ -function broadcastAgentStatus(teamId: string): void { - if (!globalControlEmitter) return; - - const status = getAgentStatusForTeam(teamId); - const room = `team:${teamId}:llm-events`; - globalControlEmitter.to(room).emit("message", status); -} - -/** - * Broadcast agent status to all teams with subscribers - */ -function broadcastAgentStatusToAllTeams(): void { - const teams = getTeamsWithSubscribers(); - for (const teamId of teams) { - broadcastAgentStatus(teamId); - } -} - -interface AdenSocket extends Socket { - user?: Record; - teamId?: string; - policyId?: string | null; - sdkInstanceId?: string; -} - -interface RedisEmitter { - of: (namespace: string) => ControlEmitterInner; -} - -interface ControlEmitterInner { - to: (room: string) => { emit: (event: string, payload: unknown) => void }; - emit: (event: string, payload: unknown) => void; -} - -interface MessageData { - event_type?: string; - [key: string]: unknown; -} - -interface ControlEmitter { - emitPolicyUpdate: (teamId: string | number, policyId: string | null, policy: unknown) => void; - emitCommand: (teamId: string | number, command: { action: string; [key: string]: unknown }) => void; - emitAlert: (teamId: string | number, policyId: string | null, alert: unknown) => void; - emitToInstance: (teamId: string | number, instanceId: string, message: unknown) => boolean; - getConnectedCount: (teamId: string | number) => number; - getConnectedInstances: (teamId: string | number) => Array<{ - instance_id: string; - policy_id: string | null; - agent_name: string | null; - connected_at: string; - last_heartbeat: string; - connection_type: "websocket" | "http"; - status?: string; - }>; - getTotalConnectedCount: () => number; -} - -/** - * Initialize Aden Control WebSocket namespace - * @param io - Socket.IO server instance - * @param rootEmitter - Redis emitter for cross-instance communication - * @returns Control emitter for sending updates - */ -function initAdenControlSockets(io: Server, rootEmitter: RedisEmitter): ControlEmitter { - // Create namespace for control plane - const controlNamespace: Namespace = io.of("/v1/control/ws"); - - // Create emitter for this namespace - const controlEmitter: ControlEmitterInner = rootEmitter.of("/v1/control/ws"); - - // Store globally for agent status broadcasts - globalControlEmitter = controlEmitter; - - // Start periodic agent status broadcast (every 2 seconds) - if (agentStatusInterval) { - clearInterval(agentStatusInterval); - } - agentStatusInterval = setInterval(broadcastAgentStatusToAllTeams, 2000); - - // Initialize LLM event batcher with emitter for real-time streaming - llmEventBatcher.setEmitter(controlEmitter as unknown as { to: (room: string) => { emit: (event: string, payload: unknown) => void } }); - - // Authentication middleware - verify JWT token - controlNamespace.use(async (socket: AdenSocket, next: (err?: Error) => void) => { - try { - let token: string | undefined = - socket.handshake.auth?.token || - socket.handshake.headers?.authorization || - (socket.handshake.query?.token as string | undefined); - - if (!token) { - console.error("[Aden Control WS] No authorization provided"); - return next(new Error("Authentication required")); - } - - // Extract token (support "Bearer " and "jwt " formats) - if (token.startsWith("Bearer ")) { - token = token.slice(7); - } else if (token.startsWith("jwt ")) { - token = token.slice(4); - } - - if (!token) { - return next(new Error("Invalid token")); - } - - // Verify JWT token using user's salt - if (!userDbService) { - console.error("[Aden Control WS] userDbService not initialized"); - return next(new Error("Server configuration error")); - } - const salt = await userDbService.findSaltByToken(token); - if (!salt) { - console.error("[Aden Control WS] No salt found for token"); - return next(new Error("Invalid token")); - } - // Token is signed with jwtSecret + salt - const verifySecret = jwtSecret ? jwtSecret + salt : salt; - const decoded = await new Promise>((resolve, reject) => { - jwt.verify(token!, verifySecret, (err, decoded) => { - if (err) reject(err); - else resolve(decoded as Record); - }); - }); - - // Store user info on socket - socket.user = decoded; - socket.teamId = decoded.current_team_id as string; - socket.policyId = - (socket.handshake.headers?.["x-policy-id"] as string) || - (socket.handshake.query?.policy_id as string) || - null; - socket.sdkInstanceId = - (socket.handshake.headers?.["x-sdk-instance-id"] as string) || - (socket.handshake.query?.instance_id as string) || - socket.id; - - console.log( - `[Aden Control WS] SDK connecting: ${socket.sdkInstanceId!.slice(0, 8)}... (team: ${socket.teamId})` - ); - - next(); - } catch (error) { - console.error("[Aden Control WS] Auth error:", (error as Error).message); - next(new Error("Authentication failed")); - } - }); - - // Handle connections - controlNamespace.on("connection", async (socket: AdenSocket) => { - const { teamId, policyId, sdkInstanceId } = socket; - - console.log( - `[Aden Control WS] SDK connected: ${sdkInstanceId!.slice(0, 8)}... (socket: ${socket.id}, team: ${teamId})` - ); - - // Track this instance by team - if (!connectedInstances.has(teamId!)) { - connectedInstances.set(teamId!, new Map()); - } - connectedInstances.get(teamId!)!.set(socket.id, { - socket, - instanceId: sdkInstanceId!, - policyId: policyId || null, - connectedAt: new Date(), - lastHeartbeat: new Date(), - }); - - // Join room for this team (for policy broadcasts) - socket.join(`team:${teamId}`); - // Also join policy-specific room if policy specified - if (policyId) { - socket.join(`team:${teamId}:policy:${policyId}`); - } - - // Send current policy immediately - try { - const policy = await controlService.getPolicy(teamId!, policyId || null); - socket.emit("message", { - type: "policy", - policy, - }); - } catch (error) { - console.error("[Aden Control WS] Error sending initial policy:", error); - } - - // Handle incoming messages from SDK - socket.on("message", async (data: MessageData | string) => { - try { - await handleSdkMessage(socket, data); - } catch (error) { - console.error("[Aden Control WS] Error handling message:", error); - socket.emit("message", { - type: "error", - error: (error as Error).message, - }); - } - }); - - // Handle direct event submission (alternative to message) - socket.on("event", async (event: Record) => { - try { - await controlService.processEvents(teamId!, policyId || null, [event as any]); - } catch (error) { - console.error("[Aden Control WS] Error processing event:", error); - } - }); - - // Handle disconnection - socket.on("disconnect", (reason: string) => { - console.log( - `[Aden Control WS] SDK disconnected: ${sdkInstanceId!.slice(0, 8)}... (reason: ${reason})` - ); - - // Remove from tracking - const instances = connectedInstances.get(teamId!); - if (instances) { - instances.delete(socket.id); - if (instances.size === 0) { - connectedInstances.delete(teamId!); - } - } - }); - - // Handle errors - socket.on("error", (error: Error) => { - console.error( - `[Aden Control WS] Socket error for ${sdkInstanceId!.slice(0, 8)}...:`, - error.message - ); - }); - - // Handle LLM events stream subscription (for dashboard real-time updates) - socket.on("subscribe-llm-events", () => { - const room = `team:${teamId}:llm-events`; - socket.join(room); - console.log(`[Aden Control WS] Socket ${socket.id} subscribed to ${room}`); - - // Track subscriber count for this team - const currentCount = teamSubscriberCounts.get(teamId!) || 0; - teamSubscriberCounts.set(teamId!, currentCount + 1); - - socket.emit("message", { - type: "subscribed", - stream: "llm-events", - teamId: teamId, - }); - - // Send initial agent status - const status = getAgentStatusForTeam(teamId!); - socket.emit("message", status); - }); - - socket.on("unsubscribe-llm-events", () => { - const room = `team:${teamId}:llm-events`; - socket.leave(room); - console.log(`[Aden Control WS] Socket ${socket.id} unsubscribed from ${room}`); - - // Decrement subscriber count - const currentCount = teamSubscriberCounts.get(teamId!) || 0; - if (currentCount > 0) { - teamSubscriberCounts.set(teamId!, currentCount - 1); - } - - socket.emit("message", { - type: "unsubscribed", - stream: "llm-events", - teamId: teamId, - }); - }); - }); - - /** - * Handle incoming message from SDK - */ - async function handleSdkMessage(socket: AdenSocket, data: MessageData | string): Promise { - // Parse if string - let parsedData: MessageData; - if (typeof data === "string") { - parsedData = JSON.parse(data); - } else { - parsedData = data; - } - - const { teamId, policyId, sdkInstanceId } = socket; - - // Route based on event type - switch (parsedData.event_type) { - case "metric": - case "control": - case "heartbeat": - case "error": - // Process as event - await controlService.processEvents(teamId!, policyId || null, [parsedData as any]); - - // Update last heartbeat time - if (parsedData.event_type === "heartbeat") { - const instances = connectedInstances.get(teamId!); - const instance = instances?.get(socket.id); - if (instance) { - instance.lastHeartbeat = new Date(); - } - } - break; - - case "get_policy": { - // Request for current policy - const policy = await controlService.getPolicy(teamId!, policyId || null); - socket.emit("message", { - type: "policy", - policy, - }); - break; - } - - default: - console.warn( - `[Aden Control WS] Unknown event type from ${sdkInstanceId!.slice(0, 8)}...: ${parsedData.event_type}` - ); - } - } - - /** - * Create emitter object for external use - */ - const emitter: ControlEmitter = { - /** - * Emit policy update to all SDK instances for a team/policy - * @param teamId - The team ID - * @param policyId - The policy ID (optional, broadcasts to all team instances if not specified) - * @param policy - The policy object - */ - emitPolicyUpdate(teamId: string | number, policyId: string | null, policy: unknown): void { - console.log(`[Aden Control WS] Broadcasting policy update for team ${teamId}`); - - // If policyId specified, emit only to instances using that policy - if (policyId) { - controlEmitter.to(`team:${teamId}:policy:${policyId}`).emit("message", { - type: "policy", - policy, - }); - } else { - // Broadcast to all team instances - controlEmitter.to(`team:${teamId}`).emit("message", { - type: "policy", - policy, - }); - } - }, - - /** - * Emit a command to all SDK instances for a team - */ - emitCommand(teamId: string | number, command: { action: string; [key: string]: unknown }): void { - console.log(`[Aden Control WS] Broadcasting command: ${command.action}`); - - controlEmitter.to(`team:${teamId}`).emit("message", { - type: "command", - command, - }); - }, - - /** - * Emit alert to team instances - */ - emitAlert(teamId: string | number, policyId: string | null, alert: unknown): void { - console.log(`[Aden Control WS] Broadcasting alert for team ${teamId}`); - - const room = policyId ? `team:${teamId}:policy:${policyId}` : `team:${teamId}`; - controlEmitter.to(room).emit("message", { - type: "alert", - alert, - }); - }, - - /** - * Emit to a specific SDK instance - */ - emitToInstance(teamId: string | number, instanceId: string, message: unknown): boolean { - const instances = connectedInstances.get(String(teamId)); - if (!instances) return false; - - for (const [, info] of instances) { - if (info.instanceId === instanceId) { - info.socket.emit("message", message); - return true; - } - } - return false; - }, - - /** - * Get connected instance count for a team (WebSocket + HTTP) - */ - getConnectedCount(teamId: string | number): number { - const teamKey = String(teamId); - const wsCount = connectedInstances.get(teamKey)?.size || 0; - const httpCount = httpInstances.get(teamKey)?.size || 0; - return wsCount + httpCount; - }, - - /** - * Get all connected instances info (for dashboard) - * Includes both WebSocket and HTTP-only agents - */ - getConnectedInstances(teamId: string | number): Array<{ - instance_id: string; - policy_id: string | null; - agent_name: string | null; - connected_at: string; - last_heartbeat: string; - connection_type: "websocket" | "http"; - status?: string; - }> { - const teamKey = String(teamId); - const results: Array<{ - instance_id: string; - policy_id: string | null; - agent_name: string | null; - connected_at: string; - last_heartbeat: string; - connection_type: "websocket" | "http"; - status?: string; - }> = []; - - // Add WebSocket-connected instances - const wsInstances = connectedInstances.get(teamKey); - if (wsInstances) { - for (const info of wsInstances.values()) { - results.push({ - instance_id: info.instanceId, - policy_id: info.policyId, - agent_name: null, // WebSocket connections don't have agent_name yet - connected_at: info.connectedAt.toISOString(), - last_heartbeat: info.lastHeartbeat.toISOString(), - connection_type: "websocket", - }); - } - } - - // Add HTTP-only instances - const httpInsts = httpInstances.get(teamKey); - if (httpInsts) { - for (const info of httpInsts.values()) { - results.push({ - instance_id: info.instanceId, - policy_id: info.policyId, - agent_name: info.agentName, - connected_at: info.firstSeen.toISOString(), - last_heartbeat: info.lastHeartbeat.toISOString(), - connection_type: "http", - status: info.status, - }); - } - } - - return results; - }, - - /** - * Get total connected SDK count across all teams (WebSocket + HTTP) - */ - getTotalConnectedCount(): number { - let total = 0; - for (const instances of connectedInstances.values()) { - total += instances.size; - } - for (const instances of httpInstances.values()) { - total += instances.size; - } - return total; - }, - }; - - // Note: Emitter is returned instead of stored globally - // Use app.locals.controlEmitter to access in routes - - console.log("[Aden Control WS] WebSocket namespace initialized at /v1/control/ws"); - - return emitter; -} - -export default initAdenControlSockets; -export { setUserDbService, registerHttpAgent }; diff --git a/hive/src/services/control/llm_event_batcher.ts b/hive/src/services/control/llm_event_batcher.ts deleted file mode 100644 index 5e1e247a..00000000 --- a/hive/src/services/control/llm_event_batcher.ts +++ /dev/null @@ -1,349 +0,0 @@ -/** - * LLMEventBatcher - Batches LLM events for efficient WebSocket delivery - * - * Features: - * - Per-team in-memory buffers - * - 5-second flush interval (configurable) - * - Buffer size cap with graceful degradation (drop oldest) - * - Payload optimization (only essential fields) - * - Periodic cleanup for idle teams - */ - -const FLUSH_REASONS = { - TIMER: 1, - BUFFER_FULL: 2, - MANUAL: 3, -} as const; - -type FlushReason = typeof FLUSH_REASONS[keyof typeof FLUSH_REASONS]; - -interface TsdbEvent { - timestamp?: Date | string; - trace_id?: string; - model?: string; - provider?: string; - agent?: string; - cost_total?: number; - latency_ms?: number; - usage?: { - input_tokens?: number; - output_tokens?: number; - }; - usage_input_tokens?: number; - usage_output_tokens?: number; -} - -interface EventSummary { - timestamp: string | undefined; - trace_id: string | undefined; - model: string; - provider: string | null; - agent: string | null; - input_tokens: number; - output_tokens: number; - cost: number; - latency_ms: number | null; -} - -interface TeamBuffer { - teamId: string; - events: EventSummary[]; - flushTimer: ReturnType | null; - lastFlush: Date; - droppedCount: number; -} - -interface BatchPayload { - type: string; - teamId: string; - events: EventSummary[]; - meta: { - batchSize: number; - droppedCount: number; - windowStart: string | undefined; - windowEnd: string | undefined; - flushReason: FlushReason; - }; -} - -interface Emitter { - to: (room: string) => { emit: (event: string, payload: BatchPayload) => void }; -} - -interface BatcherOptions { - flushIntervalMs?: number; - maxBufferSize?: number; - maxEventsPerFlush?: number; -} - -class LLMEventBatcher { - private flushIntervalMs: number; - private maxBufferSize: number; - private maxEventsPerFlush: number; - private teamBuffers: Map; - private emitter: Emitter | null; - private totalEventsBuffered: number; - private totalBatchesSent: number; - private totalEventsDropped: number; - private _cleanupInterval: ReturnType; - - constructor(options: BatcherOptions = {}) { - // Configuration - this.flushIntervalMs = options.flushIntervalMs || 5000; // 5 seconds - this.maxBufferSize = options.maxBufferSize || 500; // Max events per team buffer - this.maxEventsPerFlush = options.maxEventsPerFlush || 100; // Max events per batch - - // State - this.teamBuffers = new Map(); // teamId -> TeamBuffer - this.emitter = null; // Set by setEmitter() - - // Metrics - this.totalEventsBuffered = 0; - this.totalBatchesSent = 0; - this.totalEventsDropped = 0; - - // Start periodic cleanup - this._cleanupInterval = setInterval(() => { - this.cleanup(); - }, 300000); // Every 5 minutes - } - - /** - * Set the Socket.IO emitter for broadcasting - * Called during control_sockets initialization - * @param {Object} controlEmitter - Socket.IO namespace emitter - */ - setEmitter(controlEmitter: Emitter): void { - this.emitter = controlEmitter; - console.log("[LLMEventBatcher] Emitter configured"); - } - - /** - * Add events to the buffer for a team - * Called from control_service.js after TSDB insert - * @param {string|number} teamId - Team identifier - * @param {Array} tsdbEvents - Array of TSDB events - */ - add(teamId: string | number, tsdbEvents: TsdbEvent[]): void { - if (!tsdbEvents || tsdbEvents.length === 0) return; - - const teamIdStr = String(teamId); - - // Transform to lightweight summaries - const summaries = tsdbEvents.map((e) => this._transformToSummary(e)); - - // Get or create buffer - let buffer = this.teamBuffers.get(teamIdStr); - if (!buffer) { - buffer = this._createBuffer(teamIdStr); - this.teamBuffers.set(teamIdStr, buffer); - } - - // Add events with overflow handling - this._addToBuffer(buffer, summaries); - - // Start/reset flush timer if not already running - this._scheduleFlush(teamIdStr, buffer); - } - - /** - * Transform full TSDB event to lightweight summary - * Only includes fields needed for dashboard display - * @param {Object} event - Full TSDB event - * @returns {Object} Lightweight event summary - */ - private _transformToSummary(event: TsdbEvent): EventSummary { - // Handle both nested usage object (from transformMetricToTsdbEvent) - // and flat fields (from TSDB query results) - const inputTokens = event.usage?.input_tokens ?? event.usage_input_tokens ?? 0; - const outputTokens = event.usage?.output_tokens ?? event.usage_output_tokens ?? 0; - - return { - timestamp: event.timestamp instanceof Date ? event.timestamp.toISOString() : event.timestamp, - trace_id: event.trace_id, - model: event.model || "", - provider: event.provider || null, - agent: event.agent || null, - input_tokens: inputTokens, - output_tokens: outputTokens, - cost: event.cost_total || 0, - latency_ms: event.latency_ms || null, - }; - } - - /** - * Add events to buffer with overflow handling - * @param {Object} buffer - Team buffer - * @param {Array} summaries - Event summaries to add - */ - private _addToBuffer(buffer: TeamBuffer, summaries: EventSummary[]): void { - for (const summary of summaries) { - if (buffer.events.length >= this.maxBufferSize) { - // Drop oldest event - buffer.events.shift(); - buffer.droppedCount++; - this.totalEventsDropped++; - } - buffer.events.push(summary); - this.totalEventsBuffered++; - } - - // Force flush if buffer is full - if (buffer.events.length >= this.maxBufferSize) { - this._flush(buffer.teamId, FLUSH_REASONS.BUFFER_FULL); - } - } - - /** - * Schedule flush timer for a team - * @param {string} teamId - Team identifier - * @param {Object} buffer - Team buffer - */ - private _scheduleFlush(teamId: string, buffer: TeamBuffer): void { - // Don't reschedule if timer already running - if (buffer.flushTimer) return; - - buffer.flushTimer = setTimeout(() => { - this._flush(teamId, FLUSH_REASONS.TIMER); - }, this.flushIntervalMs); - } - - /** - * Flush buffered events to WebSocket - * @param {string} teamId - Team identifier - * @param {number} flushReason - Reason for flush - */ - private _flush(teamId: string, flushReason: FlushReason): void { - const buffer = this.teamBuffers.get(teamId); - if (!buffer || buffer.events.length === 0) return; - - // Clear timer - if (buffer.flushTimer) { - clearTimeout(buffer.flushTimer); - buffer.flushTimer = null; - } - - // Extract batch (up to maxEventsPerFlush) - const batch = buffer.events.splice(0, this.maxEventsPerFlush); - const droppedCount = buffer.droppedCount; - buffer.droppedCount = 0; - buffer.lastFlush = new Date(); - - // Build payload - const payload: BatchPayload = { - type: "llm-events-batch", - teamId: teamId, - events: batch, - meta: { - batchSize: batch.length, - droppedCount: droppedCount, - windowStart: batch[0]?.timestamp, - windowEnd: batch[batch.length - 1]?.timestamp, - flushReason: flushReason, - }, - }; - - // Emit to team room - if (this.emitter) { - const room = `team:${teamId}:llm-events`; - this.emitter.to(room).emit("message", payload); - this.totalBatchesSent++; - - if (batch.length > 0) { - console.log( - `[LLMEventBatcher] Flushed ${batch.length} events to ${room} ` + - `(dropped: ${droppedCount}, reason: ${flushReason})` - ); - } - } - - // Schedule next flush if buffer still has events - if (buffer.events.length > 0) { - this._scheduleFlush(teamId, buffer); - } - } - - /** - * Create a new buffer for a team - * @param {string} teamId - Team identifier - * @returns {Object} New team buffer - */ - private _createBuffer(teamId: string): TeamBuffer { - return { - teamId: teamId, - events: [], - flushTimer: null, - lastFlush: new Date(), - droppedCount: 0, - }; - } - - /** - * Manually flush all buffers (useful for shutdown) - */ - flushAll(): void { - for (const [teamId] of this.teamBuffers) { - this._flush(teamId, FLUSH_REASONS.MANUAL); - } - } - - /** - * Get metrics for monitoring - * @returns {Object} Batcher metrics - */ - getMetrics(): { activeTeams: number; totalBuffered: number; totalEventsBuffered: number; totalBatchesSent: number; totalEventsDropped: number } { - const activeTeams = this.teamBuffers.size; - const totalBuffered = Array.from(this.teamBuffers.values()).reduce( - (sum, b) => sum + b.events.length, - 0 - ); - - return { - activeTeams, - totalBuffered, - totalEventsBuffered: this.totalEventsBuffered, - totalBatchesSent: this.totalBatchesSent, - totalEventsDropped: this.totalEventsDropped, - }; - } - - /** - * Cleanup buffers for teams with no recent activity - * Prevents memory leaks from inactive teams - * @param {number} maxIdleMs - Max idle time before cleanup (default: 5 minutes) - */ - cleanup(maxIdleMs = 300000): void { - const now = Date.now(); - let cleaned = 0; - - for (const [teamId, buffer] of this.teamBuffers.entries()) { - if (buffer.events.length === 0 && now - buffer.lastFlush.getTime() > maxIdleMs) { - if (buffer.flushTimer) { - clearTimeout(buffer.flushTimer); - } - this.teamBuffers.delete(teamId); - cleaned++; - } - } - - if (cleaned > 0) { - console.log(`[LLMEventBatcher] Cleaned up ${cleaned} idle team buffers`); - } - } - - /** - * Shutdown the batcher (cleanup intervals and flush remaining) - */ - shutdown(): void { - if (this._cleanupInterval) { - clearInterval(this._cleanupInterval); - } - this.flushAll(); - console.log("[LLMEventBatcher] Shutdown complete"); - } -} - -// Singleton instance -const llmEventBatcher = new LLMEventBatcher(); - -export default llmEventBatcher; diff --git a/hive/src/services/mongo/mongo_db.ts b/hive/src/services/mongo/mongo_db.ts deleted file mode 100644 index dcecfd32..00000000 --- a/hive/src/services/mongo/mongo_db.ts +++ /dev/null @@ -1,26 +0,0 @@ -import config from "../../config"; -import { MongoClient } from "mongodb"; - -declare const _ACHO_MG_DB: undefined | { db: (name: string) => unknown }; - -let client: MongoClient | null = null; - -const getMongoClient = async (): Promise => { - if (client) return client; - if (!config.mongodb.url) { - throw new Error("Missing MONGODB_URL in environment"); - } - client = new MongoClient(config.mongodb.url); - await client.connect(); - return client; -}; - -const getMongoDb = async (dbName = config.mongodb.dbName): Promise => { - if (typeof _ACHO_MG_DB !== "undefined" && _ACHO_MG_DB && typeof _ACHO_MG_DB.db === "function") { - return _ACHO_MG_DB.db(dbName); - } - const c = await getMongoClient(); - return c.db(dbName); -}; - -export { getMongoDb }; diff --git a/hive/src/services/quickstart/quickstart_service.ts b/hive/src/services/quickstart/quickstart_service.ts deleted file mode 100644 index 5f3b4a4e..00000000 --- a/hive/src/services/quickstart/quickstart_service.ts +++ /dev/null @@ -1,227 +0,0 @@ -/** - * Quickstart Document Generation Service - * Template-based SDK quickstart documentation generator - * - * Structure: - * - docs/aden-sdk-documents/config/*.json - Configuration for vendors, languages, frameworks - * - docs/aden-sdk-documents/templates/{language}/*.md - Complete template files - */ - -import fs from "fs"; -import path from "path"; - -// Base paths -const DOCS_BASE = path.join(__dirname, "../../../docs/aden-sdk-documents"); -const CONFIG_PATH = path.join(DOCS_BASE, "config"); -const TEMPLATES_PATH = path.join(DOCS_BASE, "templates"); - -interface VendorConfig { - name: string; - envVarComment?: string; -} - -interface LanguageConfig { - name: string; -} - -interface FrameworkConfig { - name: string; - description: string; - templateFile: string; - pythonSupport: boolean; - typescriptSupport: boolean; -} - -interface ConfigCache { - vendors: Record; - languages: Record; - frameworks: Record; -} - -// Cache for configs and templates -let configCache: ConfigCache | null = null; -let templateCache: Record = {}; - -/** - * Load all configuration files - */ -function loadConfigs(): ConfigCache { - if (configCache) return configCache; - - configCache = { - vendors: JSON.parse( - fs.readFileSync(path.join(CONFIG_PATH, "llm-vendors.json"), "utf-8") - ), - languages: JSON.parse( - fs.readFileSync(path.join(CONFIG_PATH, "sdk-languages.json"), "utf-8") - ), - frameworks: JSON.parse( - fs.readFileSync(path.join(CONFIG_PATH, "agent-frameworks.json"), "utf-8") - ), - }; - - return configCache; -} - -/** - * Load a template file - */ -function loadTemplate(language: string, templateName: string): string | null { - const cacheKey = `${language}/${templateName}`; - if (templateCache[cacheKey]) return templateCache[cacheKey]; - - const templatePath = path.join( - TEMPLATES_PATH, - language, - `${templateName}.md` - ); - - if (!fs.existsSync(templatePath)) { - return null; - } - - templateCache[cacheKey] = fs.readFileSync(templatePath, "utf-8"); - return templateCache[cacheKey]; -} - -/** - * Clear caches (useful for development/testing) - */ -function clearCaches(): void { - configCache = null; - templateCache = {}; -} - -/** - * Replace variables in template: {{variableName}} - */ -function replaceVariables( - template: string, - variables: Record -): string { - return template.replace(/\{\{(\w+)\}\}/g, (_match, key) => { - return variables[key] !== undefined ? variables[key] : ""; - }); -} - -interface GenerateQuickstartParams { - llmVendor?: string; - sdkLanguage?: string; - agentFramework: string; - apiKey: string; -} - -/** - * Generate quickstart document based on parameters - */ -function generateQuickstart({ - llmVendor = "openai", - sdkLanguage = "python", - agentFramework, - apiKey, -}: GenerateQuickstartParams): string { - const config = loadConfigs(); - - // Validate inputs - if (!config.vendors[llmVendor]) { - throw new Error( - `Invalid LLM vendor: ${llmVendor}. Valid options: ${Object.keys( - config.vendors - ).join(", ")}` - ); - } - if (!config.languages[sdkLanguage]) { - throw new Error( - `Invalid SDK language: ${sdkLanguage}. Valid options: ${Object.keys( - config.languages - ).join(", ")}` - ); - } - if (!config.frameworks[agentFramework]) { - throw new Error( - `Invalid agent framework: ${agentFramework}. Valid options: ${Object.keys( - config.frameworks - ).join(", ")}` - ); - } - if (!apiKey) { - throw new Error("API key is required"); - } - - const vendor = config.vendors[llmVendor]; - const framework = config.frameworks[agentFramework]; - - // Check language support - if (sdkLanguage === "python" && !framework.pythonSupport) { - throw new Error(`${framework.name} does not support Python`); - } - if (sdkLanguage !== "python" && !framework.typescriptSupport) { - throw new Error(`${framework.name} does not support ${sdkLanguage}`); - } - - // Load template - const template = loadTemplate(sdkLanguage, framework.templateFile); - - if (!template) { - throw new Error( - `Template not found: ${sdkLanguage}/${framework.templateFile}` - ); - } - - // Build variables - const variables: Record = { - apiKey, - serverUrl: process.env.HIVE_HOST || "https://hive.adenhq.com", - envVarComment: vendor.envVarComment || "", - }; - - // Replace variables and return - return replaceVariables(template, variables); -} - -interface QuickstartOptions { - llmVendors: Array<{ id: string; name: string }>; - sdkLanguages: Array<{ id: string; name: string }>; - agentFrameworks: Array<{ - id: string; - name: string; - description: string; - pythonSupport: boolean; - typescriptSupport: boolean; - }>; -} - -/** - * Get available options for quickstart generation - */ -function getQuickstartOptions(): QuickstartOptions { - const config = loadConfigs(); - - return { - llmVendors: Object.entries(config.vendors).map(([key, value]) => ({ - id: key, - name: value.name, - })), - sdkLanguages: Object.entries(config.languages).map(([key, value]) => ({ - id: key, - name: value.name, - })), - agentFrameworks: Object.entries(config.frameworks).map(([key, value]) => ({ - id: key, - name: value.name, - description: value.description, - pythonSupport: value.pythonSupport, - typescriptSupport: value.typescriptSupport, - })), - }; -} - -/** - * Reload configs (useful after updating config files) - */ -function reloadConfigs(): ConfigCache { - clearCaches(); - return loadConfigs(); -} - -export { generateQuickstart, getQuickstartOptions, reloadConfigs, clearCaches }; diff --git a/hive/src/services/tsdb/00-init-timescaledb.sql b/hive/src/services/tsdb/00-init-timescaledb.sql deleted file mode 100644 index 40e8046c..00000000 --- a/hive/src/services/tsdb/00-init-timescaledb.sql +++ /dev/null @@ -1,11 +0,0 @@ --- Initialize TimescaleDB extension --- This must run BEFORE schema.sql to enable hypertables and continuous aggregates - --- Create TimescaleDB extension -CREATE EXTENSION IF NOT EXISTS timescaledb; - --- Log successful initialization -DO $$ -BEGIN - RAISE NOTICE 'TimescaleDB extension initialized successfully'; -END$$; diff --git a/hive/src/services/tsdb/analytics_service.ts b/hive/src/services/tsdb/analytics_service.ts deleted file mode 100644 index ea52e330..00000000 --- a/hive/src/services/tsdb/analytics_service.ts +++ /dev/null @@ -1,748 +0,0 @@ -/** - * TSDB Analytics Service - * Computes windowed aggregations from llm_events for dashboard analytics. - */ - -import { PoolClient } from 'pg'; -import pricingService from './pricing_service'; - -const BUCKETS = [ - { label: '0-1s', min: 0, max: 1000 }, - { label: '1-2s', min: 1000, max: 2000 }, - { label: '2-5s', min: 2000, max: 5000 }, - { label: '5-10s', min: 5000, max: 10000 }, - { label: '10-20s', min: 10000, max: 20000 }, - { label: '20s+', min: 20000, max: null as number | null }, -]; - -interface WindowDef { - label: string; - start: Date | null; - end: Date; -} - -interface DailyRow { - bucket: string; - requests: number; - cost_total: number; - tokens: { - total: number; - input: number; - output: number; - cached: number; - }; -} - -interface LatencyRow { - bucket: string; - count: number; - avg_ms: number | null; - p50_ms: number | null; - p95_ms: number | null; - p99_ms: number | null; -} - -interface ModelCostRow { - model: string; - cost_total: number; - cached_tokens: number; -} - -interface AgentCostRow { - agent: string; - requests: number; - cost_total: number; - input_tokens: number; - output_tokens: number; - avg_latency_ms: number | null; -} - -const toNumber = (val: unknown, fallback = 0): number => { - const n = Number(val); - return Number.isFinite(n) ? n : fallback; -}; - -const percentile = (values: number[], pct: number): number | null => { - if (!values.length) return null; - const sorted = [...values].sort((a, b) => a - b); - if (sorted.length === 1) return sorted[0]; - const idx = Math.max(0, Math.min(sorted.length - 1, Math.floor(pct * (sorted.length - 1)))); - return sorted[idx]; -}; - -const startOfWeekUtc = (d: Date): Date => { - const day = d.getUTCDay(); - const diff = (day + 6) % 7; - const monday = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), 0, 0, 0, 0)); - monday.setUTCDate(monday.getUTCDate() - diff); - return monday; -}; - -const startOfMonthUtc = (d: Date): Date => - new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), 1, 0, 0, 0, 0)); - -const startOfDayUtc = (d: Date): Date => - new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), 0, 0, 0, 0)); - -export const parseAnalyticsWindow = (label: string): WindowDef => { - const now = new Date(); - switch ((label || '').toLowerCase()) { - case 'all_time': - case 'all-time': - case 'alltime': - return { label: 'all_time', start: null, end: now }; - case 'today': { - const start = startOfDayUtc(now); - return { label: 'today', start, end: now }; - } - case 'last_2_weeks': - case 'last-2-weeks': - case 'last2weeks': { - const start = new Date(now.getTime() - 14 * 24 * 3600 * 1000); - return { label: 'last_2_weeks', start, end: now }; - } - case 'this_week': { - const start = startOfWeekUtc(now); - return { label: 'this_week', start, end: now }; - } - case 'this_month': - default: { - const start = startOfMonthUtc(now); - return { label: 'this_month', start, end: now }; - } - } -}; - -const bucketLatency = (latMs: number, buckets: typeof BUCKETS): string | null => { - if (latMs === null || latMs === undefined) return null; - for (const b of buckets) { - if (b.max === null) { - if (latMs >= b.min) return b.label; - } else if (latMs >= b.min && latMs < b.max) { - return b.label; - } - } - return null; -}; - -const buildLatencyDistribution = (rows: { bucket: string; count: number }[]) => { - const counts = new Map(rows.map((r) => [r.bucket, r.count])); - const total = rows.reduce((acc, r) => acc + (r.count || 0), 0); - return BUCKETS.map((b) => { - const count = counts.get(b.label) || 0; - return { - bucket: b.label, - count, - share: total ? count / total : null, - }; - }); -}; - -const bucketLabel = (date: Date, resolution: string): string => { - if (resolution === 'hour') { - const h = new Date( - Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), 0, 0, 0) - ); - return h.toISOString().slice(0, 13) + ':00:00Z'; - } - return date.toISOString().slice(0, 10); -}; - -const fetchDailyCA = async ({ - client, - start, - end, -}: { - client: PoolClient; - start: Date | null; - end: Date | null; -}): Promise => { - const params: (Date | null)[] = []; - const conds: string[] = []; - if (start) { - params.push(start); - conds.push(`bucket >= $${params.length}`); - } - if (end) { - params.push(end); - conds.push(`bucket < $${params.length}`); - } - const sql = ` - SELECT bucket, requests, cost_total, input_tokens, output_tokens, total_tokens, cached_tokens - FROM llm_events_daily_ca - ${conds.length ? `WHERE ${conds.join(' AND ')}` : ''} - ORDER BY bucket ASC - `; - const { rows } = await client.query(sql, params); - return rows.map((r: any) => ({ - bucket: r.bucket instanceof Date ? r.bucket.toISOString().slice(0, 10) : r.bucket, - requests: Number(r.requests) || 0, - cost_total: toNumber(r.cost_total, 0), - tokens: { - total: toNumber(r.total_tokens, 0), - input: toNumber(r.input_tokens, 0), - output: toNumber(r.output_tokens, 0), - cached: toNumber(r.cached_tokens, 0), - }, - })); -}; - -const fetchTodayFromBaseTable = async ({ - client, - todayStart, - end, -}: { - client: PoolClient; - todayStart: Date; - end: Date; -}): Promise => { - const sql = ` - SELECT - $1::date as bucket, - COUNT(*) as requests, - COALESCE(SUM(cost_total), 0) as cost_total, - COALESCE(SUM(usage_input_tokens), 0) as input_tokens, - COALESCE(SUM(usage_output_tokens), 0) as output_tokens, - COALESCE(SUM(COALESCE(usage_total_tokens, usage_input_tokens + usage_output_tokens)), 0) as total_tokens, - COALESCE(SUM(usage_cached_tokens), 0) as cached_tokens - FROM llm_events - WHERE "timestamp" >= $1 AND "timestamp" <= $2 - `; - const { rows } = await client.query(sql, [todayStart, end]); - if (!rows.length || rows[0].requests === 0 || rows[0].requests === '0') { - return null; - } - const r = rows[0]; - return { - bucket: todayStart.toISOString().slice(0, 10), - requests: Number(r.requests) || 0, - cost_total: toNumber(r.cost_total, 0), - tokens: { - total: toNumber(r.total_tokens, 0), - input: toNumber(r.input_tokens, 0), - output: toNumber(r.output_tokens, 0), - cached: toNumber(r.cached_tokens, 0), - }, - }; -}; - -const fetchLatencyDaily = async ({ - client, - start, - end, -}: { - client: PoolClient; - start: Date | null; - end: Date | null; -}): Promise => { - const params: (string | Date)[] = ['1 day']; - const conds = ['latency_ms IS NOT NULL']; - if (start) { - params.push(start); - conds.push(`"timestamp" >= $${params.length}`); - } - if (end) { - params.push(end); - conds.push(`"timestamp" < $${params.length}`); - } - const sql = ` - SELECT - time_bucket($1::interval, "timestamp") AS bucket, - COUNT(latency_ms) AS count, - AVG(latency_ms) AS avg_ms, - percentile_cont(0.5) WITHIN GROUP (ORDER BY latency_ms) AS p50_ms, - percentile_cont(0.95) WITHIN GROUP (ORDER BY latency_ms) AS p95_ms, - percentile_cont(0.99) WITHIN GROUP (ORDER BY latency_ms) AS p99_ms - FROM llm_events - WHERE ${conds.join(' AND ')} - GROUP BY 1 - ORDER BY 1 ASC - `; - const { rows } = await client.query(sql, params); - return rows.map((r: any) => ({ - bucket: r.bucket instanceof Date ? r.bucket.toISOString().slice(0, 10) : r.bucket, - count: Number(r.count) || 0, - avg_ms: r.avg_ms === null ? null : Number(r.avg_ms), - p50_ms: r.p50_ms === null ? null : Number(r.p50_ms), - p95_ms: r.p95_ms === null ? null : Number(r.p95_ms), - p99_ms: r.p99_ms === null ? null : Number(r.p99_ms), - })); -}; - -const fetchLatencyDistributionDaily = async ({ - client, - start, - end, -}: { - client: PoolClient; - start: Date | null; - end: Date | null; -}): Promise<{ bucket: string; count: number }[]> => { - const params: Date[] = []; - const conds = ['latency_ms IS NOT NULL']; - if (start) { - params.push(start); - conds.push(`"timestamp" >= $${params.length}`); - } - if (end) { - params.push(end); - conds.push(`"timestamp" < $${params.length}`); - } - const sql = ` - SELECT - CASE - WHEN latency_ms < 1000 THEN '0-1s' - WHEN latency_ms < 2000 THEN '1-2s' - WHEN latency_ms < 5000 THEN '2-5s' - WHEN latency_ms < 10000 THEN '5-10s' - WHEN latency_ms < 20000 THEN '10-20s' - ELSE '20s+' - END AS bucket, - COUNT(*) AS count - FROM llm_events - WHERE ${conds.join(' AND ')} - GROUP BY 1 - `; - const { rows } = await client.query(sql, params); - return rows.map((r: any) => ({ bucket: r.bucket, count: Number(r.count) || 0 })); -}; - -const fetchModelCost = async ({ - client, - start, - end, -}: { - client: PoolClient; - start: Date | null; - end: Date | null; -}): Promise => { - const params: Date[] = []; - const conds: string[] = []; - if (start) { - params.push(start); - conds.push(`"timestamp" >= $${params.length}`); - } - if (end) { - params.push(end); - conds.push(`"timestamp" < $${params.length}`); - } - const sql = ` - SELECT model, - SUM(cost_total) AS cost_total, - SUM(usage_cached_tokens) AS cached_tokens - FROM llm_events - ${conds.length ? `WHERE ${conds.join(' AND ')}` : ''} - GROUP BY model - `; - const { rows } = await client.query(sql, params); - return rows - .filter((r: any) => r.model) - .map((r: any) => ({ - model: r.model, - cost_total: toNumber(r.cost_total, 0), - cached_tokens: toNumber(r.cached_tokens, 0), - })); -}; - -const fetchAgentCost = async ({ - client, - start, - end, -}: { - client: PoolClient; - start: Date | null; - end: Date | null; -}): Promise => { - const params: Date[] = []; - const conds: string[] = []; - if (start) { - params.push(start); - conds.push(`"timestamp" >= $${params.length}`); - } - if (end) { - params.push(end); - conds.push(`"timestamp" < $${params.length}`); - } - const sql = ` - SELECT agent, - COUNT(*) AS requests, - SUM(cost_total) AS cost_total, - SUM(usage_input_tokens) AS input_tokens, - SUM(usage_output_tokens) AS output_tokens, - AVG(latency_ms) AS avg_latency_ms - FROM llm_events - ${conds.length ? `WHERE ${conds.join(' AND ')}` : ''} - GROUP BY agent - `; - const { rows } = await client.query(sql, params); - return rows - .filter((r: any) => r.agent) - .map((r: any) => ({ - agent: r.agent, - requests: Number(r.requests) || 0, - cost_total: toNumber(r.cost_total, 0), - input_tokens: toNumber(r.input_tokens, 0), - output_tokens: toNumber(r.output_tokens, 0), - avg_latency_ms: r.avg_latency_ms === null ? null : Number(r.avg_latency_ms), - })); -}; - -export const buildAnalytics = async ({ - windowLabel, - client, - resolution = 'day', -}: { - windowLabel: string; - client: PoolClient; - resolution?: 'day' | 'hour'; -}) => { - const windowDef = parseAnalyticsWindow(windowLabel); - - if (resolution === 'day') { - try { - const now = windowDef.end || new Date(); - const todayMidnight = new Date( - Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), 0, 0, 0, 0) - ); - - const caRows = await fetchDailyCA({ client, start: windowDef.start, end: todayMidnight }); - - let todayData: DailyRow | null = null; - if (now >= todayMidnight) { - try { - todayData = await fetchTodayFromBaseTable({ client, todayStart: todayMidnight, end: now }); - } catch { - // Ignore errors fetching today's data - } - } - - const allRows = [...(caRows || [])]; - if (todayData) { - const todayBucket = todayData.bucket; - const existingIdx = allRows.findIndex((r) => r.bucket === todayBucket); - if (existingIdx >= 0) { - allRows[existingIdx] = todayData; - } else { - allRows.push(todayData); - } - } - - if (allRows && allRows.length) { - const total_cost = allRows.reduce((acc, r) => acc + (r.cost_total || 0), 0); - const total_requests = allRows.reduce((acc, r) => acc + (r.requests || 0), 0); - const total_tokens = allRows.reduce((acc, r) => acc + (r.tokens.total || 0), 0); - - const bucket_cost = allRows.map((r) => ({ bucket: r.bucket, cost_total: r.cost_total })); - const bucket_requests = allRows.map((r) => ({ bucket: r.bucket, requests: r.requests })); - const bucket_tokens = allRows.map((r) => ({ - bucket: r.bucket, - total_tokens: r.tokens.total, - input_tokens: r.tokens.input, - output_tokens: r.tokens.output, - cached_tokens: r.tokens.cached, - })); - - const latencyBuckets = await fetchLatencyDaily({ - client, - start: windowDef.start, - end: windowDef.end, - }); - const latencyDistributionRows = await fetchLatencyDistributionDaily({ - client, - start: windowDef.start, - end: windowDef.end, - }); - const latency_distribution = buildLatencyDistribution(latencyDistributionRows); - const latency_total = latencyDistributionRows.reduce((acc, r) => acc + (r.count || 0), 0); - const avg_latency_ms = - latencyBuckets.reduce( - (acc, r) => acc + (r.avg_ms !== null ? r.avg_ms * (r.count || 0) : 0), - 0 - ) / (latency_total || 1); - - const modelRows = await fetchModelCost({ client, start: windowDef.start, end: windowDef.end }); - const models = modelRows - .sort((a, b) => (b.cost_total || 0) - (a.cost_total || 0)) - .map((r) => ({ - model: r.model, - cost_total: r.cost_total, - share: total_cost ? r.cost_total / total_cost : null, - })); - const cache_savings = modelRows.reduce((acc, r) => { - const pricing = pricingService.getModelPricingSync(r.model || ''); - return acc + (r.cached_tokens / 1_000_000) * pricing.input; - }, 0); - - const agentRows = await fetchAgentCost({ client, start: windowDef.start, end: windowDef.end }); - const agents = agentRows - .sort((a, b) => (b.cost_total || 0) - (a.cost_total || 0)) - .map((r) => ({ - agent: r.agent, - requests: r.requests, - cost_total: r.cost_total, - share: total_cost ? r.cost_total / total_cost : null, - avg_latency_ms: r.avg_latency_ms, - })); - - return { - window: { - label: windowDef.label, - start: windowDef.start ? windowDef.start.toISOString() : null, - end: windowDef.end ? windowDef.end.toISOString() : null, - }, - summary: { - total_cost, - total_requests, - total_tokens, - avg_latency_ms: Number.isFinite(avg_latency_ms) ? avg_latency_ms : null, - cache_savings, - }, - timeline: { - resolution: 'day', - daily: { - cost: bucket_cost, - requests: bucket_requests, - tokens: bucket_tokens, - latency_percentiles: latencyBuckets, - }, - }, - cost_by_model: { - total_cost, - models, - }, - cost_by_agent: { - total_cost, - agents, - }, - latency_distribution: { - total: latency_total, - buckets: latency_distribution, - }, - }; - } - } catch (err) { - // Fall through to base-table path - } - } - - // Fallback: scan base table directly - const params: Date[] = []; - const conditions: string[] = []; - if (windowDef.start) { - params.push(windowDef.start); - conditions.push(`"timestamp" >= $${params.length}`); - } - if (windowDef.end) { - params.push(windowDef.end); - conditions.push(`"timestamp" < $${params.length}`); - } - - const sql = ` - SELECT - "timestamp", - model, - agent, - latency_ms, - cost_total, - usage_input_tokens, - usage_output_tokens, - usage_total_tokens, - usage_cached_tokens - FROM llm_events - ${conditions.length ? `WHERE ${conditions.join(' AND ')}` : ''} - ORDER BY "timestamp" ASC - `; - - const { rows } = await client.query(sql, params); - - const bucketCost = new Map(); - const bucketRequests = new Map(); - const bucketTokens = new Map(); - const bucketLatencies = new Map(); - const modelCost = new Map(); - const agentStats = new Map(); - const latencyBucketCounts = new Map(); - - let totalCost = 0; - let totalRequests = 0; - let totalTokens = 0; - let totalLatency = 0; - let latencyCount = 0; - let cacheSavings = 0; - - rows.forEach((r: any) => { - const ts = r.timestamp instanceof Date ? r.timestamp : new Date(r.timestamp); - if (!ts || Number.isNaN(ts.getTime())) return; - const bucket = bucketLabel(ts, resolution); - - const cost = toNumber(r.cost_total, 0); - const inTok = toNumber(r.usage_input_tokens, 0); - const outTok = toNumber(r.usage_output_tokens, 0); - const totalTokRaw = toNumber(r.usage_total_tokens, inTok + outTok); - const cachedTok = toNumber(r.usage_cached_tokens, 0); - const lat = r.latency_ms === null || r.latency_ms === undefined ? null : Number(r.latency_ms); - - totalRequests += 1; - totalCost += cost; - totalTokens += totalTokRaw; - if (lat !== null && !Number.isNaN(lat)) { - totalLatency += lat; - latencyCount += 1; - } - - bucketCost.set(bucket, (bucketCost.get(bucket) || 0) + cost); - bucketRequests.set(bucket, (bucketRequests.get(bucket) || 0) + 1); - const tok = bucketTokens.get(bucket) || { total: 0, input: 0, output: 0, cached: 0 }; - tok.total += totalTokRaw; - tok.input += inTok; - tok.output += outTok; - tok.cached += cachedTok; - bucketTokens.set(bucket, tok); - - if (lat !== null && !Number.isNaN(lat)) { - const arr = bucketLatencies.get(bucket) || []; - arr.push(lat); - bucketLatencies.set(bucket, arr); - - const latBucket = bucketLatency(lat, BUCKETS); - if (latBucket) latencyBucketCounts.set(latBucket, (latencyBucketCounts.get(latBucket) || 0) + 1); - } - - if (r.model) { - modelCost.set(r.model, (modelCost.get(r.model) || 0) + cost); - } - - if (r.agent) { - const stats = agentStats.get(r.agent) || { cost: 0, requests: 0, latencies: [] }; - stats.cost += cost; - stats.requests += 1; - if (lat !== null && !Number.isNaN(lat)) { - stats.latencies.push(lat); - } - agentStats.set(r.agent, stats); - } - - if (cachedTok > 0) { - const pricing = pricingService.getModelPricingSync(r.model || ''); - cacheSavings += (cachedTok / 1_000_000) * pricing.input; - } - }); - - const sortedBuckets = Array.from( - new Set([ - ...bucketCost.keys(), - ...bucketRequests.keys(), - ...bucketTokens.keys(), - ...bucketLatencies.keys(), - ]) - ).sort(); - - const bucket_cost = sortedBuckets.map((key) => ({ bucket: key, cost_total: bucketCost.get(key) || 0 })); - const bucket_requests = sortedBuckets.map((key) => ({ - bucket: key, - requests: bucketRequests.get(key) || 0, - })); - const bucket_tokens = sortedBuckets.map((key) => { - const tok = bucketTokens.get(key) || { total: 0, input: 0, output: 0, cached: 0 }; - return { - bucket: key, - total_tokens: tok.total, - input_tokens: tok.input, - output_tokens: tok.output, - cached_tokens: tok.cached, - }; - }); - const bucket_latency_percentiles = sortedBuckets.map((key) => { - const lats = bucketLatencies.get(key) || []; - return { - bucket: key, - count: lats.length, - avg_ms: lats.length ? lats.reduce((a, b) => a + b, 0) / lats.length : null, - p50_ms: percentile(lats, 0.5), - p95_ms: percentile(lats, 0.95), - p99_ms: percentile(lats, 0.99), - }; - }); - - const latency_total = Array.from(latencyBucketCounts.values()).reduce((a, b) => a + b, 0); - const latency_distribution = BUCKETS.map((b) => { - const count = latencyBucketCounts.get(b.label) || 0; - return { - bucket: b.label, - count, - share: latency_total ? count / latency_total : null, - }; - }); - - const models = Array.from(modelCost.entries()) - .sort((a, b) => (b[1] || 0) - (a[1] || 0)) - .map(([model, cost]) => ({ - model, - cost_total: cost, - share: totalCost ? cost / totalCost : null, - })); - - const agents = Array.from(agentStats.entries()) - .sort((a, b) => (b[1].cost || 0) - (a[1].cost || 0)) - .map(([agent, stats]) => ({ - agent, - requests: stats.requests, - cost_total: stats.cost, - share: totalCost ? stats.cost / totalCost : null, - avg_latency_ms: stats.latencies.length - ? stats.latencies.reduce((a, b) => a + b, 0) / stats.latencies.length - : null, - })); - - return { - window: { - label: windowDef.label, - start: windowDef.start ? windowDef.start.toISOString() : null, - end: windowDef.end ? windowDef.end.toISOString() : null, - }, - summary: { - total_cost: totalCost, - total_requests: totalRequests, - total_tokens: totalTokens, - avg_latency_ms: latencyCount ? totalLatency / latencyCount : null, - cache_savings: cacheSavings, - }, - timeline: - resolution === 'hour' - ? { - resolution: 'hour', - hourly: { - cost: bucket_cost, - requests: bucket_requests, - tokens: bucket_tokens, - latency_percentiles: bucket_latency_percentiles, - }, - } - : { - resolution: 'day', - daily: { - cost: bucket_cost, - requests: bucket_requests, - tokens: bucket_tokens, - latency_percentiles: bucket_latency_percentiles, - }, - }, - cost_by_model: { - total_cost: totalCost, - models, - }, - cost_by_agent: { - total_cost: totalCost, - agents, - }, - latency_distribution: { - total: latency_total, - buckets: latency_distribution, - }, - }; -}; - -export default { - buildAnalytics, - parseAnalyticsWindow, -}; diff --git a/hive/src/services/tsdb/pricing_service.ts b/hive/src/services/tsdb/pricing_service.ts deleted file mode 100644 index 7ee7ea29..00000000 --- a/hive/src/services/tsdb/pricing_service.ts +++ /dev/null @@ -1,743 +0,0 @@ -/** - * LLM Pricing Service - * - * Centralized pricing table for calculating costs by provider and model. - * Prices are stored in MongoDB and cached in memory for performance. - * Prices are in USD per 1M tokens (industry standard). - * - * Sources: - * - OpenAI: https://openai.com/pricing - * - Anthropic: https://www.anthropic.com/pricing - * - Google: https://ai.google.dev/pricing - * - AWS Bedrock: https://aws.amazon.com/bedrock/pricing/ - */ - -// In-memory cache for pricing data -const pricingCache = new Map(); -const aliasCacheMap = new Map(); // model alias -> canonical model -let cacheLoadedAt: number | null = null; -const CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes - -interface PricingEntry { - model: string; - provider: string; - input: number; - output: number; - cached_input: number; - aliases: string[]; - effective_date?: Date; - updated_at?: Date; - source?: string; -} - -interface PricingTableEntry { - provider: string; - input: number; - output: number; - cached_input: number; - aliases: string[]; -} - -// Fallback pricing for unknown models (conservative estimate) -const DEFAULT_PRICING = { input: 1.00, output: 3.00, cached_input: 0.25 }; - -// Default pricing table for seeding - USD per 1M tokens -// Updated: 2025-01-01 -const DEFAULT_PRICING_TABLE: Record = { - // OpenAI Models - "gpt-4o": { provider: "openai", input: 2.50, output: 10.00, cached_input: 1.25, aliases: ["gpt-4o-2024-11-20", "gpt-4o-2024-08-06"] }, - "gpt-4o-2024-05-13": { provider: "openai", input: 5.00, output: 15.00, cached_input: 2.50, aliases: [] }, - "gpt-4o-mini": { provider: "openai", input: 0.15, output: 0.60, cached_input: 0.075, aliases: ["gpt-4o-mini-2024-07-18"] }, - "gpt-4-turbo": { provider: "openai", input: 10.00, output: 30.00, cached_input: 5.00, aliases: ["gpt-4-turbo-2024-04-09", "gpt-4-turbo-preview"] }, - "gpt-4": { provider: "openai", input: 30.00, output: 60.00, cached_input: 15.00, aliases: ["gpt-4-0613"] }, - "gpt-3.5-turbo": { provider: "openai", input: 0.50, output: 1.50, cached_input: 0.25, aliases: ["gpt-3.5-turbo-0125"] }, - "o1": { provider: "openai", input: 15.00, output: 60.00, cached_input: 7.50, aliases: ["o1-2024-12-17", "o1-preview"] }, - "o1-mini": { provider: "openai", input: 3.00, output: 12.00, cached_input: 1.50, aliases: ["o1-mini-2024-09-12"] }, - "o3-mini": { provider: "openai", input: 1.10, output: 4.40, cached_input: 0.55, aliases: [] }, - - // Anthropic Models - "claude-3-5-sonnet-20241022": { provider: "anthropic", input: 3.00, output: 15.00, cached_input: 0.30, aliases: ["claude-3-5-sonnet-20240620", "claude-3-5-sonnet-latest"] }, - "claude-sonnet-4-20250514": { provider: "anthropic", input: 3.00, output: 15.00, cached_input: 0.30, aliases: ["claude-sonnet-4-5-20250929"] }, - "claude-3-5-haiku-20241022": { provider: "anthropic", input: 0.80, output: 4.00, cached_input: 0.08, aliases: ["claude-3-5-haiku-latest"] }, - "claude-3-opus-20240229": { provider: "anthropic", input: 15.00, output: 75.00, cached_input: 1.50, aliases: ["claude-3-opus-latest"] }, - "claude-3-sonnet-20240229": { provider: "anthropic", input: 3.00, output: 15.00, cached_input: 0.30, aliases: [] }, - "claude-3-haiku-20240307": { provider: "anthropic", input: 0.25, output: 1.25, cached_input: 0.025, aliases: [] }, - "claude-opus-4-5-20251101": { provider: "anthropic", input: 15.00, output: 75.00, cached_input: 1.50, aliases: ["claude-opus-4-20250514"] }, - - // Google Models - "gemini-2.0-flash": { provider: "google", input: 0.10, output: 0.40, cached_input: 0.025, aliases: ["gemini-2.0-flash-exp"] }, - "gemini-1.5-flash": { provider: "google", input: 0.075, output: 0.30, cached_input: 0.01875, aliases: ["gemini-1.5-flash-latest"] }, - "gemini-1.5-flash-8b": { provider: "google", input: 0.0375, output: 0.15, cached_input: 0.01, aliases: [] }, - "gemini-1.5-pro": { provider: "google", input: 1.25, output: 5.00, cached_input: 0.3125, aliases: ["gemini-1.5-pro-latest"] }, - "gemini-1.0-pro": { provider: "google", input: 0.50, output: 1.50, cached_input: 0.125, aliases: ["gemini-pro"] }, - "gemini-exp-1206": { provider: "google", input: 0.00, output: 0.00, cached_input: 0.00, aliases: [] }, - - // AWS Bedrock - Claude (cross-region inference) - "anthropic.claude-3-5-sonnet-20241022-v2:0": { provider: "bedrock", input: 3.00, output: 15.00, cached_input: 0.30, aliases: [] }, - "anthropic.claude-3-5-haiku-20241022-v1:0": { provider: "bedrock", input: 0.80, output: 4.00, cached_input: 0.08, aliases: [] }, - "anthropic.claude-3-opus-20240229-v1:0": { provider: "bedrock", input: 15.00, output: 75.00, cached_input: 1.50, aliases: [] }, - "anthropic.claude-3-sonnet-20240229-v1:0": { provider: "bedrock", input: 3.00, output: 15.00, cached_input: 0.30, aliases: [] }, - "anthropic.claude-3-haiku-20240307-v1:0": { provider: "bedrock", input: 0.25, output: 1.25, cached_input: 0.025, aliases: [] }, - - // AWS Bedrock - Amazon Models - "amazon.nova-pro-v1:0": { provider: "bedrock", input: 0.80, output: 3.20, cached_input: 0.20, aliases: [] }, - "amazon.nova-lite-v1:0": { provider: "bedrock", input: 0.06, output: 0.24, cached_input: 0.015, aliases: [] }, - "amazon.nova-micro-v1:0": { provider: "bedrock", input: 0.035, output: 0.14, cached_input: 0.00875, aliases: [] }, - "amazon.titan-text-express-v1": { provider: "bedrock", input: 0.20, output: 0.60, cached_input: 0.05, aliases: [] }, - "amazon.titan-text-lite-v1": { provider: "bedrock", input: 0.15, output: 0.20, cached_input: 0.0375, aliases: [] }, - - // Mistral Models - "mistral-large-latest": { provider: "mistral", input: 2.00, output: 6.00, cached_input: 0.50, aliases: ["mistral-large-2411"] }, - "mistral-medium-latest": { provider: "mistral", input: 2.70, output: 8.10, cached_input: 0.675, aliases: [] }, - "mistral-small-latest": { provider: "mistral", input: 0.20, output: 0.60, cached_input: 0.05, aliases: ["mistral-small-2409"] }, - "codestral-latest": { provider: "mistral", input: 0.30, output: 0.90, cached_input: 0.075, aliases: [] }, - "pixtral-large-latest": { provider: "mistral", input: 2.00, output: 6.00, cached_input: 0.50, aliases: [] }, - "ministral-8b-latest": { provider: "mistral", input: 0.10, output: 0.10, cached_input: 0.025, aliases: [] }, - "ministral-3b-latest": { provider: "mistral", input: 0.04, output: 0.04, cached_input: 0.01, aliases: [] }, - - // Cohere Models - "command-r-plus": { provider: "cohere", input: 2.50, output: 10.00, cached_input: 0.625, aliases: [] }, - "command-r": { provider: "cohere", input: 0.15, output: 0.60, cached_input: 0.0375, aliases: [] }, - "command": { provider: "cohere", input: 1.00, output: 2.00, cached_input: 0.25, aliases: [] }, - "command-light": { provider: "cohere", input: 0.30, output: 0.60, cached_input: 0.075, aliases: [] }, - - // DeepSeek Models - "deepseek-chat": { provider: "deepseek", input: 0.14, output: 0.28, cached_input: 0.014, aliases: [] }, - "deepseek-reasoner": { provider: "deepseek", input: 0.55, output: 2.19, cached_input: 0.055, aliases: [] }, - - // Groq Models (inference pricing, not training) - "llama-3.3-70b-versatile": { provider: "groq", input: 0.59, output: 0.79, cached_input: 0.15, aliases: [] }, - "llama-3.1-70b-versatile": { provider: "groq", input: 0.59, output: 0.79, cached_input: 0.15, aliases: [] }, - "llama-3.1-8b-instant": { provider: "groq", input: 0.05, output: 0.08, cached_input: 0.0125, aliases: [] }, - "llama-3.2-90b-vision-preview": { provider: "groq", input: 0.90, output: 0.90, cached_input: 0.225, aliases: [] }, - "mixtral-8x7b-32768": { provider: "groq", input: 0.24, output: 0.24, cached_input: 0.06, aliases: [] }, -}; - -declare const _ACHO_MG_DB: { db: (name: string) => { collection: (name: string) => unknown } }; -declare const _ACHO_MDB_CONFIG: { ERP_DBNAME: string }; -declare const _ACHO_MDB_COLLECTIONS: { ADEN_LLM_PRICING: string }; - -interface MongoCollection { - find: (query: Record) => { toArray: () => Promise; sort: (sort: Record) => { toArray: () => Promise } }; - findOne: (query: Record) => Promise; - findOneAndUpdate: (query: Record, update: Record, options: Record) => Promise; - deleteOne: (query: Record) => Promise<{ deletedCount: number }>; - insertOne: (doc: Record) => Promise; - updateOne: (query: Record, update: Record) => Promise; -} - -/** - * Get the MongoDB collection for pricing - * @returns {Collection} MongoDB collection - */ -function getPricingCollection(): MongoCollection { - const db = _ACHO_MG_DB.db(_ACHO_MDB_CONFIG.ERP_DBNAME); - return db.collection(_ACHO_MDB_COLLECTIONS.ADEN_LLM_PRICING) as MongoCollection; -} - -/** - * Check if cache is still valid - * @returns {boolean} - */ -function isCacheValid(): boolean { - if (!cacheLoadedAt || pricingCache.size === 0) return false; - return Date.now() - cacheLoadedAt < CACHE_TTL_MS; -} - -interface DbPricingDoc { - model: string; - provider: string; - input_per_1m: number; - output_per_1m: number; - cached_input_per_1m: number; - aliases?: string[]; - effective_date?: Date; - updated_at?: Date; -} - -/** - * Load pricing from MongoDB into memory cache - * @param {boolean} force - Force reload even if cache is valid - * @returns {Promise} Pricing cache - */ -async function loadPricingFromDb(force = false): Promise> { - if (!force && isCacheValid()) { - return pricingCache; - } - - try { - const collection = getPricingCollection(); - const docs = await collection.find({}).toArray() as DbPricingDoc[]; - - if (docs.length === 0) { - console.log("[pricing_service] No pricing in DB, using defaults"); - loadFromDefaults(); - return pricingCache; - } - - // Clear and rebuild cache - pricingCache.clear(); - aliasCacheMap.clear(); - - for (const doc of docs) { - const pricing: PricingEntry = { - model: doc.model, - provider: doc.provider, - input: doc.input_per_1m, - output: doc.output_per_1m, - cached_input: doc.cached_input_per_1m, - aliases: doc.aliases || [], - effective_date: doc.effective_date, - updated_at: doc.updated_at, - }; - pricingCache.set(doc.model.toLowerCase(), pricing); - - // Build alias map - for (const alias of pricing.aliases) { - aliasCacheMap.set(alias.toLowerCase(), doc.model.toLowerCase()); - } - } - - cacheLoadedAt = Date.now(); - console.log(`[pricing_service] Loaded ${pricingCache.size} pricing entries from DB`); - return pricingCache; - } catch (err) { - console.error("[pricing_service] Error loading from DB, using defaults:", (err as Error).message); - loadFromDefaults(); - return pricingCache; - } -} - -/** - * Load pricing from hardcoded defaults into cache - */ -function loadFromDefaults(): void { - pricingCache.clear(); - aliasCacheMap.clear(); - - for (const [model, data] of Object.entries(DEFAULT_PRICING_TABLE)) { - const pricing: PricingEntry = { - model, - provider: data.provider, - input: data.input, - output: data.output, - cached_input: data.cached_input, - aliases: data.aliases || [], - source: "default", - }; - pricingCache.set(model.toLowerCase(), pricing); - - // Build alias map - for (const alias of data.aliases || []) { - aliasCacheMap.set(alias.toLowerCase(), model.toLowerCase()); - } - } - - cacheLoadedAt = Date.now(); - console.log(`[pricing_service] Loaded ${pricingCache.size} pricing entries from defaults`); -} - -/** - * Invalidate cache to force reload on next access - */ -function invalidateCache(): void { - cacheLoadedAt = null; -} - -/** - * Resolve model name to canonical form using aliases - * @param {string} model - Model name (possibly an alias) - * @returns {string} Canonical model name - */ -function resolveAlias(model: string): string | null { - if (!model) return null; - const lower = model.toLowerCase().trim(); - - // Check if it's a direct match - if (pricingCache.has(lower)) { - return lower; - } - - // Check alias map - if (aliasCacheMap.has(lower)) { - return aliasCacheMap.get(lower)!; - } - - // Try partial matching for model families - for (const [key, pricing] of pricingCache.entries()) { - // Check if input starts with a known model prefix - if (lower.startsWith(key) || key.startsWith(lower)) { - return key; - } - // Check aliases - for (const alias of pricing.aliases || []) { - if (lower.startsWith(alias.toLowerCase()) || alias.toLowerCase().startsWith(lower)) { - return key; - } - } - } - - return lower; -} - -interface ModelPricingResult { - input: number; - output: number; - cached_input: number; - model: string; - provider: string; - source: string; -} - -/** - * Get pricing for a model - * @param {string} model - Model name - * @param {string} provider - Provider name (optional, for disambiguation) - * @returns {Promise} Pricing { input, output, cached_input } in USD per 1M tokens - */ -async function getModelPricing(model: string, provider: string | null = null): Promise { - await loadPricingFromDb(); - - const resolved = resolveAlias(model); - - // Try exact match - if (resolved && pricingCache.has(resolved)) { - const pricing = pricingCache.get(resolved)!; - return { - input: pricing.input, - output: pricing.output, - cached_input: pricing.cached_input, - model: pricing.model, - provider: pricing.provider, - source: "db", - }; - } - - // Try provider-prefixed lookup for Bedrock - if (provider === "bedrock" || provider === "aws") { - for (const [key, pricing] of pricingCache.entries()) { - if (key.includes(resolved || "") || (resolved || "").includes(key.split(".").pop()?.split("-")[0] || "")) { - return { - input: pricing.input, - output: pricing.output, - cached_input: pricing.cached_input, - model: pricing.model, - provider: pricing.provider, - source: "bedrock_match", - }; - } - } - } - - // Return default pricing - console.log(`[pricing_service] Unknown model: ${model}, using default pricing`); - return { - ...DEFAULT_PRICING, - model: model, - provider: provider || "unknown", - source: "default", - }; -} - -/** - * Get model pricing synchronously (uses cached data) - * @param {string} model - Model name - * @returns {Object} Pricing { input, output, cached_input } in USD per 1M tokens - */ -function getModelPricingSync(model: string): ModelPricingResult { - const resolved = resolveAlias(model); - - if (resolved && pricingCache.has(resolved)) { - const cached = pricingCache.get(resolved)!; - return { - input: cached.input, - output: cached.output, - cached_input: cached.cached_input, - model: cached.model, - provider: cached.provider, - source: "db", - }; - } - - return { ...DEFAULT_PRICING, model, provider: "unknown", source: "default" }; -} - -interface CostCalculationParams { - model: string; - provider?: string; - input_tokens?: number; - output_tokens?: number; - cached_tokens?: number; -} - -interface CostResult { - total: number; - input_cost: number; - output_cost: number; - cached_cost: number; - pricing: { - model: string; - source: string; - input_per_1m: number; - output_per_1m: number; - cached_per_1m: number; - }; -} - -/** - * Calculate cost for a request (synchronous version using cached data) - * @param {Object} params - Request parameters - * @returns {Object} Cost breakdown { total, input_cost, output_cost, cached_cost, pricing } - */ -function calculateCostSync({ model, provider: _provider, input_tokens = 0, output_tokens = 0, cached_tokens = 0 }: CostCalculationParams): CostResult { - const resolved = resolveAlias(model); - let pricing: { input: number; output: number; cached_input: number; model: string; source: string }; - - if (resolved && pricingCache.has(resolved)) { - const cached = pricingCache.get(resolved)!; - pricing = { - input: cached.input, - output: cached.output, - cached_input: cached.cached_input, - model: cached.model, - source: "db", - }; - } else { - pricing = { ...DEFAULT_PRICING, model, source: "default" }; - } - - // Non-cached input tokens - const nonCachedInput = Math.max(0, input_tokens - cached_tokens); - - // Calculate costs (pricing is per 1M tokens) - const inputCost = (nonCachedInput / 1_000_000) * pricing.input; - const outputCost = (output_tokens / 1_000_000) * pricing.output; - const cachedCost = (cached_tokens / 1_000_000) * pricing.cached_input; - - const total = inputCost + outputCost + cachedCost; - - return { - total, - input_cost: inputCost, - output_cost: outputCost, - cached_cost: cachedCost, - pricing: { - model: pricing.model, - source: pricing.source, - input_per_1m: pricing.input, - output_per_1m: pricing.output, - cached_per_1m: pricing.cached_input, - }, - }; -} - -/** - * Calculate cost for a request (async version) - * @param {Object} params - Request parameters - * @returns {Promise} Cost breakdown { total, input_cost, output_cost, cached_cost, pricing } - */ -async function calculateCost(params: CostCalculationParams): Promise { - await loadPricingFromDb(); - return calculateCostSync(params); -} - -interface UpsertPricingInput { - provider?: string; - input_per_1m?: number; - input?: number; - output_per_1m?: number; - output?: number; - cached_input_per_1m?: number; - cached_input?: number; - aliases?: string[]; - effective_date?: Date; -} - -/** - * Upsert pricing for a model - * @param {string} model - Model identifier - * @param {Object} pricing - Pricing data - * @param {string} userId - User making the change - * @returns {Promise} Updated document - */ -async function upsertPricing(model: string, pricing: UpsertPricingInput, userId: string | null = null): Promise { - const collection = getPricingCollection(); - - const doc = { - model: model, - provider: pricing.provider, - input_per_1m: pricing.input_per_1m ?? pricing.input, - output_per_1m: pricing.output_per_1m ?? pricing.output, - cached_input_per_1m: pricing.cached_input_per_1m ?? pricing.cached_input, - aliases: pricing.aliases || [], - effective_date: pricing.effective_date || new Date(), - updated_at: new Date(), - updated_by: userId, - }; - - const result = await collection.findOneAndUpdate( - { model: model }, - { $set: doc }, - { upsert: true, returnDocument: "after" } - ); - - // Invalidate cache to force reload - invalidateCache(); - - return result; -} - -/** - * Delete pricing for a model - * @param {string} model - Model identifier - * @returns {Promise} True if deleted - */ -async function deletePricing(model: string): Promise { - const collection = getPricingCollection(); - const result = await collection.deleteOne({ model: model }); - - // Invalidate cache to force reload - invalidateCache(); - - return result.deletedCount > 0; -} - -interface SeedResult { - inserted: number; - updated: number; - skipped: number; - errors: { model: string; error: string }[]; -} - -/** - * Seed default pricing to MongoDB - * @param {string} userId - User making the change - * @param {boolean} overwrite - If true, overwrite existing entries - * @returns {Promise} Seed results - */ -async function seedDefaultPricing(userId: string | null = null, overwrite = false): Promise { - const collection = getPricingCollection(); - const results: SeedResult = { inserted: 0, updated: 0, skipped: 0, errors: [] }; - - for (const [model, data] of Object.entries(DEFAULT_PRICING_TABLE)) { - try { - const existing = await collection.findOne({ model }); - - if (existing && !overwrite) { - results.skipped++; - continue; - } - - const doc = { - model, - provider: data.provider, - input_per_1m: data.input, - output_per_1m: data.output, - cached_input_per_1m: data.cached_input, - aliases: data.aliases || [], - effective_date: new Date(), - updated_at: new Date(), - updated_by: userId, - }; - - if (existing) { - await collection.updateOne({ model }, { $set: doc }); - results.updated++; - } else { - await collection.insertOne(doc); - results.inserted++; - } - } catch (err) { - results.errors.push({ model, error: (err as Error).message }); - } - } - - // Invalidate cache to force reload - invalidateCache(); - - console.log(`[pricing_service] Seeded pricing: ${results.inserted} inserted, ${results.updated} updated, ${results.skipped} skipped`); - return results; -} - -interface AllPricingResult { - [key: string]: { - provider: string; - input: number; - output: number; - cached_input: number; - aliases: string[]; - }; -} - -/** - * Get all available pricing data - * @returns {Promise} Full pricing table - */ -async function getAllPricing(): Promise { - await loadPricingFromDb(); - - const result: AllPricingResult = {}; - for (const [, pricing] of pricingCache.entries()) { - result[pricing.model] = { - provider: pricing.provider, - input: pricing.input, - output: pricing.output, - cached_input: pricing.cached_input, - aliases: pricing.aliases, - }; - } - return result; -} - -interface PricingByProviderResult { - [provider: string]: { - [model: string]: { - input: number; - output: number; - cached_input: number; - aliases: string[]; - }; - }; -} - -/** - * Get pricing summary grouped by provider - * @returns {Promise} Pricing by provider - */ -async function getPricingByProvider(): Promise { - await loadPricingFromDb(); - - const byProvider: PricingByProviderResult = {}; - - for (const [, pricing] of pricingCache.entries()) { - const provider = pricing.provider || "other"; - if (!byProvider[provider]) { - byProvider[provider] = {}; - } - byProvider[provider][pricing.model] = { - input: pricing.input, - output: pricing.output, - cached_input: pricing.cached_input, - aliases: pricing.aliases, - }; - } - - return byProvider; -} - -interface DegradationModel { - model: string; - label: string; - input_cost: number; - output_cost: number; - avg_cost: number; -} - -interface DegradationTargetsResult { - providers: string[]; - models: { [provider: string]: DegradationModel[] }; -} - -/** - * Get degradation target models grouped by provider - * Returns models sorted by cost (cheapest first) for budget control "degrade" mode - * @returns {Promise} { providers: [...], models: { provider: [...] } } - */ -async function getDegradationTargets(): Promise { - await loadPricingFromDb(); - - const byProvider: { [provider: string]: DegradationModel[] } = {}; - - for (const [, pricing] of pricingCache.entries()) { - const provider = pricing.provider || "other"; - if (!byProvider[provider]) { - byProvider[provider] = []; - } - - // Calculate average cost per 1M tokens (input + output) / 2 - const avgCost = (pricing.input + pricing.output) / 2; - - byProvider[provider].push({ - model: pricing.model, - label: pricing.model, - input_cost: pricing.input, - output_cost: pricing.output, - avg_cost: avgCost, - }); - } - - // Sort models within each provider by avg_cost (cheapest first) - for (const provider of Object.keys(byProvider)) { - byProvider[provider].sort((a, b) => a.avg_cost - b.avg_cost); - } - - // Get sorted list of providers - const providers = Object.keys(byProvider).sort(); - - return { - providers, - models: byProvider, - }; -} - -/** - * Get pricing directly from DB (bypasses cache) - * @param {string} model - Model identifier - * @returns {Promise} Pricing document or null - */ -async function getPricingFromDb(model: string): Promise { - const collection = getPricingCollection(); - return collection.findOne({ model }); -} - -/** - * List all pricing from DB (bypasses cache) - * @returns {Promise} All pricing documents - */ -async function listAllPricingFromDb(): Promise { - const collection = getPricingCollection(); - return collection.find({}).sort({ provider: 1, model: 1 }).toArray(); -} - -/** - * Initialize pricing service - call on server startup - * @returns {Promise} - */ -async function initialize(): Promise { - try { - await loadPricingFromDb(true); - console.log("[pricing_service] Initialized successfully"); - } catch (err) { - console.error("[pricing_service] Failed to initialize, using defaults:", (err as Error).message); - loadFromDefaults(); - } -} - -export default { - // Core functions - getModelPricing, - getModelPricingSync, - calculateCost, - calculateCostSync, - - // CRUD operations - upsertPricing, - deletePricing, - seedDefaultPricing, - - // Query functions - getAllPricing, - getPricingByProvider, - getDegradationTargets, - getPricingFromDb, - listAllPricingFromDb, - - // Cache management - loadPricingFromDb, - invalidateCache, - initialize, - - // Constants (for reference/testing) - DEFAULT_PRICING, - DEFAULT_PRICING_TABLE, -}; diff --git a/hive/src/services/tsdb/schema.sql b/hive/src/services/tsdb/schema.sql deleted file mode 100644 index f3811afa..00000000 --- a/hive/src/services/tsdb/schema.sql +++ /dev/null @@ -1,358 +0,0 @@ --- TSDB schema for team-scoped hypertable (Timescale) --- Architecture: Hot (metrics) / Warm (content refs) / Cold (content store) - --- ============================================================================= --- Enable TimescaleDB extension (required for hypertables and continuous aggregates) --- This is safe to run multiple times - CREATE EXTENSION IF NOT EXISTS is idempotent --- ============================================================================= -CREATE EXTENSION IF NOT EXISTS timescaledb; - --- ============================================================================= --- HOT TABLE: llm_events (metrics only - fast time-series queries) --- ============================================================================= -CREATE TABLE IF NOT EXISTS llm_events ( - "timestamp" timestamptz NOT NULL, - ingest_date date, - team_id text NOT NULL, - user_id text, - trace_id text NOT NULL, - span_id text, - parent_span_id text, - request_id text, - provider text, - call_sequence integer NOT NULL, - model text, - stream boolean DEFAULT false, - agent text, - agent_name text, - agent_stack jsonb, - call_site jsonb, - metadata jsonb, - latency_ms double precision, - usage_input_tokens double precision, - usage_output_tokens double precision, - usage_total_tokens double precision, - usage_cached_tokens double precision, - usage_reasoning_tokens double precision, - usage_accepted_prediction_tokens double precision, - usage_rejected_prediction_tokens double precision, - cost_total numeric, - -- Content flags (lightweight references instead of full content) - has_content boolean DEFAULT false, - finish_reason text, - tool_call_count integer DEFAULT 0, - -- Deprecated: content_capture jsonb (migrated to warm storage) - content_capture jsonb, - created_at timestamptz DEFAULT now(), - CONSTRAINT llm_events_pk PRIMARY KEY ("timestamp", trace_id, call_sequence) -); - --- ============================================================================= --- WARM TABLE: llm_event_content (content references per event) --- Links events to deduplicated content in the cold store --- ============================================================================= -CREATE TABLE IF NOT EXISTS llm_event_content ( - id bigserial, - "timestamp" timestamptz NOT NULL, - trace_id text NOT NULL, - call_sequence integer NOT NULL, - team_id text NOT NULL, - -- Content type: 'system_prompt', 'messages', 'response', 'tools', 'params' - content_type text NOT NULL, - -- Reference to cold storage (content-addressable) - content_hash text NOT NULL, - -- Quick access metadata (no need to fetch from cold store) - byte_size integer NOT NULL DEFAULT 0, - message_count integer, -- For messages type - truncated_preview text, -- First 200 chars for quick preview - created_at timestamptz DEFAULT now(), - CONSTRAINT llm_event_content_pk PRIMARY KEY (id) -); - --- Index for joining back to events -CREATE INDEX IF NOT EXISTS idx_llm_event_content_event - ON llm_event_content (trace_id, call_sequence, "timestamp"); - --- Index for content type queries -CREATE INDEX IF NOT EXISTS idx_llm_event_content_type - ON llm_event_content (team_id, content_type, "timestamp" DESC); - --- Index for content hash lookups (finding which events use a content) -CREATE INDEX IF NOT EXISTS idx_llm_event_content_hash - ON llm_event_content (content_hash); - --- ============================================================================= --- COLD TABLE: llm_content_store (deduplicated content storage) --- Content-addressable storage with SHA-256 hashes --- ============================================================================= -CREATE TABLE IF NOT EXISTS llm_content_store ( - content_hash text NOT NULL, - team_id text NOT NULL, - content text NOT NULL, - byte_size integer NOT NULL, - ref_count integer DEFAULT 1, -- Number of events referencing this content - first_seen_at timestamptz DEFAULT now(), - last_seen_at timestamptz DEFAULT now(), - CONSTRAINT llm_content_store_pk PRIMARY KEY (content_hash, team_id) -); - --- Index for cleanup queries (find orphaned content) -CREATE INDEX IF NOT EXISTS idx_llm_content_store_refs - ON llm_content_store (team_id, ref_count, last_seen_at); - --- ============================================================================= --- MIGRATION: Add new columns to existing llm_events tables --- ============================================================================= -ALTER TABLE llm_events ADD COLUMN IF NOT EXISTS has_content boolean DEFAULT false; -ALTER TABLE llm_events ADD COLUMN IF NOT EXISTS finish_reason text; -ALTER TABLE llm_events ADD COLUMN IF NOT EXISTS tool_call_count integer DEFAULT 0; - --- Ensure primary key includes timestamp if table already existed without it -DO $$ -BEGIN - IF EXISTS ( - SELECT 1 - FROM pg_constraint c - JOIN pg_class t ON c.conrelid = t.oid - WHERE t.relname = 'llm_events' - AND c.contype = 'p' - AND NOT EXISTS ( - SELECT 1 - FROM unnest(c.conkey) WITH ORDINALITY AS ck(attnum, ord) - JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ck.attnum - WHERE a.attname = 'timestamp' - ) - ) THEN - ALTER TABLE llm_events DROP CONSTRAINT IF EXISTS llm_events_pk; - ALTER TABLE llm_events ADD CONSTRAINT llm_events_pk PRIMARY KEY ("timestamp", trace_id, call_sequence); - END IF; -END$$; - --- Promote to hypertable when Timescale is available -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'timescaledb') THEN - PERFORM public.create_hypertable('llm_events', 'timestamp', if_not_exists => TRUE); - END IF; -END$$; - --- Ensure metadata column exists for flexible fields -ALTER TABLE llm_events - ADD COLUMN IF NOT EXISTS metadata jsonb; - --- Ensure content_capture column exists (for Layer 0 content capture) -ALTER TABLE llm_events - ADD COLUMN IF NOT EXISTS content_capture jsonb; - --- Helpful indexes -CREATE INDEX IF NOT EXISTS idx_llm_events_ts ON llm_events ("timestamp" DESC); -CREATE INDEX IF NOT EXISTS idx_llm_events_team_ts ON llm_events (team_id, "timestamp" DESC); -CREATE INDEX IF NOT EXISTS idx_llm_events_model ON llm_events (model); -CREATE INDEX IF NOT EXISTS idx_llm_events_agent ON llm_events (agent); -CREATE INDEX IF NOT EXISTS idx_llm_events_trace ON llm_events (trace_id); - --- Continuous aggregate: daily rollup for analytics-wide -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'timescaledb') THEN - CREATE MATERIALIZED VIEW IF NOT EXISTS llm_events_daily_ca - WITH (timescaledb.continuous) AS - SELECT - time_bucket('1 day', "timestamp") AS bucket, - COUNT(*) AS requests, - SUM(cost_total) AS cost_total, - SUM(usage_input_tokens) AS input_tokens, - SUM(usage_output_tokens) AS output_tokens, - SUM(COALESCE(usage_total_tokens, COALESCE(usage_input_tokens, 0) + COALESCE(usage_output_tokens, 0))) AS total_tokens, - SUM(usage_cached_tokens) AS cached_tokens - FROM llm_events - GROUP BY 1 - WITH NO DATA; - - -- Initial refresh to populate the CA immediately - CALL refresh_continuous_aggregate('llm_events_daily_ca', NULL, NOW()); - END IF; -EXCEPTION - WHEN others THEN NULL; -- Ignore errors if CA already exists or refresh fails -END$$; - --- Index on CA for fast range scans -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM pg_class WHERE relname = 'llm_events_daily_ca') THEN - CREATE INDEX IF NOT EXISTS idx_llm_events_daily_ca_bucket ON llm_events_daily_ca (bucket DESC); - END IF; -EXCEPTION WHEN undefined_table THEN - NULL; -END$$; - --- Continuous aggregate: daily rollup by model for fast model-grouped queries -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'timescaledb') THEN - CREATE MATERIALIZED VIEW IF NOT EXISTS llm_events_daily_by_model_ca - WITH (timescaledb.continuous) AS - SELECT - time_bucket('1 day', "timestamp") AS bucket, - model, - provider, - COUNT(*) AS requests, - SUM(cost_total) AS cost_total, - SUM(usage_input_tokens) AS input_tokens, - SUM(usage_output_tokens) AS output_tokens, - SUM(COALESCE(usage_total_tokens, COALESCE(usage_input_tokens, 0) + COALESCE(usage_output_tokens, 0))) AS total_tokens, - SUM(usage_cached_tokens) AS cached_tokens, - AVG(latency_ms) AS avg_latency_ms - FROM llm_events - GROUP BY 1, 2, 3 - WITH NO DATA; - - -- Initial refresh to populate the CA immediately - CALL refresh_continuous_aggregate('llm_events_daily_by_model_ca', NULL, NOW()); - END IF; -EXCEPTION - WHEN others THEN NULL; -- Ignore errors if CA already exists or refresh fails -END$$; - --- Index on model CA for fast range scans -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM pg_class WHERE relname = 'llm_events_daily_by_model_ca') THEN - CREATE INDEX IF NOT EXISTS idx_llm_events_daily_by_model_ca_bucket ON llm_events_daily_by_model_ca (bucket DESC); - CREATE INDEX IF NOT EXISTS idx_llm_events_daily_by_model_ca_model ON llm_events_daily_by_model_ca (model); - END IF; -EXCEPTION WHEN undefined_table THEN - NULL; -END$$; - --- Continuous aggregate: daily rollup by agent for fast agent-grouped queries -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'timescaledb') THEN - CREATE MATERIALIZED VIEW IF NOT EXISTS llm_events_daily_by_agent_ca - WITH (timescaledb.continuous) AS - SELECT - time_bucket('1 day', "timestamp") AS bucket, - agent, - COUNT(*) AS requests, - SUM(cost_total) AS cost_total, - SUM(usage_input_tokens) AS input_tokens, - SUM(usage_output_tokens) AS output_tokens, - SUM(COALESCE(usage_total_tokens, COALESCE(usage_input_tokens, 0) + COALESCE(usage_output_tokens, 0))) AS total_tokens, - SUM(usage_cached_tokens) AS cached_tokens, - AVG(latency_ms) AS avg_latency_ms - FROM llm_events - GROUP BY 1, 2 - WITH NO DATA; - - -- Initial refresh to populate the CA immediately - CALL refresh_continuous_aggregate('llm_events_daily_by_agent_ca', NULL, NOW()); - END IF; -EXCEPTION - WHEN others THEN NULL; -- Ignore errors if CA already exists or refresh fails -END$$; - --- Index on agent CA for fast range scans -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM pg_class WHERE relname = 'llm_events_daily_by_agent_ca') THEN - CREATE INDEX IF NOT EXISTS idx_llm_events_daily_by_agent_ca_bucket ON llm_events_daily_by_agent_ca (bucket DESC); - CREATE INDEX IF NOT EXISTS idx_llm_events_daily_by_agent_ca_agent ON llm_events_daily_by_agent_ca (agent); - END IF; -EXCEPTION WHEN undefined_table THEN - NULL; -END$$; - --- Refresh policies: keep recent buckets fresh --- Note: Using timescaledb_information.jobs (not the deprecated policy_refresh_continuous_aggregate view) -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'timescaledb') - AND EXISTS ( - SELECT 1 - FROM timescaledb_information.continuous_aggregates - WHERE view_name = 'llm_events_daily_ca' - AND view_schema = current_schema() - ) - THEN - -- Add refresh policy if none exists for this CA - IF NOT EXISTS ( - SELECT 1 FROM timescaledb_information.jobs - WHERE proc_name = 'policy_refresh_continuous_aggregate' - AND hypertable_schema = current_schema() - AND hypertable_name = 'llm_events_daily_ca' - ) THEN - PERFORM add_continuous_aggregate_policy( - 'llm_events_daily_ca', - start_offset => interval '30 days', - end_offset => interval '1 hour', - schedule_interval => interval '15 minutes' - ); - END IF; - END IF; -EXCEPTION - WHEN undefined_table THEN NULL; - WHEN undefined_function THEN NULL; -END$$; - --- Refresh policies for llm_events_daily_by_model_ca -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'timescaledb') - AND EXISTS ( - SELECT 1 - FROM timescaledb_information.continuous_aggregates - WHERE view_name = 'llm_events_daily_by_model_ca' - AND view_schema = current_schema() - ) - THEN - -- Add refresh policy if none exists for this CA - IF NOT EXISTS ( - SELECT 1 FROM timescaledb_information.jobs - WHERE proc_name = 'policy_refresh_continuous_aggregate' - AND hypertable_schema = current_schema() - AND hypertable_name = 'llm_events_daily_by_model_ca' - ) THEN - PERFORM add_continuous_aggregate_policy( - 'llm_events_daily_by_model_ca', - start_offset => interval '30 days', - end_offset => interval '1 hour', - schedule_interval => interval '15 minutes' - ); - END IF; - END IF; -EXCEPTION - WHEN undefined_table THEN NULL; - WHEN undefined_function THEN NULL; -END$$; - --- Refresh policies for llm_events_daily_by_agent_ca -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'timescaledb') - AND EXISTS ( - SELECT 1 - FROM timescaledb_information.continuous_aggregates - WHERE view_name = 'llm_events_daily_by_agent_ca' - AND view_schema = current_schema() - ) - THEN - -- Add refresh policy if none exists for this CA - IF NOT EXISTS ( - SELECT 1 FROM timescaledb_information.jobs - WHERE proc_name = 'policy_refresh_continuous_aggregate' - AND hypertable_schema = current_schema() - AND hypertable_name = 'llm_events_daily_by_agent_ca' - ) THEN - PERFORM add_continuous_aggregate_policy( - 'llm_events_daily_by_agent_ca', - start_offset => interval '30 days', - end_offset => interval '1 hour', - schedule_interval => interval '15 minutes' - ); - END IF; - END IF; -EXCEPTION - WHEN undefined_table THEN NULL; - WHEN undefined_function THEN NULL; -END$$; diff --git a/hive/src/services/tsdb/team_context.ts b/hive/src/services/tsdb/team_context.ts deleted file mode 100644 index 578dfefb..00000000 --- a/hive/src/services/tsdb/team_context.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { Pool, PoolConfig, PoolClient } from "pg"; -import jwt from "jsonwebtoken"; - -// Cache pools per team schema -const poolCache = new Map(); - -interface TokenPayload { - team_id?: string; - team?: string; - teamId?: string; - current_team_id?: string; - user_id?: string; - sub?: string; - user?: string; - userId?: string; - [key: string]: unknown; -} - -interface ParsedToken { - team_id: string; - user_id: string | null; - token: string; - payload: TokenPayload; -} - -/** - * Parse JWT to extract team_id and user_id. - * - Supports Authorization header formats: "Bearer " or "jwt " or raw token. - * - team_id: payload.team_id || payload.team || payload.teamId - * - user_id: payload.user_id || payload.sub || payload.user || payload.userId - */ -const parseToken = (authHeader: string | undefined): ParsedToken | null => { - if (!authHeader) return null; - const parts = authHeader.trim().split(" "); - const token = parts.length === 2 ? parts[1] : parts[0]; - if (!token) return null; - - // Token is already verified by passport middleware; decode only to extract team/user fields. - const payload = jwt.decode(token) as TokenPayload | null; - if (!payload || typeof payload !== "object") return null; - - const team_id = payload.team_id || payload.team || payload.teamId || payload.current_team_id; - const user_id = payload.user_id || payload.sub || payload.user || payload.userId || null; - if (!team_id) return null; - - return { team_id, user_id: user_id as string | null, token, payload }; -}; - -const buildSchemaName = (team_id: string | number): string => { - return `team_${team_id}`.replace(/[^a-zA-Z0-9_]/g, "_"); -}; - -declare const _GLOBAL_CONST: { ACHO_PG_CONFIG?: { USER: string; HOST: string; DATABASE: string; PASSWORD: string; PORT: number } }; - -const basePoolConfig = (): Partial => { - const connStr = (process.env.TSDB_PG_URL || "").replace(/\s+/g, ""); - if (connStr) { - // Only enable SSL for non-local connections or when explicitly requested - const isLocal = connStr.includes("localhost") || connStr.includes("127.0.0.1") || connStr.includes("timescaledb"); - const sslRequested = connStr.includes("sslmode=require") || process.env.TSDB_SSL === "true"; - const ssl = !isLocal || sslRequested ? { rejectUnauthorized: false } : false; - return { connectionString: connStr, ssl }; - } - if (typeof _GLOBAL_CONST !== "undefined" && _GLOBAL_CONST.ACHO_PG_CONFIG) { - const cfg = _GLOBAL_CONST.ACHO_PG_CONFIG; - return { - user: cfg.USER, - host: cfg.HOST, - database: cfg.DATABASE, - password: cfg.PASSWORD, - port: cfg.PORT, - }; - } - return {}; -}; - -const getTeamPool = async (team_id: string | number, overrideConfig?: Partial): Promise => { - const schema = buildSchemaName(team_id); - if (poolCache.has(schema)) return poolCache.get(schema)!; - - const pool = new Pool({ - ...basePoolConfig(), - ...(overrideConfig || {}), - max: 10, - idleTimeoutMillis: 30000, - connectionTimeoutMillis: 10000, - }); - - // Handle pool-level errors to prevent unhandled rejections - pool.on("error", (err) => { - console.error(`[team_context] Pool error for schema ${schema}:`, err.message); - // Remove from cache to force fresh pool on next request - poolCache.delete(schema); - }); - - // Ensure schema exists and set search_path per connection - pool.on("connect", (client: PoolClient) => { - // Fire-and-forget with error handling - don't await in event handler - client.query(`CREATE SCHEMA IF NOT EXISTS ${schema}`) - .then(() => client.query(`SET search_path TO ${schema}, public`)) - .catch((err: Error) => { - console.error(`[team_context] Schema setup error for ${schema}:`, err.message); - }); - }); - - poolCache.set(schema, pool); - return pool; -}; - -export { - parseToken, - buildSchemaName, - getTeamPool, -}; diff --git a/hive/src/services/tsdb/tsdb_service.ts b/hive/src/services/tsdb/tsdb_service.ts deleted file mode 100644 index 02d5d2f2..00000000 --- a/hive/src/services/tsdb/tsdb_service.ts +++ /dev/null @@ -1,955 +0,0 @@ -import fs from "fs"; -import path from "path"; -import crypto from "crypto"; -import { Pool, PoolClient } from "pg"; -import pricingService from "./pricing_service"; - -let _tsdbPool: Pool | undefined; -let _schemaReadyPromise: Promise | null; -const _schemaReadyByName = new Map>(); // Per-schema initialization tracking -const SCHEMA_SQL = fs.readFileSync(path.join(__dirname, "schema.sql"), "utf8"); - -const safeParseJson = (val: unknown): unknown => { - if (val === null || val === undefined) return null; - if (typeof val === "object") return val; - if (typeof val === "string") { - try { - return JSON.parse(val); - } catch (_e) { - return null; - } - } - return null; -}; - -const asObject = (val: unknown, fallback: Record = {}): Record => { - const parsed = safeParseJson(val); - if (parsed && !Array.isArray(parsed) && typeof parsed === "object") return parsed as Record; - if (val && typeof val === "object" && !Array.isArray(val)) return val as Record; - return fallback; -}; - -const asArray = (val: unknown, fallback: unknown[] = []): unknown[] => { - if (Array.isArray(val)) return val; - const parsed = safeParseJson(val); - if (Array.isArray(parsed)) return parsed; - if (typeof val === "string") { - const trimmed = val.trim(); - if (trimmed.startsWith("{") && trimmed.endsWith("}")) { - const inner = trimmed.slice(1, -1).trim(); - if (!inner) return []; - return inner - .split(",") - .map((s) => s.trim().replace(/^"+|"+$/g, "")) - .filter(Boolean); - } - return [val]; - } - if (val !== null && val !== undefined && typeof val !== "object" && typeof val !== "function") { - return [val]; - } - return fallback; -}; - -const buildMetadata = (raw: Record): Record | null => { - const base = asObject(raw.metadata ?? raw.meta ?? raw.properties ?? raw.extra, {}); - const tags = asArray(raw.tags ?? raw.labels, []) as string[]; - if (tags && tags.length) { - base.tags = tags; - } - const sessionId = raw.session_id ?? raw.sessionId; - if (sessionId !== undefined && sessionId !== null && base.session_id === undefined) { - base.session_id = sessionId; - } - const environment = raw.environment ?? raw.env; - if (environment && base.environment === undefined) { - base.environment = environment; - } - return Object.keys(base).length ? base : null; -}; - -interface UsageData { - input_tokens?: number; - output_tokens?: number; - total_tokens?: number; - cached_tokens?: number; - reasoning_tokens?: number; - accepted_prediction_tokens?: number; - rejected_prediction_tokens?: number; -} - -const calcCost = (model: string, usage: UsageData = {}): number => { - const inputTokens = Number.isFinite(Number(usage.input_tokens)) ? Number(usage.input_tokens) : 0; - const outputTokens = Number.isFinite(Number(usage.output_tokens)) ? Number(usage.output_tokens) : 0; - const cachedTokens = Number.isFinite(Number(usage.cached_tokens)) ? Number(usage.cached_tokens) : 0; - - const result = pricingService.calculateCostSync({ - model: model || "", - input_tokens: inputTokens, - output_tokens: outputTokens, - cached_tokens: cachedTokens, - }); - - return result.total; -}; - -// ============================================================================= -// Content Storage Types and Utilities -// ============================================================================= - -interface ContentCapture { - system_prompt?: string; - messages?: unknown[]; - tools?: unknown[]; - params?: Record; - response_content?: string; - finish_reason?: string; - choice_count?: number; - has_images?: boolean; - image_urls?: string[]; -} - -interface ContentReference { - content_type: string; - content_hash: string; - byte_size: number; - message_count?: number; - truncated_preview?: string; -} - -interface ContentToStore { - content_hash: string; - content: string; - byte_size: number; -} - -/** - * Generate SHA-256 hash of content for content-addressable storage - */ -const hashContent = (content: string): string => { - return crypto.createHash("sha256").update(content, "utf8").digest("hex"); -}; - -/** - * Create a truncated preview of content (first 200 chars) - */ -const createPreview = (content: string, maxLength: number = 200): string => { - if (!content || content.length <= maxLength) return content || ""; - return content.slice(0, maxLength) + "..."; -}; - -/** - * Extract content from ContentCapture and prepare for storage - * Returns content references for warm table and content items for cold table - */ -const extractContent = ( - contentCapture: ContentCapture | null | undefined -): { refs: ContentReference[]; items: ContentToStore[] } => { - if (!contentCapture) { - return { refs: [], items: [] }; - } - - const refs: ContentReference[] = []; - const items: ContentToStore[] = []; - const seenHashes = new Set(); - - // Helper to process a content field - const processContent = ( - type: string, - value: unknown, - messageCount?: number - ): void => { - if (value === null || value === undefined) return; - - const contentStr = typeof value === "string" ? value : JSON.stringify(value); - if (!contentStr || contentStr === "null" || contentStr === "{}") return; - - const hash = hashContent(contentStr); - const byteSize = Buffer.byteLength(contentStr, "utf8"); - - refs.push({ - content_type: type, - content_hash: hash, - byte_size: byteSize, - message_count: messageCount, - truncated_preview: createPreview(contentStr), - }); - - // Only store content once per hash (deduplication within batch) - if (!seenHashes.has(hash)) { - seenHashes.add(hash); - items.push({ - content_hash: hash, - content: contentStr, - byte_size: byteSize, - }); - } - }; - - // Extract each content type - if (contentCapture.system_prompt) { - processContent("system_prompt", contentCapture.system_prompt); - } - - if (contentCapture.messages && Array.isArray(contentCapture.messages) && contentCapture.messages.length > 0) { - processContent("messages", contentCapture.messages, contentCapture.messages.length); - } - - if (contentCapture.response_content) { - processContent("response", contentCapture.response_content); - } - - if (contentCapture.tools && Array.isArray(contentCapture.tools) && contentCapture.tools.length > 0) { - processContent("tools", contentCapture.tools); - } - - // Only store params if they have meaningful values (not all nulls) - if (contentCapture.params) { - const hasValues = Object.values(contentCapture.params).some( - (v) => v !== null && v !== undefined - ); - if (hasValues) { - processContent("params", contentCapture.params); - } - } - - return { refs, items }; -}; - -const parseDate = (val: unknown): Date | null => { - if (!val) return null; - const d = new Date(val as string | number | Date); - return Number.isNaN(d.getTime()) ? null : d; -}; - -const numberOrNull = (val: unknown): number | null => { - const n = Number(val); - return Number.isFinite(n) ? n : null; -}; - -interface RawEvent { - timestamp?: unknown; - team_id?: unknown; - traceId?: string; - trace_id?: string; - spanId?: string; - span_id?: string; - parent_span_id?: string; - callSequence?: number; - call_sequence?: number; - requestId?: string; - request_id?: string; - provider?: string; - model?: string; - stream?: boolean; - agent?: string; - agent_name?: string; - user_id?: string; - latency_ms?: number; - usage?: UsageData; - input_tokens?: number; - output_tokens?: number; - total_tokens?: number; - cached_tokens?: number; - reasoning_tokens?: number; - accepted_prediction_tokens?: number; - rejected_prediction_tokens?: number; - metadata?: Record; - meta?: Record; - properties?: Record; - extra?: Record; - tags?: string[]; - labels?: string[]; - session_id?: string; - sessionId?: string; - environment?: string; - env?: string; - agentStack?: string[]; - agent_stack?: string[]; - callSite?: Record; - call_site?: Record; - call_site_file?: string; - call_site_line?: number; - call_site_column?: number; - call_site_function?: string; - call_stack?: string[]; - content_capture?: Record; -} - -interface NormalizedEvent { - timestamp: Date; - ingest_date: string; - team_id: string; - trace_id: string; - span_id: string | null; - parent_span_id: string | null; - request_id: string | null; - provider: string | null; - call_sequence: number; - model: string; - stream: boolean; - agent: string | null; - agent_name: string | null; - user_id: string | null; - latency_ms: number | null; - usage_input_tokens: number | null; - usage_output_tokens: number | null; - usage_total_tokens: number | null; - usage_cached_tokens: number | null; - usage_reasoning_tokens: number | null; - usage_accepted_prediction_tokens: number | null; - usage_rejected_prediction_tokens: number | null; - metadata: Record | null; - call_site: Record; - agent_stack: string[]; - cost_total: number; - // Hot table fields (lightweight content indicators) - has_content: boolean; - finish_reason: string | null; - tool_call_count: number; - // Content data for warm/cold storage (extracted separately) - content_refs: ContentReference[]; - content_items: ContentToStore[]; - // Deprecated: kept for backward compatibility during migration - content_capture: Record | null; -} - -const normalizeEvent = (raw: RawEvent): NormalizedEvent | null => { - const ts = raw.timestamp; - const teamId = raw.team_id; - const parsedTs = parseDate(ts); - if (!parsedTs) return null; - - const traceId = raw.traceId || raw.trace_id; - const spanId = raw.spanId || raw.span_id; - const parentSpanId = raw.parent_span_id || null; - const callSeqRaw = raw.callSequence ?? raw.call_sequence; - if ( - traceId === undefined || - callSeqRaw === undefined || - callSeqRaw === null || - teamId === undefined || - teamId === null - ) { - return null; - } - const callSeq = Number(callSeqRaw); - if (!Number.isInteger(callSeq)) return null; - - const usage: UsageData = raw.usage || { - input_tokens: raw.input_tokens, - output_tokens: raw.output_tokens, - total_tokens: raw.total_tokens, - cached_tokens: raw.cached_tokens, - reasoning_tokens: raw.reasoning_tokens, - accepted_prediction_tokens: raw.accepted_prediction_tokens, - rejected_prediction_tokens: raw.rejected_prediction_tokens, - }; - // Extract agent - metadata.agent takes precedence over top-level agent - const metadata = asObject(raw.metadata, {}); - const effectiveAgent = (metadata.agent as string) || raw.agent || null; - - let agentStack = asArray(raw.agentStack ?? raw.agent_stack, []) as string[]; - if (effectiveAgent) { - const agentVal = String(effectiveAgent); - if (!agentStack.includes(agentVal)) { - agentStack = [agentVal, ...agentStack]; - } - } - const callSite = - raw.callSite || - asObject(raw.call_site, { - file: raw.call_site_file, - line: raw.call_site_line, - column: raw.call_site_column, - function: raw.call_site_function, - stack: asArray(raw.call_stack, []), - }); - - // Extract content for warm/cold storage - const contentCapture = raw.content_capture as ContentCapture | undefined; - const { refs: contentRefs, items: contentItems } = extractContent(contentCapture); - - // Extract lightweight content indicators for hot table - const hasContent = contentRefs.length > 0; - const finishReason = contentCapture?.finish_reason || null; - - // Count tool calls from messages or tool_calls field - let toolCallCount = 0; - if (contentCapture?.messages && Array.isArray(contentCapture.messages)) { - for (const msg of contentCapture.messages) { - const msgObj = msg as Record; - if (msgObj.tool_calls && Array.isArray(msgObj.tool_calls)) { - toolCallCount += msgObj.tool_calls.length; - } - } - } - - return { - timestamp: parsedTs, - ingest_date: parsedTs.toISOString().slice(0, 10), - team_id: String(teamId), - trace_id: String(traceId), - span_id: spanId || null, - parent_span_id: parentSpanId, - request_id: raw.requestId || raw.request_id || null, - provider: raw.provider || null, - call_sequence: callSeq, - model: raw.model || "", - stream: Boolean(raw.stream), - agent: agentStack[0] || null, - agent_name: raw.agent_name || null, - user_id: raw.user_id || null, - latency_ms: numberOrNull(raw.latency_ms), - usage_input_tokens: numberOrNull(usage.input_tokens), - usage_output_tokens: numberOrNull(usage.output_tokens), - usage_total_tokens: numberOrNull(usage.total_tokens), - usage_cached_tokens: numberOrNull(usage.cached_tokens), - usage_reasoning_tokens: numberOrNull(usage.reasoning_tokens), - usage_accepted_prediction_tokens: numberOrNull(usage.accepted_prediction_tokens), - usage_rejected_prediction_tokens: numberOrNull(usage.rejected_prediction_tokens), - metadata: buildMetadata(raw as Record), - call_site: callSite as Record, - agent_stack: agentStack, - cost_total: calcCost(raw.model || "", usage), - // Hot table content indicators - has_content: hasContent, - finish_reason: finishReason, - tool_call_count: toolCallCount, - // Content for warm/cold storage - content_refs: contentRefs, - content_items: contentItems, - // Deprecated: kept for backward compatibility - content_capture: raw.content_capture || null, - }; -}; - -const dedupeEvents = (events: NormalizedEvent[]): NormalizedEvent[] => { - const deduped = new Map(); - events.forEach((ev) => { - const key = `${ev.trace_id}||${ev.call_sequence}`; - const existing = deduped.get(key); - if (!existing) { - deduped.set(key, ev); - return; - } - if (existing.timestamp && ev.timestamp && ev.timestamp > existing.timestamp) { - deduped.set(key, ev); - } - }); - return Array.from(deduped.values()); -}; - -const normalizeEvents = (rawEvents: RawEvent[] = []): NormalizedEvent[] => { - const normalized: NormalizedEvent[] = []; - rawEvents.forEach((ev) => { - const n = normalizeEvent(ev); - if (n) normalized.push(n); - }); - return dedupeEvents(normalized); -}; - -const getTsdbPool = (): Pool => { - if (_tsdbPool) return _tsdbPool; - const connStr = (process.env.TSDB_PG_URL || "").replace(/\s+/g, ""); - if (connStr) { - _tsdbPool = new Pool({ - connectionString: connStr, - ssl: { rejectUnauthorized: false }, - }); - return _tsdbPool; - } - if ((global as unknown as Record)._ACHO_PG_POOL) { - _tsdbPool = (global as unknown as Record)._ACHO_PG_POOL as Pool; - return _tsdbPool; - } - throw new Error("TSDB pool not available. Set TSDB_PG_URL or initialize _ACHO_PG_POOL."); -}; - -const ensureSchema = async (client?: PoolClient): Promise => { - if (client) { - // Get current schema name for per-schema caching - const schemaResult = await client.query("SELECT current_schema()"); - const schemaName = schemaResult.rows[0]?.current_schema || "public"; - - // Check if this schema is already initialized - if (_schemaReadyByName.has(schemaName)) { - return _schemaReadyByName.get(schemaName); - } - - // Create and cache the initialization promise - const initPromise = (async () => { - try { - await client.query(SCHEMA_SQL); - } catch (err: unknown) { - // Handle race condition - if object already exists, it's fine - const pgError = err as { code?: string }; - if (pgError.code === "23505" || pgError.code === "42P07") { - // 23505 = unique_violation, 42P07 = duplicate_table - console.log(`[tsdb] Schema ${schemaName} already initialized (concurrent request)`); - return; - } - throw err; - } - })(); - - _schemaReadyByName.set(schemaName, initPromise); - - try { - await initPromise; - } catch (err) { - _schemaReadyByName.delete(schemaName); - throw err; - } - return; - } - - if (_schemaReadyPromise) return _schemaReadyPromise; - - const pool = getTsdbPool(); - _schemaReadyPromise = (async () => { - const executor = await pool.connect(); - try { - await executor.query(SCHEMA_SQL); - } finally { - executor.release(); - } - })(); - - try { - await _schemaReadyPromise; - } catch (err) { - _schemaReadyPromise = null; - throw err; - } -}; - -interface UpsertResult { - rowsWritten: number; - normalized: number; - received?: number; - contentStored?: number; - contentDeduplicated?: number; -} - -/** - * Store content in cold storage (llm_content_store) with deduplication - * Uses ON CONFLICT to increment ref_count for existing content - */ -const storeContentCold = async ( - executor: PoolClient, - teamId: string, - items: ContentToStore[] -): Promise<{ stored: number; deduplicated: number }> => { - if (!items.length) return { stored: 0, deduplicated: 0 }; - - // Batch upsert content items - const cols = ["content_hash", "team_id", "content", "byte_size", "ref_count", "first_seen_at", "last_seen_at"]; - const values: unknown[] = []; - const placeholders: string[] = []; - const now = new Date(); - - items.forEach((item, idx) => { - const base = idx * cols.length; - placeholders.push(`(${cols.map((__, i) => `$${base + i + 1}`).join(", ")})`); - values.push(item.content_hash, teamId, item.content, item.byte_size, 1, now, now); - }); - - const sql = ` - INSERT INTO llm_content_store (${cols.join(", ")}) - VALUES ${placeholders.join(", ")} - ON CONFLICT (content_hash, team_id) - DO UPDATE SET - ref_count = llm_content_store.ref_count + 1, - last_seen_at = EXCLUDED.last_seen_at - RETURNING (xmax = 0) AS inserted - `; - - const result = await executor.query(sql, values); - const inserted = result.rows.filter((r: { inserted: boolean }) => r.inserted).length; - const deduplicated = items.length - inserted; - - return { stored: inserted, deduplicated }; -}; - -/** - * Store content references in warm storage (llm_event_content) - */ -const storeContentWarm = async ( - executor: PoolClient, - events: NormalizedEvent[] -): Promise => { - // Collect all content references from all events - const allRefs: Array<{ - timestamp: Date; - trace_id: string; - call_sequence: number; - team_id: string; - ref: ContentReference; - }> = []; - - for (const ev of events) { - for (const ref of ev.content_refs) { - allRefs.push({ - timestamp: ev.timestamp, - trace_id: ev.trace_id, - call_sequence: ev.call_sequence, - team_id: ev.team_id, - ref, - }); - } - } - - if (!allRefs.length) return 0; - - const cols = [ - '"timestamp"', - "trace_id", - "call_sequence", - "team_id", - "content_type", - "content_hash", - "byte_size", - "message_count", - "truncated_preview", - ]; - const values: unknown[] = []; - const placeholders: string[] = []; - - allRefs.forEach((item, idx) => { - const base = idx * cols.length; - placeholders.push(`(${cols.map((__, i) => `$${base + i + 1}`).join(", ")})`); - values.push( - item.timestamp, - item.trace_id, - item.call_sequence, - item.team_id, - item.ref.content_type, - item.ref.content_hash, - item.ref.byte_size, - item.ref.message_count || null, - item.ref.truncated_preview || null - ); - }); - - const sql = ` - INSERT INTO llm_event_content (${cols.join(", ")}) - VALUES ${placeholders.join(", ")} - `; - - await executor.query(sql, values); - return allRefs.length; -}; - -const upsertEvents = async (rawEvents: RawEvent[] = [], client?: PoolClient): Promise => { - const events = normalizeEvents(rawEvents); - if (!events.length) { - return { rowsWritten: 0, normalized: 0 }; - } - - // Hot table columns (metrics only, no full content_capture) - const cols = [ - '"timestamp"', - "ingest_date", - "team_id", - "user_id", - "trace_id", - "span_id", - "parent_span_id", - "request_id", - "provider", - "call_sequence", - "model", - "stream", - "agent", - "agent_name", - "latency_ms", - "usage_input_tokens", - "usage_output_tokens", - "usage_total_tokens", - "usage_cached_tokens", - "usage_reasoning_tokens", - "usage_accepted_prediction_tokens", - "usage_rejected_prediction_tokens", - "call_site", - "metadata", - "agent_stack", - "cost_total", - // New lightweight content fields - "has_content", - "finish_reason", - "tool_call_count", - // Deprecated: kept for backward compatibility during migration - "content_capture", - ]; - - const values: unknown[] = []; - const placeholders: string[] = []; - events.forEach((ev, idx) => { - const base = idx * cols.length; - placeholders.push(`(${cols.map((__, i) => `$${base + i + 1}`).join(", ")})`); - values.push( - ev.timestamp, - ev.ingest_date, - ev.team_id, - ev.user_id, - ev.trace_id, - ev.span_id, - ev.parent_span_id, - ev.request_id, - ev.provider, - ev.call_sequence, - ev.model, - ev.stream, - ev.agent, - ev.agent_name, - ev.latency_ms, - ev.usage_input_tokens, - ev.usage_output_tokens, - ev.usage_total_tokens, - ev.usage_cached_tokens, - ev.usage_reasoning_tokens, - ev.usage_accepted_prediction_tokens, - ev.usage_rejected_prediction_tokens, - JSON.stringify(ev.call_site || {}), - ev.metadata ? JSON.stringify(ev.metadata) : null, - JSON.stringify(ev.agent_stack || []), - ev.cost_total, - // New fields - ev.has_content, - ev.finish_reason, - ev.tool_call_count, - // Deprecated: store null for new events, keep for backward compat - null - ); - }); - - const sql = ` - INSERT INTO llm_events (${cols.join(", ")}) - VALUES ${placeholders.join(", ")} - ON CONFLICT ("timestamp", trace_id, call_sequence) - DO UPDATE SET - "timestamp" = EXCLUDED."timestamp", - ingest_date = EXCLUDED.ingest_date, - team_id = EXCLUDED.team_id, - user_id = EXCLUDED.user_id, - trace_id = EXCLUDED.trace_id, - span_id = EXCLUDED.span_id, - parent_span_id = EXCLUDED.parent_span_id, - request_id = EXCLUDED.request_id, - provider = EXCLUDED.provider, - model = EXCLUDED.model, - stream = EXCLUDED.stream, - agent = EXCLUDED.agent, - agent_name = EXCLUDED.agent_name, - latency_ms = EXCLUDED.latency_ms, - usage_input_tokens = EXCLUDED.usage_input_tokens, - usage_output_tokens = EXCLUDED.usage_output_tokens, - usage_total_tokens = EXCLUDED.usage_total_tokens, - usage_cached_tokens = EXCLUDED.usage_cached_tokens, - usage_reasoning_tokens = EXCLUDED.usage_reasoning_tokens, - usage_accepted_prediction_tokens = EXCLUDED.usage_accepted_prediction_tokens, - usage_rejected_prediction_tokens = EXCLUDED.usage_rejected_prediction_tokens, - call_site = EXCLUDED.call_site, - metadata = EXCLUDED.metadata, - agent_stack = EXCLUDED.agent_stack, - cost_total = EXCLUDED.cost_total, - has_content = EXCLUDED.has_content, - finish_reason = EXCLUDED.finish_reason, - tool_call_count = EXCLUDED.tool_call_count - WHERE EXCLUDED."timestamp" >= llm_events."timestamp" - `; - - const pool = client ? null : getTsdbPool(); - const executor = client || (await pool!.connect()); - - let contentStored = 0; - let contentDeduplicated = 0; - - try { - // 1. Insert into hot table (llm_events) - await executor.query(sql, values); - - // 2. Collect all content items for cold storage (deduplicated across events) - const allContentItems: ContentToStore[] = []; - const seenHashes = new Set(); - const teamId = events[0]?.team_id; - - for (const ev of events) { - for (const item of ev.content_items) { - if (!seenHashes.has(item.content_hash)) { - seenHashes.add(item.content_hash); - allContentItems.push(item); - } - } - } - - // 3. Store content in cold storage (llm_content_store) - if (allContentItems.length > 0 && teamId) { - const coldResult = await storeContentCold(executor, teamId, allContentItems); - contentStored = coldResult.stored; - contentDeduplicated = coldResult.deduplicated; - } - - // 4. Store content references in warm storage (llm_event_content) - await storeContentWarm(executor, events); - - } finally { - if (!client && executor && 'release' in executor) { - (executor as PoolClient).release(); - } - } - - return { - rowsWritten: events.length, - normalized: events.length, - received: rawEvents.length, - contentStored, - contentDeduplicated, - }; -}; - -/** - * Retrieve content from cold storage by hash - */ -const getContentByHash = async ( - teamId: string, - contentHash: string, - client?: PoolClient -): Promise => { - const pool = client ? null : getTsdbPool(); - const executor = client || (await pool!.connect()); - - try { - const result = await executor.query( - `SELECT content FROM llm_content_store WHERE content_hash = $1 AND team_id = $2`, - [contentHash, teamId] - ); - return result.rows[0]?.content || null; - } finally { - if (!client && executor && "release" in executor) { - (executor as PoolClient).release(); - } - } -}; - -/** - * Get all content references for an event - */ -const getEventContent = async ( - teamId: string, - traceId: string, - callSequence: number, - client?: PoolClient -): Promise> => { - const pool = client ? null : getTsdbPool(); - const executor = client || (await pool!.connect()); - - try { - // Get content references from warm storage - const refsResult = await executor.query( - `SELECT content_type, content_hash, byte_size, message_count, truncated_preview - FROM llm_event_content - WHERE team_id = $1 AND trace_id = $2 AND call_sequence = $3`, - [teamId, traceId, callSequence] - ); - - const refs = refsResult.rows as ContentReference[]; - - // Optionally fetch full content from cold storage - const results: Array = []; - for (const ref of refs) { - const content = await getContentByHash(teamId, ref.content_hash, executor); - results.push({ ...ref, content: content || undefined }); - } - - return results; - } finally { - if (!client && executor && "release" in executor) { - (executor as PoolClient).release(); - } - } -}; - -interface DistinctAgentRecord { - agent: string; - agent_name: string | null; - first_seen: Date; - last_seen: Date; - total_requests: number; - total_cost: number; -} - -/** - * Get all distinct agents from events for a team - * Returns agent identifiers with their first/last seen timestamps and usage stats - */ -const getDistinctAgents = async ( - teamId: string, - options: { - since?: Date; - limit?: number; - } = {}, - client?: PoolClient -): Promise => { - const pool = client ? null : getTsdbPool(); - const executor = client || (await pool!.connect()); - - try { - const { since, limit = 100 } = options; - - let sql = ` - SELECT - agent, - MAX(agent_name) as agent_name, - MIN("timestamp") as first_seen, - MAX("timestamp") as last_seen, - COUNT(*) as total_requests, - COALESCE(SUM(cost_total), 0) as total_cost - FROM llm_events - WHERE team_id = $1 - AND agent IS NOT NULL - AND agent != '' - `; - - const params: unknown[] = [teamId]; - - if (since) { - sql += ` AND "timestamp" >= $${params.length + 1}`; - params.push(since); - } - - sql += ` - GROUP BY agent - ORDER BY last_seen DESC - LIMIT $${params.length + 1} - `; - params.push(limit); - - const result = await executor.query(sql, params); - - return result.rows.map((row: Record) => ({ - agent: row.agent as string, - agent_name: row.agent_name as string | null, - first_seen: new Date(row.first_seen as string), - last_seen: new Date(row.last_seen as string), - total_requests: Number(row.total_requests), - total_cost: Number(row.total_cost), - })); - } finally { - if (!client && executor && "release" in executor) { - (executor as PoolClient).release(); - } - } -}; - -export { - normalizeEvent, - normalizeEvents, - ensureSchema, - upsertEvents, - getTsdbPool, - getContentByHash, - getEventContent, - getDistinctAgents, -}; diff --git a/hive/src/services/tsdb/users_schema.sql b/hive/src/services/tsdb/users_schema.sql deleted file mode 100644 index 7a9c7257..00000000 --- a/hive/src/services/tsdb/users_schema.sql +++ /dev/null @@ -1,149 +0,0 @@ --- User Authentication Schema for PostgreSQL (Local Development) --- This schema mirrors the MySQL user tables for local development --- Run this on your local PostgreSQL/TimescaleDB instance - --- ============================================================================= --- USERS TABLE: Core user accounts --- ============================================================================= -CREATE TABLE IF NOT EXISTS users ( - id SERIAL PRIMARY KEY, - email VARCHAR(255) UNIQUE NOT NULL, - password VARCHAR(255), - name VARCHAR(255), - firstname VARCHAR(255), - lastname VARCHAR(255), - -- JWT authentication (TEXT for long JWT tokens) - token TEXT UNIQUE, - salt TEXT, - -- Team association - current_team_id INTEGER, - -- Account status - status VARCHAR(50) DEFAULT 'active', - email_verified BOOLEAN DEFAULT false, - -- Metadata - avatar_url TEXT, - preferences JSONB DEFAULT '{}', - -- Timestamps - created_at TIMESTAMPTZ DEFAULT NOW(), - updated_at TIMESTAMPTZ DEFAULT NOW(), - last_login_at TIMESTAMPTZ -); - --- Indexes for common lookups -CREATE INDEX IF NOT EXISTS idx_users_email ON users (email); -CREATE INDEX IF NOT EXISTS idx_users_token ON users (token); -CREATE INDEX IF NOT EXISTS idx_users_team ON users (current_team_id); - --- ============================================================================= --- DEVELOPERS TABLE: API tokens for programmatic access --- ============================================================================= -CREATE TABLE IF NOT EXISTS developers ( - id SERIAL PRIMARY KEY, - user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, - team_id INTEGER NOT NULL, - token TEXT UNIQUE NOT NULL, - label VARCHAR(255), - -- System tokens are managed by the platform, not users - "system" BOOLEAN DEFAULT false, - -- Permissions and scope - scopes JSONB DEFAULT '[]', - -- Rate limiting - rate_limit INTEGER DEFAULT 1000, - -- Timestamps - create_time BIGINT DEFAULT EXTRACT(EPOCH FROM NOW())::BIGINT, - last_used_at TIMESTAMPTZ, - expires_at TIMESTAMPTZ, - -- Status - revoked BOOLEAN DEFAULT false, - revoked_at TIMESTAMPTZ -); - --- Indexes for token lookups -CREATE INDEX IF NOT EXISTS idx_developers_token ON developers (token); -CREATE INDEX IF NOT EXISTS idx_developers_user ON developers (user_id); -CREATE INDEX IF NOT EXISTS idx_developers_team ON developers (team_id); -CREATE INDEX IF NOT EXISTS idx_developers_user_team ON developers (user_id, team_id); - --- ============================================================================= --- TEAMS TABLE: Team/Organization accounts --- ============================================================================= -CREATE TABLE IF NOT EXISTS teams ( - id SERIAL PRIMARY KEY, - name VARCHAR(255) NOT NULL, - slug VARCHAR(255) UNIQUE, - -- Billing and subscription - plan VARCHAR(50) DEFAULT 'free', - billing_email VARCHAR(255), - -- Settings - settings JSONB DEFAULT '{}', - -- Timestamps - created_at TIMESTAMPTZ DEFAULT NOW(), - updated_at TIMESTAMPTZ DEFAULT NOW() -); - --- ============================================================================= --- TEAM_MEMBERS TABLE: User-Team associations --- ============================================================================= -CREATE TABLE IF NOT EXISTS team_members ( - id SERIAL PRIMARY KEY, - user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, - team_id INTEGER NOT NULL REFERENCES teams(id) ON DELETE CASCADE, - role VARCHAR(50) DEFAULT 'member', - -- Timestamps - joined_at TIMESTAMPTZ DEFAULT NOW(), - UNIQUE(user_id, team_id) -); - -CREATE INDEX IF NOT EXISTS idx_team_members_user ON team_members (user_id); -CREATE INDEX IF NOT EXISTS idx_team_members_team ON team_members (team_id); - --- ============================================================================= --- SEED DATA: Default development user and team --- ============================================================================= - --- Create a default team -INSERT INTO teams (id, name, slug, plan) -VALUES (1, 'Development Team', 'dev-team', 'enterprise') -ON CONFLICT (id) DO NOTHING; - --- Create a default development user --- Email: dev@honeycomb.local --- Password: honeycomb123 -INSERT INTO users (id, email, password, name, firstname, lastname, token, salt, current_team_id, status, email_verified) -VALUES ( - 1, - 'dev@honeycomb.local', - '$2b$10$BgXnS6Cg7HwimTzBtsnh0.j8s8.ypWFooW9A.7YbNIC4e94HIFxYu', - 'Development User', - 'Dev', - 'User', - 'dev-token-12345', - 'dev-salt-secret-key', - 1, - 'active', - true -) -ON CONFLICT (id) DO NOTHING; - --- Create a default API token for the development user -INSERT INTO developers (id, user_id, team_id, token, label, "system") -VALUES ( - 1, - 1, - 1, - 'hive_dev_token_abc123xyz', - 'Development API Token', - false -) -ON CONFLICT (id) DO NOTHING; - --- Add user to team -INSERT INTO team_members (user_id, team_id, role) -VALUES (1, 1, 'admin') -ON CONFLICT (user_id, team_id) DO NOTHING; - --- Reset sequences to avoid conflicts -SELECT setval('users_id_seq', COALESCE((SELECT MAX(id) FROM users), 1)); -SELECT setval('teams_id_seq', COALESCE((SELECT MAX(id) FROM teams), 1)); -SELECT setval('developers_id_seq', COALESCE((SELECT MAX(id) FROM developers), 1)); -SELECT setval('team_members_id_seq', COALESCE((SELECT MAX(id) FROM team_members), 1)); diff --git a/hive/src/sockets/control.socket.ts b/hive/src/sockets/control.socket.ts deleted file mode 100644 index e5061804..00000000 --- a/hive/src/sockets/control.socket.ts +++ /dev/null @@ -1,98 +0,0 @@ -/** - * Control Socket Initialization - * - * Wrapper for initializing control plane WebSockets with proper dependencies. - */ - -import { Server } from 'socket.io'; -import { createAdapter } from '@socket.io/redis-adapter'; -import { Emitter } from '@socket.io/redis-emitter'; -import Redis from 'ioredis'; -import type { Server as HttpServer } from 'http'; - -import initAdenControlSockets, { setUserDbService } from '../services/control/control_sockets'; - -interface ControlEmitter { - emitPolicyUpdate: (teamId: string | number, policyId: string | null, policy: unknown) => void; - emitCommand: (teamId: string | number, command: { action: string; [key: string]: unknown }) => void; - emitAlert: (teamId: string | number, policyId: string | null, alert: unknown) => void; - emitToInstance: (teamId: string | number, instanceId: string, message: unknown) => boolean; - getConnectedCount: (teamId: string | number) => number; - getConnectedInstances: (teamId: string | number) => Array<{ - instance_id: string; - policy_id: string | null; - connected_at: string; - last_heartbeat: string; - }>; - getTotalConnectedCount: () => number; -} - -interface MockEmitter { - of: () => { - to: () => { emit: () => void }; - emit: () => void; - }; -} - -/** - * Initialize WebSockets for the control plane - * @param server - HTTP server instance - * @returns Promise<{io: Server, controlEmitter: Object}> - */ -async function initializeSockets(server: HttpServer): Promise<{ io: Server; controlEmitter: ControlEmitter }> { - // Create Socket.IO server - const io = new Server(server, { - cors: { - origin: '*', - methods: ['GET', 'POST'], - }, - transports: ['websocket', 'polling'], - }); - - let controlEmitter: ControlEmitter; - - // Try to setup Redis adapter for scaling - if (process.env.REDIS_URL) { - try { - const pubClient = new Redis(process.env.REDIS_URL); - const subClient = pubClient.duplicate(); - - await Promise.all([ - new Promise((resolve) => pubClient.on('connect', resolve)), - new Promise((resolve) => subClient.on('connect', resolve)), - ]); - - io.adapter(createAdapter(pubClient, subClient)); - - // Create Redis emitter for cross-instance communication - const redisEmitter = new Emitter(pubClient); - controlEmitter = initAdenControlSockets(io, redisEmitter as unknown as { of: (namespace: string) => { to: (room: string) => { emit: (event: string, payload: unknown) => void }; emit: (event: string, payload: unknown) => void } }); - - console.log('[Sockets] Redis adapter connected'); - } catch (err) { - console.warn('[Sockets] Redis connection failed, using local adapter:', (err as Error).message); - // Create a mock emitter for local development - const mockEmitter: MockEmitter = { - of: () => ({ - to: () => ({ emit: () => {} }), - emit: () => {}, - }), - }; - controlEmitter = initAdenControlSockets(io, mockEmitter as unknown as { of: (namespace: string) => { to: (room: string) => { emit: (event: string, payload: unknown) => void }; emit: (event: string, payload: unknown) => void } }); - } - } else { - console.warn('[Sockets] No REDIS_URL configured, using local adapter'); - // Create a mock emitter for local development - const mockEmitter: MockEmitter = { - of: () => ({ - to: () => ({ emit: () => {} }), - emit: () => {}, - }), - }; - controlEmitter = initAdenControlSockets(io, mockEmitter as unknown as { of: (namespace: string) => { to: (room: string) => { emit: (event: string, payload: unknown) => void }; emit: (event: string, payload: unknown) => void } }); - } - - return { io, controlEmitter }; -} - -export { initializeSockets, setUserDbService }; diff --git a/hive/src/types/acho-inc-administration.d.ts b/hive/src/types/acho-inc-administration.d.ts deleted file mode 100644 index 6e40ae19..00000000 --- a/hive/src/types/acho-inc-administration.d.ts +++ /dev/null @@ -1,123 +0,0 @@ -declare module '@acho-inc/administration' { - import { Pool } from 'pg'; - import { Strategy } from 'passport-jwt'; - - export interface MySQLPoolConfig { - host?: string; - port?: number; - user?: string; - password?: string; - database?: string; - ssl?: { - ca?: string | Buffer; - key?: string | Buffer; - cert?: string | Buffer; - } | null; - } - - export interface UserDbServiceConfig { - /** MySQL connection pool (for production) */ - mysqlPool?: any; - /** PostgreSQL connection pool (for local development) */ - pgPool?: Pool; - /** Database type: 'mysql' or 'postgres' */ - dbType?: 'mysql' | 'postgres'; - /** Redis client for caching (optional) */ - redisClient?: any; - /** Table name mapping */ - tables: { - USER: string; - DEVELOPERS?: string; - }; - /** Service account salt lookup function (optional) */ - findServiceAccountSalt?: (token: string) => Promise; - } - - export interface DevTokenObject { - id: number; - user_id: number; - team_id: number; - token: string; - label: string; - system?: boolean; - create_time: number; - } - - export interface LoginResult { - token: string; - email: string; - firstname?: string; - lastname?: string; - name?: string; - current_team_id?: number; - created_at?: Date | number; - } - - export interface TokenResult { - token: string; - salt: string; - } - - export interface LoginOptions { - jwtSecret: string; - expiresIn?: string; - } - - export interface RegisterOptions extends LoginOptions { - defaultTeamId?: number; - } - - export interface UserData { - email: string; - password: string; - name?: string; - firstname?: string; - lastname?: string; - } - - export interface RegisterResult { - id: number; - token: string; - email: string; - name?: string; - firstname?: string; - lastname?: string; - current_team_id?: number; - created_at?: Date; - } - - export interface UserDbService { - findSaltByToken: (token: string) => Promise; - findById: (id: number) => Promise; - findByToken: (token: string) => Promise; - findByEmail: (email: string) => Promise; - getLatestUserDevToken: (user: { id: number; current_team_id: number }) => Promise; - // Auth methods - verifyPassword: (password: string, hash: string) => Promise; - hashPassword: (password: string) => Promise; - generateToken: (user: any, options: LoginOptions) => Promise; - updateUserToken: (userId: number, token: string, salt: string) => Promise; - login: (email: string, password: string, options: LoginOptions) => Promise; - register: (userData: UserData, options: RegisterOptions) => Promise; - dbType?: 'mysql' | 'postgres'; - } - - export interface PassportStrategyConfig { - findSaltByToken: (token: string) => Promise; - jwtSecret?: string; - } - - export const auth: { - createPassportStrategy: (config: PassportStrategyConfig) => Strategy; - verifyToken: (token: string, secret: string) => Promise; - }; - - export const database: { - createMySQLPool: (config: MySQLPoolConfig) => any; - createPGPool: (connectionString: string) => Pool; - }; - - export const models: { - createUserDbService: (config: UserDbServiceConfig) => UserDbService; - }; -} diff --git a/hive/tests/endpoints/health.test.ts b/hive/tests/endpoints/health.test.ts deleted file mode 100644 index 927841a0..00000000 --- a/hive/tests/endpoints/health.test.ts +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Health Endpoint Tests - * - * Example test file demonstrating how to test API endpoints with supertest. - * Use this as a template for writing additional endpoint tests. - */ - -import request from 'supertest'; -import { createFullTestApp, TestAppResult } from '../utils/test-app'; - -describe('GET /health', () => { - let testApp: TestAppResult; - - beforeEach(async () => { - testApp = await createFullTestApp(); - }); - - it('should return 200 OK with correct response schema', async () => { - const response = await request(testApp.app) - .get('/health') - .expect(200) - .expect('Content-Type', /application\/json/); - - expect(response.body).toMatchObject({ - status: 'ok', - service: 'aden-hive', - timestamp: expect.any(String), - userDbType: 'postgres', - }); - }); - - it('should not require authentication', async () => { - const response = await request(testApp.app) - .get('/health') - .expect(200); - - expect(response.body.status).toBe('ok'); - }); - - it('should reflect database type configuration', async () => { - const mysqlApp = await createFullTestApp({ dbType: 'mysql' }); - - const response = await request(mysqlApp.app) - .get('/health') - .expect(200); - - expect(response.body.userDbType).toBe('mysql'); - }); -}); diff --git a/hive/tests/setup.ts b/hive/tests/setup.ts deleted file mode 100644 index 7aab0f50..00000000 --- a/hive/tests/setup.ts +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Jest Global Setup - * - * Configures environment variables and global mocks before all tests. - */ - -import { clearGlobalMongoMocks } from './utils/db-mocks'; -import { cleanupPassportStrategies } from './utils/test-app'; - -// Set test environment variables before any imports -process.env.NODE_ENV = 'test'; -process.env.PORT = '4001'; -process.env.JWT_SECRET = 'test-jwt-secret-for-testing-only'; -process.env.JWT_EXPIRES_IN = '1h'; - -// Cleanup after each test to prevent state leakage -afterEach(() => { - jest.clearAllMocks(); - clearGlobalMongoMocks(); - cleanupPassportStrategies(); -}); - -// Final cleanup after all tests complete -afterAll(() => { - clearGlobalMongoMocks(); - cleanupPassportStrategies(); -}); - -export {}; diff --git a/hive/tests/utils/auth-mocks.ts b/hive/tests/utils/auth-mocks.ts deleted file mode 100644 index f48244ad..00000000 --- a/hive/tests/utils/auth-mocks.ts +++ /dev/null @@ -1,124 +0,0 @@ -/** - * Authentication Mock Utilities - * - * Provides utilities for mocking JWT authentication and user context in tests. - */ - -import jwt from 'jsonwebtoken'; - -const TEST_JWT_SECRET_FALLBACK = 'test-jwt-secret-for-testing-only'; - -function getTestJwtSecret(): string { - return process.env.JWT_SECRET || TEST_JWT_SECRET_FALLBACK; -} - -// ============================================================================= -// User Factory -// ============================================================================= - -export interface MockUser { - id: number; - email: string; - current_team_id: number; - firstname?: string; - lastname?: string; - name?: string; - roles?: string[]; -} - -/** - * Create a mock user with sensible defaults - */ -export function createMockUser(overrides: Partial = {}): MockUser { - return { - id: 1, - email: 'test@example.com', - current_team_id: 1, - firstname: 'Test', - lastname: 'User', - name: 'Test User', - roles: ['user'], - ...overrides, - }; -} - -// ============================================================================= -// JWT Token Generation -// ============================================================================= - -export interface TokenPayload { - id: number; - email: string; - current_team_id: number; - [key: string]: unknown; -} - -/** - * Generate a valid JWT token for testing - */ -export function generateTestToken( - payload: Partial = {}, - options: { expiresIn?: number; secret?: string } = {} -): string { - const { expiresIn = 3600, secret = getTestJwtSecret() } = options; - - const defaultPayload: TokenPayload = { - id: 1, - email: 'test@example.com', - current_team_id: 1, - ...payload, - }; - - return jwt.sign(defaultPayload, secret, { expiresIn } as jwt.SignOptions); -} - -// ============================================================================= -// Mock User Database Service -// ============================================================================= - -/** - * Minimal MockUserDbService interface for testing - */ -export interface MockUserDbService { - findByToken: jest.Mock; - login: jest.Mock; - dbType: 'postgres' | 'mysql'; -} - -/** - * Create a mock userDbService for testing - */ -export function createMockUserDbService( - user: MockUser = createMockUser(), - options: { dbType?: 'postgres' | 'mysql' } = {} -): MockUserDbService { - const { dbType = 'postgres' } = options; - - return { - findByToken: jest.fn().mockResolvedValue(user), - login: jest.fn().mockResolvedValue({ - token: generateTestToken({ id: user.id, email: user.email, current_team_id: user.current_team_id }), - email: user.email, - firstname: user.firstname, - lastname: user.lastname, - name: user.name, - current_team_id: user.current_team_id, - created_at: new Date(), - }), - dbType, - }; -} - -// ============================================================================= -// Request Headers Helper -// ============================================================================= - -/** - * Create authorization header object for supertest - */ -export function authHeader(token?: string): Record { - const finalToken = token || generateTestToken(); - return { - Authorization: `Bearer ${finalToken}`, - }; -} diff --git a/hive/tests/utils/db-mocks.ts b/hive/tests/utils/db-mocks.ts deleted file mode 100644 index 3c73542b..00000000 --- a/hive/tests/utils/db-mocks.ts +++ /dev/null @@ -1,142 +0,0 @@ -/** - * Database Mock Utilities - * - * Provides mock factories for PostgreSQL and MongoDB connections. - * Use these to create isolated test environments without real database connections. - */ - -import { QueryResult } from 'pg'; - -// ============================================================================= -// PostgreSQL Mocks -// ============================================================================= - -export interface MockQueryResult> extends Partial> { - rows: T[]; - rowCount?: number; -} - -export interface MockPoolClient { - query: jest.Mock; - release: jest.Mock; -} - -export interface MockPool { - connect: jest.Mock>; - query: jest.Mock; - end: jest.Mock; -} - -/** - * Create a mock PostgreSQL pool client - */ -export function createMockPoolClient(defaultRows: unknown[] = []): MockPoolClient { - return { - query: jest.fn().mockResolvedValue({ rows: defaultRows, rowCount: defaultRows.length }), - release: jest.fn(), - }; -} - -/** - * Create a mock PostgreSQL pool - */ -export function createMockPool(defaultRows: unknown[] = []): MockPool { - return { - connect: jest.fn().mockImplementation(() => { - return Promise.resolve(createMockPoolClient(defaultRows)); - }), - query: jest.fn().mockResolvedValue({ rows: defaultRows, rowCount: defaultRows.length }), - end: jest.fn().mockResolvedValue(undefined), - }; -} - -// ============================================================================= -// MongoDB Mocks -// ============================================================================= - -export interface MockCollection { - find: jest.Mock; - findOne: jest.Mock; - insertOne: jest.Mock; - updateOne: jest.Mock; - deleteOne: jest.Mock; -} - -export interface MockDb { - collection: jest.Mock; -} - -export interface MockMongoClient { - connect: jest.Mock; - db: jest.Mock; - close: jest.Mock; -} - -/** - * Create a mock MongoDB collection - */ -export function createMockCollection(defaultDocs: unknown[] = []): MockCollection { - const cursor = { - toArray: jest.fn().mockResolvedValue(defaultDocs), - }; - - return { - find: jest.fn().mockReturnValue(cursor), - findOne: jest.fn().mockResolvedValue(defaultDocs[0] || null), - insertOne: jest.fn().mockResolvedValue({ insertedId: 'mock-id' }), - updateOne: jest.fn().mockResolvedValue({ matchedCount: 1, modifiedCount: 1 }), - deleteOne: jest.fn().mockResolvedValue({ deletedCount: 1 }), - }; -} - -/** - * Create a mock MongoDB database - */ -export function createMockDb(collections: Record = {}): MockDb { - return { - collection: jest.fn().mockImplementation((name: string) => { - return collections[name] || createMockCollection(); - }), - }; -} - -/** - * Create a mock MongoDB client - */ -export function createMockMongoClient(dbs: Record = {}): MockMongoClient { - return { - connect: jest.fn().mockResolvedValue(undefined), - db: jest.fn().mockImplementation((name: string) => { - return dbs[name] || createMockDb(); - }), - close: jest.fn().mockResolvedValue(undefined), - }; -} - -/** - * Setup global MongoDB mocks (for services that use global._ACHO_MG_DB) - */ -export function setupGlobalMongoMocks(collections: Record = {}): void { - const mockDb = createMockDb(collections); - const mockClient = createMockMongoClient({ erp: mockDb, aden: mockDb }); - - (global as Record)._ACHO_MG_DB = mockClient; - (global as Record)._ACHO_MDB_CONFIG = { - ERP_DBNAME: 'erp', - DBNAME: 'aden', - }; - (global as Record)._ACHO_MDB_COLLECTIONS = { - ADEN_CONTROL_POLICIES: 'aden_control_policies', - ADEN_CONTROL_CONTENT: 'aden_control_content', - LLM_PRICING: 'llm_pricing', - }; -} - -/** - * Clear global MongoDB mocks - */ -export function clearGlobalMongoMocks(): void { - delete (global as Record)._ACHO_MG_DB; - delete (global as Record)._ACHO_MDB_CONFIG; - delete (global as Record)._ACHO_MDB_COLLECTIONS; -} diff --git a/hive/tests/utils/index.ts b/hive/tests/utils/index.ts deleted file mode 100644 index 79153a3e..00000000 --- a/hive/tests/utils/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Test Utilities Index - * - * Re-exports all test utilities for convenient importing. - */ - -export * from './db-mocks'; -export * from './auth-mocks'; -export * from './test-app'; diff --git a/hive/tests/utils/test-app.ts b/hive/tests/utils/test-app.ts deleted file mode 100644 index 3d6bf05b..00000000 --- a/hive/tests/utils/test-app.ts +++ /dev/null @@ -1,118 +0,0 @@ -/** - * Test Application Factory - * - * Creates isolated Express app instances for testing with mocked dependencies. - */ - -import express, { Express, Request, Response, NextFunction } from 'express'; -import cors from 'cors'; -import passport from 'passport'; -import { Strategy as JwtStrategy, ExtractJwt } from 'passport-jwt'; -import { createMockPool, setupGlobalMongoMocks, MockPool } from './db-mocks'; -import { createMockUser, createMockUserDbService, MockUser, MockUserDbService } from './auth-mocks'; - -const TEST_JWT_SECRET_FALLBACK = 'test-jwt-secret-for-testing-only'; - -function getTestJwtSecret(): string { - return process.env.JWT_SECRET || TEST_JWT_SECRET_FALLBACK; -} - -const TEST_JWT_STRATEGY_NAME = 'jwt'; - -/** - * Cleanup Passport strategies registered by test apps. - * Call this in afterEach to prevent strategy accumulation across tests. - */ -export function cleanupPassportStrategies(): void { - try { - passport.unuse(TEST_JWT_STRATEGY_NAME); - } catch { - // Strategy not found - that's fine - } -} - -export interface TestAppOptions { - user?: MockUser; - mockPool?: MockPool; - dbType?: 'postgres' | 'mysql'; -} - -export interface TestAppResult { - app: Express; - mockPool: MockPool; - mockUserDbService: MockUserDbService; - mockUser: MockUser; -} - -/** - * Create a test application with routes mounted - * - * This creates a fresh Express app with mocked database connections, - * authentication, and real routes for integration testing. - */ -export async function createFullTestApp(options: TestAppOptions = {}): Promise { - const { - user = createMockUser(), - mockPool = createMockPool(), - dbType = 'postgres', - } = options; - - const app = express(); - - // Middleware (match production order) - app.use(cors()); - app.use(express.json({ limit: '10mb' })); - app.use(express.urlencoded({ extended: true })); - app.disable('x-powered-by'); - - // Setup mock user database service - const mockUserDbService = createMockUserDbService(user, { dbType }); - app.locals.userDbService = mockUserDbService; - app.locals.pgPool = mockPool; - - // Setup Passport JWT authentication - passport.use(new JwtStrategy({ - jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), - secretOrKey: getTestJwtSecret(), - }, (payload, done) => { - done(null, payload); - })); - app.use(passport.initialize()); - - // Setup global MongoDB mocks - setupGlobalMongoMocks(); - - // Health check endpoint - app.get('/health', (req: Request, res: Response) => { - res.json({ - status: 'ok', - service: 'aden-hive', - timestamp: new Date().toISOString(), - userDbType: dbType, - }); - }); - - // 404 handler - app.use((req: Request, res: Response) => { - res.status(404).json({ - error: 'not_found', - message: `Route ${req.method} ${req.path} not found`, - }); - }); - - // Error handler - app.use((err: Error & { status?: number }, req: Request, res: Response, _next: NextFunction) => { - const status = err.status || 500; - res.status(status).json({ - error: err.name || 'Error', - message: err.message || 'An unexpected error occurred', - }); - }); - - return { - app, - mockPool, - mockUserDbService, - mockUser: user, - }; -} diff --git a/hive/tsconfig.json b/hive/tsconfig.json deleted file mode 100644 index 29a905f7..00000000 --- a/hive/tsconfig.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "commonjs", - "lib": ["ES2022"], - "outDir": "./dist", - "rootDir": "./src", - "strict": false, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "declaration": false, - "sourceMap": true, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "noImplicitAny": false, - "strictNullChecks": false, - "noUnusedLocals": false, - "noUnusedParameters": false, - "useUnknownInCatchVariables": false, - "typeRoots": ["./node_modules/@types", "./src/types"] - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist", "tests"] -} diff --git a/hive/tsconfig.test.json b/hive/tsconfig.test.json deleted file mode 100644 index 6739f8f4..00000000 --- a/hive/tsconfig.test.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "rootDir": ".", - "types": ["jest", "node"], - "typeRoots": ["./node_modules/@types", "../node_modules/@types", "./src/types"] - }, - "include": ["src/**/*", "tests/**/*"], - "exclude": ["node_modules", "dist"] -} diff --git a/honeycomb/.dockerignore b/honeycomb/.dockerignore deleted file mode 100644 index 982246ac..00000000 --- a/honeycomb/.dockerignore +++ /dev/null @@ -1,9 +0,0 @@ -node_modules -dist -.env -.env.* -*.log -.DS_Store -.git -.vscode -.idea diff --git a/honeycomb/.env.example b/honeycomb/.env.example deleted file mode 100644 index 407158f7..00000000 --- a/honeycomb/.env.example +++ /dev/null @@ -1,13 +0,0 @@ -# Frontend Environment Variables -# Copy this file to .env and update values as needed -# Or run `npm run generate:env` from the root to generate from config.yaml - -# Hive API URL (handles all backend endpoints: auth, user, IAM, agent control) -VITE_API_URL=http://localhost:4000 - -# Application settings -VITE_APP_NAME=Hive -VITE_APP_ENV=development - -# Google OAuth (optional) -VITE_GOOGLE_OAUTH_ID=your-google-oauth-client-id diff --git a/honeycomb/.eslintrc.cjs b/honeycomb/.eslintrc.cjs deleted file mode 100644 index d6c95379..00000000 --- a/honeycomb/.eslintrc.cjs +++ /dev/null @@ -1,18 +0,0 @@ -module.exports = { - root: true, - env: { browser: true, es2020: true }, - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:react-hooks/recommended', - ], - ignorePatterns: ['dist', '.eslintrc.cjs'], - parser: '@typescript-eslint/parser', - plugins: ['react-refresh'], - rules: { - 'react-refresh/only-export-components': [ - 'warn', - { allowConstantExport: true }, - ], - }, -} diff --git a/honeycomb/Dockerfile b/honeycomb/Dockerfile deleted file mode 100644 index fa06b1c8..00000000 --- a/honeycomb/Dockerfile +++ /dev/null @@ -1,36 +0,0 @@ -# Build stage -FROM node:20-alpine AS builder - -WORKDIR /app - -# Build argument for API URL (Vite needs this at build time) -ARG VITE_API_URL=http://localhost:4000 -ENV VITE_API_URL=$VITE_API_URL - -# Copy package files -COPY package*.json ./ - -# Install dependencies -RUN npm install - -# Copy source code -COPY . . - -# Build the application -RUN npm run build - -# Production stage -FROM nginx:alpine AS production - -# Copy custom nginx config -COPY nginx.conf /etc/nginx/conf.d/default.conf - -# Copy built assets from builder -COPY --from=builder /app/dist /usr/share/nginx/html - -# Expose port -EXPOSE 3000 - -# Override the default entrypoint to skip noisy scripts -ENTRYPOINT [] -CMD ["sh", "-c", "echo '[Hive] Frontend ready at http://localhost:3000' && exec nginx -g 'daemon off;' 2>/dev/null"] diff --git a/honeycomb/Dockerfile.dev b/honeycomb/Dockerfile.dev deleted file mode 100644 index 282a0d69..00000000 --- a/honeycomb/Dockerfile.dev +++ /dev/null @@ -1,20 +0,0 @@ -# Development Dockerfile with hot reload -# The 'production' alias allows this to work with docker-compose.yml target -FROM node:20-alpine AS production - -WORKDIR /app - -# Copy package files -COPY package*.json ./ - -# Install dependencies -RUN npm install - -# Copy source code -COPY . . - -# Expose port -EXPOSE 3000 - -# Start development server with hot reload -CMD ["npm", "run", "dev"] diff --git a/honeycomb/components.json b/honeycomb/components.json deleted file mode 100644 index d29aef0b..00000000 --- a/honeycomb/components.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "$schema": "https://ui.shadcn.com/schema.json", - "style": "default", - "rsc": false, - "tsx": true, - "tailwind": { - "config": "tailwind.config.js", - "css": "src/styles/index.css", - "baseColor": "slate", - "cssVariables": true, - "prefix": "" - }, - "aliases": { - "components": "@/components", - "utils": "@/lib/utils", - "ui": "@/components/ui", - "lib": "@/lib", - "hooks": "@/hooks" - } -} diff --git a/honeycomb/index.html b/honeycomb/index.html deleted file mode 100644 index f891a023..00000000 --- a/honeycomb/index.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - Hive - - -
- - - diff --git a/honeycomb/nginx.conf b/honeycomb/nginx.conf deleted file mode 100644 index ef067b7a..00000000 --- a/honeycomb/nginx.conf +++ /dev/null @@ -1,46 +0,0 @@ -# Suppress noisy logs - only log errors -error_log /var/log/nginx/error.log error; -access_log off; - -server { - listen 3000; - server_name localhost; - root /usr/share/nginx/html; - index index.html; - - # Gzip compression - gzip on; - gzip_vary on; - gzip_min_length 1024; - gzip_proxied expired no-cache no-store private auth; - gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml application/javascript; - - # Security headers - add_header X-Frame-Options "SAMEORIGIN" always; - add_header X-Content-Type-Options "nosniff" always; - add_header X-XSS-Protection "1; mode=block" always; - - # Handle SPA routing - serve index.html for all routes - location / { - try_files $uri $uri/ /index.html; - } - - # Proxy API requests to backend - location /api { - proxy_pass http://hive:4000; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection 'upgrade'; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_cache_bypass $http_upgrade; - } - - # Cache static assets - location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ { - expires 1y; - add_header Cache-Control "public, immutable"; - } -} diff --git a/honeycomb/package.json b/honeycomb/package.json deleted file mode 100644 index d160ba35..00000000 --- a/honeycomb/package.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "name": "honeycomb", - "version": "0.1.0", - "private": true, - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc --noEmit && vite build", - "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", - "preview": "vite preview", - "test": "vitest --passWithNoTests", - "test:coverage": "vitest run --coverage", - "clean": "rm -rf dist node_modules" - }, - "dependencies": { - "@hookform/resolvers": "^5.2.2", - "@radix-ui/react-avatar": "^1.1.11", - "@radix-ui/react-dialog": "^1.1.15", - "@radix-ui/react-dropdown-menu": "^2.1.16", - "@radix-ui/react-label": "^2.1.8", - "@radix-ui/react-popover": "^1.1.15", - "@radix-ui/react-progress": "^1.1.8", - "@radix-ui/react-scroll-area": "^1.2.10", - "@radix-ui/react-select": "^2.2.6", - "@radix-ui/react-separator": "^1.1.8", - "@radix-ui/react-slot": "^1.2.4", - "@radix-ui/react-switch": "^1.2.6", - "@radix-ui/react-tabs": "^1.1.13", - "@radix-ui/react-tooltip": "^1.2.8", - "@tanstack/react-query": "^5.90.16", - "class-variance-authority": "^0.7.1", - "clsx": "^2.1.1", - "date-fns": "^4.1.0", - "react-day-picker": "^9.13.0", - "lucide-react": "^0.562.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-hook-form": "^7.71.0", - "react-markdown": "^10.1.0", - "react-router-dom": "^6.21.0", - "react-vega": "^8.0.0", - "recharts": "^3.6.0", - "socket.io-client": "^4.8.3", - "tailwind-merge": "^3.4.0", - "tailwindcss-animate": "^1.0.7", - "vega": "^6.2.0", - "vega-embed": "^7.1.0", - "vega-lite": "^6.4.1", - "zod": "^4.3.5", - "zustand": "^5.0.10" - }, - "devDependencies": { - "@testing-library/jest-dom": "^6.4.2", - "@testing-library/react": "^14.2.1", - "@testing-library/user-event": "^14.5.2", - "@types/react": "^18.2.43", - "@types/react-dom": "^18.2.17", - "@typescript-eslint/eslint-plugin": "^6.14.0", - "@typescript-eslint/parser": "^6.14.0", - "@vitejs/plugin-react": "^4.2.1", - "@types/node": "^20.10.0", - "autoprefixer": "^10.4.23", - "eslint": "^8.55.0", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-refresh": "^0.4.5", - "jsdom": "^24.0.0", - "postcss": "^8.5.6", - "tailwindcss": "^3.4.19", - "typescript": "^5.3.0", - "vite": "^5.0.8", - "vitest": "^1.1.0" - } -} \ No newline at end of file diff --git a/honeycomb/postcss.config.js b/honeycomb/postcss.config.js deleted file mode 100644 index 2e7af2b7..00000000 --- a/honeycomb/postcss.config.js +++ /dev/null @@ -1,6 +0,0 @@ -export default { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -} diff --git a/honeycomb/public/favicon.svg b/honeycomb/public/favicon.svg deleted file mode 100644 index 41fb817d..00000000 --- a/honeycomb/public/favicon.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/honeycomb/src/App.tsx b/honeycomb/src/App.tsx deleted file mode 100644 index ddd777b6..00000000 --- a/honeycomb/src/App.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'; -import { AgentControlLayout } from './components/agent-control/AgentControlLayout'; -import { DataPanel } from './components/agent-control/DataPanel'; -import { AnalyticsPanel } from './components/agent-control/AnalyticsPanel'; -import { CostControls } from './components/agent-control/CostControls'; -import { WorkersPanel } from './components/agent-control/WorkersPanel'; -import { NotFoundPage } from './pages/NotFoundPage'; -import { LoginPage } from './pages/LoginPage'; -import { RegisterPage } from './pages/RegisterPage'; -import { ProtectedRoute } from './components/auth/ProtectedRoute'; - -export function App() { - return ( - - - {/* Public routes */} - } /> - } /> - } /> - } /> - - {/* Protected routes */} - } /> - - - - } - > - } /> - } /> - } /> - } /> - - } /> - - - ); -} diff --git a/honeycomb/src/assets/aden-icon.png b/honeycomb/src/assets/aden-icon.png deleted file mode 100644 index 08e94456a876e7d2d3136f5d10af3ceb1d22d712..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2027 zcmVaE=UlwF&@JuVUUp{goG&SRx!v|* zzs}5^bI!~#2uP}?IVncRY6WL6F(GOMKq=h&A_~J0Fy_e5-T?vatk^x(n{IG|`~o)J zH>RqaHVGE17g973dcjz?5YX7)x$Wq*-ageEQm=knBV4yxw&)}fy5k67`=^pWsq|z` zb7|4tvAs;dM?e?_WAMdjQGCCX-aM4^`?+qWRy8HvSgaLGNVP z1ty|}^bPAOplbPiFp;jyH>LbL(00y&u1hz;1hkNDGF8jwdtdb%m%zYa23mf&0&N}F z<@E^Y3XSO@vS3~U_I&sXe1B*??A*EnbVUp4!y{u5B~bp3Ei2&ciFf7oEYJ-tq+_=j zMNt0P6YqHssyd;C^tN+1Aj%y4q(&?8T1dwyU{jua^99B0GDFekLGI9zOAvJq?pX~b zv*MtdSlOcW`#=LQ=z$-|(k0J8R4GXm!_#F?dUJY}Xd@jtck%DYi?1v%gRbsDr4O%K zNk>pTveM89-E>$er*W;P`#=?124}uH@;j`3=NO!n9}IT;Q3E4*D#vzKQGHl|=HOVE zdcF))f|4-Mk}97gd!czVP7obvyZ|l7{{$5n5qlrbjC#{LoxpiFhFbHL|N3jsDw9sJ z_dLNddF|WBA7|rOo60_gh@34BwZm36;;)cbPFNr7DCc3 zgrr-Daf=;rZdqMdXsRPf4$N%mtyE9sTxv*GK{-cS~kwgqjZqwwzzt*0@&0BA8~ z!!8|LI0-KdT1elyC<4PjG+ew%Z;)6G^)E-6ar<^ zF-elDm=ow{uyud%@h?Ek3}p{;xWXd{I8Gn<@&XVuN161hfL*({f|a`TP*5g4XfUSh z@*oi5piKJ0xxp$yaau-%gE8e&QQKfpCB}5`M0ikPq=hJxPEX?MP$oU-7)`@Lc#!mv z&|xRY>0(UxUX@3jzK|sHsQOVgBQZvL{l*uyZcX{@GBupBOge6r83Yu*L*vsDHW*a> zqqL<5-JAzoyN<_XU}2~3!%sF!=jpwD!ME)2kIBHgI$ZLk8eEitXSSF$yHHw0aZx5w z@+p_X57@6#@sG$F7##KqpQpR5s&=hUb|tI8P+&DPfc=#@K189c^= zj_Ar_bZi{X$Y~t5_{xehnP`dDMg=ENUxj_2p9hs_e_9hp+c3_K2i=(b2hh`h+iT&i z8uVgD9MR>2e*k{G8|&tSu7xWk*nOjDKR2M$X;Vf?&js#NgGrEt>;*9Ao=}i^8yLKo zjr+}~qR_vbQy}va$jIlHjHqhOhZg9LQ z8x!L#Ktvt^tPx+Cf8&Mf!`B5s5{Rhc^mT4uj2HKVGmN{Nfru=!mGAejWB$dhzkYUR zFM8`K25c1&kwSoI?C;!u(EtAfVc5Iz;(fpvP2r-2<9W^E0qIV9^AH~&uag7414I;X zc-&osUbAmbNVs@YIM-c6;tfak*eD#QXb*oYXO<1ckH+K6a4Z1AIMCZzQBh9e2%G8` zq^g@X3E+EaI%fn9m$R_m^9|`oy=hA6J}BR1v0Wg - - diff --git a/honeycomb/src/assets/aden-logo.svg b/honeycomb/src/assets/aden-logo.svg deleted file mode 100644 index 38f30b6d..00000000 --- a/honeycomb/src/assets/aden-logo.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - diff --git a/honeycomb/src/components/.gitkeep b/honeycomb/src/components/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/honeycomb/src/components/ErrorBoundary.tsx b/honeycomb/src/components/ErrorBoundary.tsx deleted file mode 100644 index 1011e485..00000000 --- a/honeycomb/src/components/ErrorBoundary.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { Component, ErrorInfo, ReactNode } from 'react' - -interface Props { - children: ReactNode -} - -interface State { - hasError: boolean - error?: Error -} - -export class ErrorBoundary extends Component { - constructor(props: Props) { - super(props) - this.state = { hasError: false } - } - - static getDerivedStateFromError(error: Error): State { - return { hasError: true, error } - } - - componentDidCatch(error: Error, errorInfo: ErrorInfo) { - console.error('Uncaught error:', error, errorInfo) - } - - render() { - if (this.state.hasError) { - return ( -
-
-

- Something went wrong -

-

- {this.state.error?.message || 'An unexpected error occurred'} -

- -
-
- ) - } - - return this.props.children - } -} diff --git a/honeycomb/src/components/agent-control/AgentControlLayout.tsx b/honeycomb/src/components/agent-control/AgentControlLayout.tsx deleted file mode 100644 index fc7c5436..00000000 --- a/honeycomb/src/components/agent-control/AgentControlLayout.tsx +++ /dev/null @@ -1,306 +0,0 @@ -import { useEffect } from 'react' -import { Outlet, NavLink, useNavigate, useLocation } from 'react-router-dom' -import { useControlSocket } from '@/hooks/useControlSocket' -import { useAgentControlStore } from '@/stores/agentControlStore' -import { useUserStore, type UserState } from '@/stores/userStore' -import { useSidebarCollapsed } from '@/hooks/usePersistedSettings' -import { NotificationBell } from './shared/NotificationBell' -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from '@/components/ui/dropdown-menu' -import { LiveIndicator } from './shared/LiveIndicator' -import { UserAvatar } from '@/components/user/UserAvatar' -import { Button } from '@/components/ui/button' -import adenLogo from '@/assets/aden-logo.svg' -import adenIcon from '@/assets/aden-icon.png' -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from '@/components/ui/tooltip' -import { cn } from '@/lib/utils' -import { - Database, - BarChart3, - DollarSign, - Users, - PanelLeftClose, - PanelLeft, - Settings, - Sparkles, - LogOut, - HelpCircle, - ExternalLink, - FileText, - MessageCircle, -} from 'lucide-react' -import { SettingsModal } from '@/components/settings/SettingsModal' -import { HelpDialog } from './shared/HelpDialog' - -const navItems = [ - { value: 'agents', label: 'Agents', path: '/agents', icon: Users }, - { value: 'data', label: 'Logs', path: '/data', icon: Database }, - { value: 'analytics', label: 'Performance Dashboard', path: '/performance-dashboard', icon: BarChart3 }, - { value: 'cost-control', label: 'Cost Control', path: '/cost-control', icon: DollarSign }, -] - -/** - * Main layout for Agent Control with sidebar navigation and socket lifecycle. - */ -export function AgentControlLayout() { - const { connect, disconnect, isConnected } = useControlSocket() - const hasActiveAgents = useAgentControlStore((state) => state.eventsBuffer.length > 0) - const user = useUserStore((state: UserState) => state.user) - const fullName = useUserStore((state: UserState) => state.fullName()) - const signOut = useUserStore((state: UserState) => state.signOut) - const isLoggingOut = useUserStore((state: UserState) => state.isLoggingOut) - const navigate = useNavigate() - const location = useLocation() - const { sidebarCollapsed, toggleSidebar } = useSidebarCollapsed() - - // Settings modal controlled by URL hash - const settingsOpen = location.hash === '#settings' - const handleSettingsClose = (open: boolean) => { - if (!open) { - navigate(location.pathname, { replace: true }) - } - } - - // Help dialog controlled by URL hash - const helpOpen = location.hash === '#help' - const handleHelpClose = (open: boolean) => { - if (!open) { - navigate(location.pathname, { replace: true }) - } - } - - // Connect socket on mount - useEffect(() => { - connect() - return () => disconnect() - }, [connect, disconnect]) - - return ( -
- {/* Sidebar - full height */} - - - {/* Right side - header bar + content */} -
- {/* Top bar with connection status + notifications */} -
- - - {/* Connection status - hidden during logout to prevent red flash */} - {!isLoggingOut && ( -
- - {isConnected ? 'Connected' : 'Disconnected'} -
- )} - - - - {/* Help dropdown */} - - - - - - navigate(`${location.pathname}#help`)}> - - Guide - - window.open('https://docs.adenhq.com/', '_blank')}> - - Documentation - - - window.open('https://discord.gg/MXE49hrKDk', '_blank')}> - - Discord - - - - -
- - {/* Content area */} -
-
- -
-
-
- - - -
- ) -} diff --git a/honeycomb/src/components/agent-control/AnalyticsPanel.tsx b/honeycomb/src/components/agent-control/AnalyticsPanel.tsx deleted file mode 100644 index 9a2add5b..00000000 --- a/honeycomb/src/components/agent-control/AnalyticsPanel.tsx +++ /dev/null @@ -1,351 +0,0 @@ -import { useMemo } from 'react' -import { Card } from '@/components/ui/card' -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@/components/ui/select' -import { Skeleton } from '@/components/ui/skeleton' -import { KpiCard } from './shared/KpiCard' -import { LiveIndicator } from './shared/LiveIndicator' -import { VegaLiteChart } from './charts/VegaLiteChart' -import { useAnalytics } from '@/hooks/queries/useAnalytics' -import { useAgentControlStore } from '@/stores/agentControlStore' -import { usePersistedTimeRange } from '@/hooks/usePersistedSettings' -import type { TimeRange } from '@/types/settings' -import { transformAnalyticsData, type CostByModelData } from './charts/transformers' -import { - createCostTrendSpec, - createTokenUsageSpec, - createCostByModelSpec, - createLatencyDistributionSpec, -} from './charts/specs' -import type { RawJsonData, KPIValues } from '@/types/agentControl' - -// Shape of analytics API response for type safety -interface AnalyticsResponse extends RawJsonData { - analytics?: { - summary?: { - total_cost?: number - total_requests?: number - total_tokens?: number - avg_latency_ms?: number - cache_savings?: number - } - } - kpis?: Record - summary?: Record -} - -const timeRangeOptions: { value: TimeRange; label: string }[] = [ - { value: 'all', label: 'All Time' }, - { value: 'month', label: 'Last Month' }, - { value: 'twoWeeks', label: 'Last 2 Weeks' }, - { value: 'week', label: 'Last Week' }, - { value: 'today', label: 'Today' }, -] - -// Helper to safely extract KPI values from raw API response -function extractKpis(data: RawJsonData | undefined): KPIValues { - const defaults: KPIValues = { - totalCost: 0, - projectedMonthlyCost: 0, - totalRequests: 0, - totalTokens: 0, - successRate: 0.99, - avgLatency: 0, - cacheSavings: 0, - } - - if (!data) return defaults - - // Handle new analytics response shape - const analyticsData = data as AnalyticsResponse - if (analyticsData?.analytics?.summary) { - const summary = analyticsData.analytics.summary - return { - totalCost: Number(summary.total_cost || 0), - projectedMonthlyCost: Number(summary.total_cost || 0) * 30, - totalRequests: Number(summary.total_requests || 0), - totalTokens: Number(summary.total_tokens || 0), - successRate: 0.99, // Not provided in new API - avgLatency: Number(summary.avg_latency_ms || 0), - cacheSavings: Number(summary.cache_savings || 0), - } - } - - // Fallback to old response shapes - const kpis = (data.kpis || data.summary || data) as Record - - return { - totalCost: Number(kpis.totalCost || kpis.total_cost || 0), - projectedMonthlyCost: Number(kpis.projectedMonthlyCost || kpis.projected_cost || 0), - totalRequests: Number(kpis.totalRequests || kpis.total_requests || 0), - totalTokens: Number(kpis.totalTokens || kpis.total_tokens || 0), - successRate: Number(kpis.successRate || kpis.success_rate || 0.99), - avgLatency: Number(kpis.avgLatency || kpis.avg_latency || 0), - cacheSavings: Number(kpis.cacheSavings || kpis.cache_savings || 0), - } -} - -/** - * Main analytics dashboard with KPIs and VegaLite charts. - */ -export function AnalyticsPanel() { - const { timeRange, setTimeRange } = usePersistedTimeRange() - const hasActiveAgents = useAgentControlStore((state) => state.eventsBuffer.length > 0) - - const { data: analytics, isLoading } = useAnalytics() - - const kpis = extractKpis(analytics as RawJsonData | undefined) - - // Transform API data to chart-ready format - const chartData = useMemo( - () => transformAnalyticsData(analytics), - [analytics] - ) - - // Create chart specs with memoization - const costTrendSpec = useMemo( - () => (chartData.costTrends.length > 0 ? createCostTrendSpec(chartData.costTrends) : null), - [chartData.costTrends] - ) - - const tokenUsageSpec = useMemo( - () => (chartData.tokenUsage.length > 0 ? createTokenUsageSpec(chartData.tokenUsage) : null), - [chartData.tokenUsage] - ) - - const costByModelSpec = useMemo( - () => (chartData.costByModel.length > 0 ? createCostByModelSpec(chartData.costByModel) : null), - [chartData.costByModel] - ) - - const latencyDistributionSpec = useMemo( - () => - chartData.latencyDistribution.length > 0 - ? createLatencyDistributionSpec(chartData.latencyDistribution) - : null, - [chartData.latencyDistribution] - ) - - const formatCurrency = (value: number) => - new Intl.NumberFormat('en-US', { - style: 'currency', - currency: 'USD', - minimumFractionDigits: 0, - maximumFractionDigits: 2, - }).format(value) - - const formatNumber = (value: number) => { - if (value >= 1000000) return `${(value / 1000000).toFixed(1)}M` - if (value >= 1000) return `${(value / 1000).toFixed(1)}K` - return value.toLocaleString() - } - - const formatPercent = (value: number) => `${(value * 100).toFixed(1)}%` - - return ( -
- {/* Header */} -
-
-

Analytics

- -
- -
- - {/* KPI Grid */} -
- - - - - } - /> - - - - } - /> - - - - } - /> - - - - } - /> - - - - } - /> -
- - {/* Charts Grid */} - {isLoading ? ( -
- {[...Array(4)].map((_, i) => ( - - - - - ))} -
- ) : ( -
- {/* Cost Trend Chart */} - -

Cost Trend

- {costTrendSpec ? ( - - ) : ( -
- No cost data available -
- )} -
- - {/* Token Usage Chart */} - -

Token Usage

- {tokenUsageSpec ? ( - - ) : ( -
- No token data available -
- )} -
- - {/* Cost by Model Chart */} - -

Cost by Model

- {costByModelSpec ? ( -
- -
- {chartData.costByModel.map((model: CostByModelData) => ( -
-
- {model.name} - {model.value}% - ${model.cost.toFixed(4)} -
- ))} -
-
- ) : ( -
- No model data available -
- )} - - - {/* Latency Distribution Chart */} - -

Latency Distribution

- {latencyDistributionSpec ? ( - - ) : ( -
- No latency data available -
- )} -
-
- )} -
- ) -} diff --git a/honeycomb/src/components/agent-control/CostControls.tsx b/honeycomb/src/components/agent-control/CostControls.tsx deleted file mode 100644 index 61074ecd..00000000 --- a/honeycomb/src/components/agent-control/CostControls.tsx +++ /dev/null @@ -1,279 +0,0 @@ -import { useState, useMemo } from 'react' -import { Button } from '@/components/ui/button' -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@/components/ui/select' -import { Skeleton } from '@/components/ui/skeleton' -import { BudgetCard } from './shared/BudgetCard' -import { KpiCard } from './shared/KpiCard' -import { AddBudgetDialog } from './budget/AddBudgetDialog' -import { BudgetDetailPanel } from './budget/BudgetDetailPanel' -import { useBudgets } from '@/hooks/queries/useBudgets' -import type { BudgetType, BudgetConfig, RawJsonData } from '@/types/agentControl' - -const budgetTypeOptions: { value: BudgetType | 'all'; label: string }[] = [ - { value: 'all', label: 'All Types' }, - { value: 'global', label: 'Global' }, - { value: 'agent', label: 'Agent' }, - { value: 'customer', label: 'Customer' }, - { value: 'feature', label: 'Feature' }, - { value: 'tag', label: 'Tag' }, -] - -// Extract budgets from API response (handles policy-based structure) -function extractBudgets(data: RawJsonData | undefined): BudgetConfig[] { - if (!data) return [] - if (Array.isArray(data)) return data as BudgetConfig[] - if (data.policies && Array.isArray(data.policies)) { - const allBudgets: BudgetConfig[] = [] - for (const policy of data.policies as Array<{ budgets?: BudgetConfig[] }>) { - if (policy.budgets) allBudgets.push(...policy.budgets) - } - return allBudgets - } - if (data.budgets && Array.isArray(data.budgets)) { - return data.budgets as BudgetConfig[] - } - return [] -} - -// Extract policyId from API response (uses first policy or 'default') -function extractPolicyId(data: RawJsonData | undefined): string | null { - if (!data) return null - if (data.policies && Array.isArray(data.policies) && data.policies.length > 0) { - return (data.policies[0] as { id?: string }).id || 'default' - } - return 'default' -} - -/** - * Budget management panel with summary cards and budget list. - */ -export function CostControls() { - const [typeFilter, setTypeFilter] = useState('all') - const [addDialogOpen, setAddDialogOpen] = useState(false) - const [selectedBudget, setSelectedBudget] = useState(null) - const [detailPanelOpen, setDetailPanelOpen] = useState(false) - - const handleBudgetClick = (budget: BudgetConfig) => { - setSelectedBudget(budget) - setDetailPanelOpen(true) - } - - const { data: rawData, isLoading, error } = useBudgets() - - // Parse budgets and policyId from API response - const budgets = useMemo( - () => extractBudgets(rawData as RawJsonData | undefined), - [rawData] - ) - - const policyId = useMemo( - () => extractPolicyId(rawData as RawJsonData | undefined), - [rawData] - ) - - // Compute summary stats - const summary = useMemo(() => { - if (!budgets.length) return null - return { - totalBudget: budgets.reduce((sum: number, b: BudgetConfig) => sum + b.limit, 0), - totalSpent: budgets.reduce((sum: number, b: BudgetConfig) => sum + b.spent, 0), - activeAlerts: budgets.filter((b: BudgetConfig) => - b.alerts.some((a) => a.enabled && b.spent / b.limit >= a.threshold / 100) - ).length, - budgetsAtRisk: budgets.filter((b: BudgetConfig) => b.spent / b.limit >= 0.9).length, - } - }, [budgets]) - - // Filter budgets by type - const filteredBudgets = useMemo( - () => budgets.filter((b: BudgetConfig) => typeFilter === 'all' || b.type === typeFilter), - [budgets, typeFilter] - ) - - const formatCurrency = (value: number) => - new Intl.NumberFormat('en-US', { - style: 'currency', - currency: 'USD', - minimumFractionDigits: 0, - maximumFractionDigits: 0, - }).format(value) - - if (error) { - return ( -
-

Failed to load budgets

- -
- ) - } - - return ( -
- {/* Summary Cards */} -
- - - - } - /> - 0 - ? { - value: Math.round((summary.totalSpent / summary.totalBudget) * 100), - direction: summary.totalSpent / summary.totalBudget > 0.8 ? 'up' : 'down', - } - : undefined - } - icon={ - - - - } - /> - 0} - icon={ - - - - } - /> - 0} - icon={ - - - - } - /> -
- - {/* Controls */} -
-

Budgets

-
- - -
-
- - {/* Budget List */} - {isLoading ? ( -
- {[...Array(4)].map((_, i) => ( - - ))} -
- ) : filteredBudgets.length === 0 ? ( -
-

No budgets found

-
- ) : ( -
- {filteredBudgets.map((budget: BudgetConfig) => ( - handleBudgetClick(budget)} - /> - ))} -
- )} - - {/* Add Budget Dialog */} - - - {/* Budget Detail Panel */} - -
- ) -} diff --git a/honeycomb/src/components/agent-control/DataPanel.tsx b/honeycomb/src/components/agent-control/DataPanel.tsx deleted file mode 100644 index b6fdd54b..00000000 --- a/honeycomb/src/components/agent-control/DataPanel.tsx +++ /dev/null @@ -1,521 +0,0 @@ -import { useState, useMemo } from 'react' -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' -import { Button } from '@/components/ui/button' -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@/components/ui/select' -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/ui/table' -import { Skeleton } from '@/components/ui/skeleton' -import { Badge } from '@/components/ui/badge' -import { LiveIndicator } from './shared/LiveIndicator' -import { DateRangePicker } from '@/components/ui/date-range-picker' -import { useLogs, useLogsAggregated } from '@/hooks/queries/useLogs' -import { useAgentControlStore } from '@/stores/agentControlStore' -import type { DateRange } from 'react-day-picker' - -type ViewType = 'raw' | 'metrics' | 'model' | 'agent' -type LogType = 'llm_request' | 'tool_call' | 'error' - -const viewOptions = [ - { value: 'raw', label: 'Raw Data' }, - { value: 'metrics', label: 'Metrics Summary' }, - { value: 'model', label: 'Model Usage' }, - { value: 'agent', label: 'Agent Activity' }, -] - -interface LogEntry { - id?: string - timestamp: string - derived_type: LogType - derived_success: boolean - agent?: string - model?: string - provider?: string - cost_total?: number - latency_ms?: number - finish_reason?: string - tool_call_count?: number - usage_input_tokens?: number - usage_output_tokens?: number - usage_total_tokens?: number - [key: string]: unknown -} - -interface AggregatedEntry { - model?: string - agent?: string - request_count: number - total_input_tokens: number - total_output_tokens: number - total_tokens: number - total_cost: number - avg_latency_ms: number - first_seen?: string - last_seen?: string -} - -export function DataPanel() { - const [viewType, setViewType] = useState('raw') - const [expandedRow, setExpandedRow] = useState(null) - - // Default date range: last 7 days - const [dateRange, setDateRange] = useState(() => { - const end = new Date() - end.setHours(23, 59, 59, 999) - const start = new Date() - start.setDate(start.getDate() - 7) - start.setHours(0, 0, 0, 0) - return { from: start, to: end } - }) - - const hasActiveAgents = useAgentControlStore((state) => state.eventsBuffer.length > 0) - - // Convert date range to ISO strings for API - const startDate = useMemo(() => { - return dateRange?.from?.toISOString() ?? new Date().toISOString() - }, [dateRange?.from]) - - const endDate = useMemo(() => { - return dateRange?.to?.toISOString() ?? new Date().toISOString() - }, [dateRange?.to]) - - // Fetch raw logs for 'raw' and 'metrics' views - const { - data: logsData, - isLoading: logsLoading, - error: logsError, - refetch: refetchLogs, - } = useLogs(startDate, endDate, 500, viewType === 'raw' || viewType === 'metrics') - - // Fetch aggregated data for 'model' view - const { - data: modelData, - isLoading: modelLoading, - error: modelError, - refetch: refetchModel, - } = useLogsAggregated(startDate, endDate, 'model', 100, viewType === 'model') - - // Fetch aggregated data for 'agent' view - const { - data: agentData, - isLoading: agentLoading, - error: agentError, - refetch: refetchAgent, - } = useLogsAggregated(startDate, endDate, 'agent', 100, viewType === 'agent') - - // Parse logs from API response - const logs = useMemo((): LogEntry[] => { - if (!logsData) return [] - const rawLogs = (logsData as { rows?: unknown[] }).rows || - (logsData as { logs?: unknown[] }).logs || - (Array.isArray(logsData) ? logsData : []) - return (rawLogs as LogEntry[]).map((log, idx) => ({ - ...log, - id: log.id || `log-${idx}`, - })) - }, [logsData]) - - // Parse aggregated data - const modelAggregations = useMemo((): AggregatedEntry[] => { - if (!modelData) return [] - return (modelData as { aggregations?: AggregatedEntry[] }).aggregations || [] - }, [modelData]) - - const agentAggregations = useMemo((): AggregatedEntry[] => { - if (!agentData) return [] - return (agentData as { aggregations?: AggregatedEntry[] }).aggregations || [] - }, [agentData]) - - // Determine loading/error state based on current view - const isLoading = viewType === 'raw' || viewType === 'metrics' - ? logsLoading - : viewType === 'model' - ? modelLoading - : agentLoading - - const error = viewType === 'raw' || viewType === 'metrics' - ? logsError - : viewType === 'model' - ? modelError - : agentError - - const refetch = viewType === 'raw' || viewType === 'metrics' - ? refetchLogs - : viewType === 'model' - ? refetchModel - : refetchAgent - - const handleExport = () => { - let csv = '' - - if (viewType === 'raw') { - if (!logs.length) return - csv = [ - ['Timestamp', 'Provider', 'Model', 'Agent', 'Tokens', 'Cost', 'Latency'].join(','), - ...logs.map((log) => - [ - log.timestamp, - log.provider || '-', - log.model || '-', - log.agent || '-', - log.usage_total_tokens ?? '-', - log.cost_total ? Number(log.cost_total).toFixed(6) : '-', - log.latency_ms ? `${Math.round(Number(log.latency_ms))}ms` : '-', - ].join(',') - ), - ].join('\n') - } else if (viewType === 'metrics') { - const successCount = logs.filter((l) => l.derived_success).length - const totalCost = logs.reduce((sum, l) => sum + (Number(l.cost_total) || 0), 0) - csv = [ - ['Metric', 'Value'].join(','), - ['Total Requests', logs.length].join(','), - ['Success Rate', `${((successCount / Math.max(logs.length, 1)) * 100).toFixed(1)}%`].join(','), - ['Total Cost', `$${totalCost.toFixed(2)}`].join(','), - ].join('\n') - } else if (viewType === 'model') { - if (!modelAggregations.length) return - csv = [ - ['Model', 'Requests', 'Input Tokens', 'Output Tokens', 'Total Cost', 'Avg Latency'].join(','), - ...modelAggregations.map((row) => - [ - row.model || '-', - row.request_count, - row.total_input_tokens, - row.total_output_tokens, - `$${row.total_cost.toFixed(4)}`, - `${Math.round(row.avg_latency_ms)}ms`, - ].join(',') - ), - ].join('\n') - } else if (viewType === 'agent') { - if (!agentAggregations.length) return - csv = [ - ['Agent', 'Requests', 'Input Tokens', 'Output Tokens', 'Total Cost', 'Avg Latency'].join(','), - ...agentAggregations.map((row) => - [ - row.agent || '-', - row.request_count, - row.total_input_tokens, - row.total_output_tokens, - `$${row.total_cost.toFixed(4)}`, - `${Math.round(row.avg_latency_ms)}ms`, - ].join(',') - ), - ].join('\n') - } - - if (!csv) return - - const blob = new Blob([csv], { type: 'text/csv' }) - const url = URL.createObjectURL(blob) - const a = document.createElement('a') - a.href = url - a.download = `logs-${viewType}-${new Date().toISOString().split('T')[0]}.csv` - a.click() - URL.revokeObjectURL(url) - } - - const formatTimestamp = (ts: string) => { - return new Date(ts).toLocaleString(undefined, { - month: 'short', - day: 'numeric', - hour: '2-digit', - minute: '2-digit', - second: '2-digit', - }) - } - - const getCardTitle = () => { - switch (viewType) { - case 'raw': - return 'Raw Data' - case 'metrics': - return 'Metrics Summary' - case 'model': - return 'Model Usage' - case 'agent': - return 'Agent Activity' - default: - return 'Data' - } - } - - const hasData = () => { - switch (viewType) { - case 'raw': - case 'metrics': - return logs.length > 0 - case 'model': - return modelAggregations.length > 0 - case 'agent': - return agentAggregations.length > 0 - default: - return false - } - } - - if (error) { - return ( -
-

Failed to load data

- -
- ) - } - - return ( -
- {/* Controls */} -
-
- - - -
- -
- - -
-
- - {/* Data Table */} - - - {getCardTitle()} - - - {isLoading ? ( -
- {[...Array(10)].map((_, i) => ( - - ))} -
- ) : !hasData() ? ( -
- No data found for the selected date range -
- ) : viewType === 'raw' ? ( - - - - Timestamp - Provider - Model - Agent - Tokens - Cost - Latency - - - - {logs.map((log) => ( - <> - - setExpandedRow(expandedRow === log.id ? null : log.id || null) - } - > - - {formatTimestamp(log.timestamp)} - - - - {log.provider || '-'} - - - - {log.model || '-'} - - - {log.agent || '-'} - - - {log.usage_total_tokens ?? '-'} - - - {log.cost_total ? `$${Number(log.cost_total).toFixed(6)}` : '-'} - - - {log.latency_ms ? `${Math.round(Number(log.latency_ms))}ms` : '-'} - - - {expandedRow === log.id && ( - - -
-                            {JSON.stringify(log, null, 2)}
-                          
-
-
- )} - - ))} -
-
- ) : viewType === 'metrics' ? ( - - - - Metric - Value - - - - - Total Requests - {logs.length} - - - Success Rate - - {( - (logs.filter((l) => l.derived_success).length / - Math.max(logs.length, 1)) * - 100 - ).toFixed(1)} - % - - - - Total Cost - - $ - {logs - .reduce((sum, l) => sum + (Number(l.cost_total) || 0), 0) - .toFixed(2)} - - - - Total Tokens - - {logs - .reduce((sum, l) => sum + (Number(l.usage_total_tokens) || 0), 0) - .toLocaleString()} - - - - Avg Latency - - {Math.round( - logs.reduce((sum, l) => sum + (Number(l.latency_ms) || 0), 0) / - Math.max(logs.length, 1) - )} - ms - - - -
- ) : viewType === 'model' ? ( - - - - Model - Requests - Input Tokens - Output Tokens - Total Cost - Avg Latency - - - - {modelAggregations.map((row, idx) => ( - - {row.model || '-'} - {row.request_count} - - {row.total_input_tokens.toLocaleString()} - - - {row.total_output_tokens.toLocaleString()} - - - ${row.total_cost.toFixed(4)} - - - {Math.round(row.avg_latency_ms)}ms - - - ))} - -
- ) : viewType === 'agent' ? ( - - - - Agent - Requests - Input Tokens - Output Tokens - Total Cost - Avg Latency - - - - {agentAggregations.map((row, idx) => ( - - {row.agent || '(no agent)'} - {row.request_count} - - {row.total_input_tokens.toLocaleString()} - - - {row.total_output_tokens.toLocaleString()} - - - ${row.total_cost.toFixed(4)} - - - {Math.round(row.avg_latency_ms)}ms - - - ))} - -
- ) : null} -
-
-
- ) -} diff --git a/honeycomb/src/components/agent-control/WorkersPanel.tsx b/honeycomb/src/components/agent-control/WorkersPanel.tsx deleted file mode 100644 index c22e61ab..00000000 --- a/honeycomb/src/components/agent-control/WorkersPanel.tsx +++ /dev/null @@ -1,276 +0,0 @@ -import { useState, useMemo } from 'react' -import { useQuery } from '@tanstack/react-query' -import { Card, CardContent } from '@/components/ui/card' -import { Avatar, AvatarFallback } from '@/components/ui/avatar' -import { Badge } from '@/components/ui/badge' -import { Skeleton } from '@/components/ui/skeleton' -import { KpiCard } from './shared/KpiCard' -import { WorkerProfilePanel } from './workers/WorkerProfilePanel' -import { useAgentControlStore } from '@/stores/agentControlStore' -import { getAgents } from '@/services/controlApi' -import { cn } from '@/lib/utils' -import type { AgentInfo, LLMEvent } from '@/types/agentControl' - -// Derive workers from events buffer -function deriveWorkersFromEvents(events: LLMEvent[]): AgentInfo[] { - const workerMap = new Map() - - for (const event of events) { - const existing = workerMap.get(event.agent) - if (existing) { - existing.total_requests++ - existing.total_cost += event.cost - if (new Date(event.timestamp) > new Date(existing.last_seen)) { - existing.last_seen = event.timestamp - } - } else { - workerMap.set(event.agent, { - agent: event.agent, - agent_name: null, - status: 'connected', - connection_type: 'websocket', - instance_id: null, - first_seen: event.timestamp, - last_seen: event.timestamp, - total_requests: 1, - total_cost: event.cost, - }) - } - } - - return Array.from(workerMap.values()) -} - -/** - * Worker/Agent management grid with status indicators. - */ -export function WorkersPanel() { - const [selectedWorker, setSelectedWorker] = useState(null) - const [profileOpen, setProfileOpen] = useState(false) - - // Fetch agents from API (past week) - const { data: agentsData, isLoading } = useQuery({ - queryKey: ['agents'], - queryFn: async () => { - const oneWeekAgo = new Date() - oneWeekAgo.setDate(oneWeekAgo.getDate() - 7) - return getAgents(oneWeekAgo.toISOString()) - }, - }) - - // Get real-time events from store - const eventsBuffer = useAgentControlStore((state) => state.eventsBuffer) - const realtimeAgents = useMemo(() => deriveWorkersFromEvents(eventsBuffer), [eventsBuffer]) - - // Merge API agents with real-time updates (real-time overrides API data) - const workers = useMemo(() => { - const apiAgents = agentsData?.agents || [] - const agentMap = new Map() - // Add API agents first - for (const agent of apiAgents) { - agentMap.set(agent.agent, agent) - } - // Override with real-time data - for (const agent of realtimeAgents) { - agentMap.set(agent.agent, agent) - } - return Array.from(agentMap.values()) - }, [agentsData?.agents, realtimeAgents]) - - // Compute summary stats - const onlineCount = workers.filter((w: AgentInfo) => w.status === 'connected').length - const offlineCount = workers.filter((w: AgentInfo) => w.status === 'disconnected').length - const totalRequests = workers.reduce((sum: number, w: AgentInfo) => sum + w.total_requests, 0) - - const handleWorkerClick = (worker: AgentInfo) => { - setSelectedWorker(worker) - setProfileOpen(true) - } - - const formatCurrency = (value: number) => - new Intl.NumberFormat('en-US', { - style: 'currency', - currency: 'USD', - minimumFractionDigits: 2, - }).format(value) - - return ( -
- {/* Summary Cards */} -
- - - - } - /> - 0} - icon={ - - - - } - /> - - - - } - /> - - - - } - /> -
- - {/* Workers Grid */} - {isLoading ? ( -
- {[...Array(6)].map((_, i) => ( - - ))} -
- ) : workers.length === 0 ? ( -
-

No agents found

-

- Agents will appear here when they connect and send events -

-
- ) : ( -
- {workers.map((worker: AgentInfo) => ( - handleWorkerClick(worker)} - formatCurrency={formatCurrency} - /> - ))} -
- )} - - {/* Worker Profile Panel */} - -
- ) -} - -interface WorkerCardProps { - worker: AgentInfo - onClick: () => void - formatCurrency: (value: number) => string -} - -function WorkerCard({ worker, onClick, formatCurrency }: WorkerCardProps) { - const isOnline = worker.status === 'connected' - - return ( - - -
- - - {(worker.agent_name || worker.agent).slice(0, 2).toUpperCase()} - - - -
-
- - {worker.agent_name || worker.agent} - - - {isOnline ? 'Online' : 'Offline'} - -
- -
-
- Requests - - {worker.total_requests.toLocaleString()} - -
-
- Cost - - {formatCurrency(worker.total_cost)} - -
-
-
-
-
-
- ) -} diff --git a/honeycomb/src/components/agent-control/budget/AddBudgetDialog.tsx b/honeycomb/src/components/agent-control/budget/AddBudgetDialog.tsx deleted file mode 100644 index ab9d4665..00000000 --- a/honeycomb/src/components/agent-control/budget/AddBudgetDialog.tsx +++ /dev/null @@ -1,184 +0,0 @@ -import { useState } from 'react' -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from '@/components/ui/dialog' -import { Button } from '@/components/ui/button' -import { Input } from '@/components/ui/input' -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@/components/ui/select' -import { useCreateBudget } from '@/hooks/queries/useBudgets' -import { useNotificationStore } from '@/stores/notificationStore' -import type { BudgetType } from '@/types/agentControl' - -interface AddBudgetDialogProps { - open: boolean - onOpenChange: (open: boolean) => void - policyId: string | null -} - -const budgetTypes: { value: BudgetType; label: string }[] = [ - { value: 'global', label: 'Global' }, - { value: 'agent', label: 'Agent' }, - { value: 'customer', label: 'Customer' }, - { value: 'feature', label: 'Feature' }, - { value: 'tag', label: 'Tag' }, -] - -/** - * Dialog for creating a new budget configuration. - */ -export function AddBudgetDialog({ open, onOpenChange, policyId }: AddBudgetDialogProps) { - const [name, setName] = useState('') - const [type, setType] = useState('agent') - const [limit, setLimit] = useState('100') - const [error, setError] = useState(null) - - const createBudget = useCreateBudget() - const addNotification = useNotificationStore((state) => state.addNotification) - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault() - setError(null) - - if (!policyId) { - setError('No policy available. Please try again later.') - return - } - - if (!name.trim()) { - setError('Name is required') - return - } - - const limitValue = parseFloat(limit) - if (isNaN(limitValue) || limitValue <= 0) { - setError('Limit must be greater than 0') - return - } - - try { - await createBudget.mutateAsync({ - policyId, - budget: { - id: name.trim().toLowerCase().replace(/\s+/g, '-'), - name: name.trim(), - type, - limit: limitValue, - spent: 0, - limitAction: 'throttle', - throttleRate: 1.0, - alerts: [ - { threshold: 80, enabled: true }, - { threshold: 100, enabled: true }, - ], - notifications: { - inApp: true, - email: false, - emailRecipients: [], - webhook: false, - }, - }, - }) - addNotification({ - type: 'success', - title: 'Budget created', - message: `"${name.trim()}" has been created successfully.`, - }) - handleClose() - } catch (err) { - addNotification({ - type: 'error', - title: 'Creation failed', - message: err instanceof Error ? err.message : 'Failed to create budget', - }) - } - } - - const handleClose = () => { - setName('') - setType('agent') - setLimit('100') - setError(null) - onOpenChange(false) - } - - return ( - - - - Create Budget - - Set up a new budget to control costs for agents, models, or features. - - - -
- {error && ( -
- {error} -
- )} - - {/* Name */} -
- - setName(e.target.value)} - placeholder="e.g., Production Agent Budget" - /> -
- - {/* Type */} -
- - -
- - {/* Limit */} -
- - setLimit(e.target.value)} - placeholder="100.00" - /> -
- - - - - -
-
-
- ) -} diff --git a/honeycomb/src/components/agent-control/budget/BudgetDetailPanel.tsx b/honeycomb/src/components/agent-control/budget/BudgetDetailPanel.tsx deleted file mode 100644 index 9ccaed1e..00000000 --- a/honeycomb/src/components/agent-control/budget/BudgetDetailPanel.tsx +++ /dev/null @@ -1,541 +0,0 @@ -import { useState, useEffect } from 'react' -import { - Sheet, - SheetContent, - SheetHeader, - SheetTitle, - SheetFooter, -} from '@/components/ui/sheet' -import { Button } from '@/components/ui/button' -import { Input } from '@/components/ui/input' -import { Label } from '@/components/ui/label' -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@/components/ui/select' -import { Progress } from '@/components/ui/progress' -import { Separator } from '@/components/ui/separator' -import { Badge } from '@/components/ui/badge' -import { Switch } from '@/components/ui/switch' -import { cn } from '@/lib/utils' -import { - DollarSign, - Bot, - User, - LayoutGrid, - Tag, - Trash2, - Plus, - X, - Bell, - Mail, -} from 'lucide-react' -import { useUpdateBudget, useDeleteBudget } from '@/hooks/queries/useBudgets' -import { useNotificationStore } from '@/stores/notificationStore' -import type { BudgetConfig, BudgetType, LimitAction } from '@/types/agentControl' - -interface BudgetDetailPanelProps { - budget: BudgetConfig | null - open: boolean - onOpenChange: (open: boolean) => void - policyId: string | null - existingBudgets: BudgetConfig[] -} - -const typeIcons: Record = { - global: DollarSign, - agent: Bot, - customer: User, - feature: LayoutGrid, - tag: Tag, -} - -const typeColors: Record = { - global: 'bg-blue-100 text-blue-700', - agent: 'bg-red-100 text-red-700', - customer: 'bg-purple-100 text-purple-700', - feature: 'bg-orange-100 text-orange-700', - tag: 'bg-green-100 text-green-700', -} - -const limitActions: { value: LimitAction; label: string; description: string }[] = [ - { value: 'throttle', label: 'Throttle', description: 'Rate limit requests when budget is exceeded' }, - { value: 'kill', label: 'Block', description: 'Stop all requests when budget is exceeded' }, -] - -/** - * Right-side slide-over panel for viewing and editing budget details. - */ -export function BudgetDetailPanel({ - budget, - open, - onOpenChange, - policyId, - existingBudgets, -}: BudgetDetailPanelProps) { - // Local state for editing - const [limit, setLimit] = useState('') - const [limitAction, setLimitAction] = useState('throttle') - const [throttleRate, setThrottleRate] = useState('1.0') - const [alerts, setAlerts] = useState<{ threshold: number; enabled: boolean }[]>([]) - const [newThreshold, setNewThreshold] = useState('') - const [emailEnabled, setEmailEnabled] = useState(false) - const [emailRecipients, setEmailRecipients] = useState([]) - const [newEmail, setNewEmail] = useState('') - const [inAppEnabled, setInAppEnabled] = useState(false) - const [isDirty, setIsDirty] = useState(false) - - const updateBudget = useUpdateBudget() - const deleteBudgetMutation = useDeleteBudget() - const addNotification = useNotificationStore((state) => state.addNotification) - - // Reset form when budget changes - useEffect(() => { - if (budget) { - setLimit(budget.limit.toString()) - setLimitAction(budget.limitAction) - setThrottleRate(budget.throttleRate?.toString() ?? '1.0') - setAlerts([...budget.alerts]) - setEmailEnabled(budget.notifications.email) - setEmailRecipients([...budget.notifications.emailRecipients]) - setInAppEnabled(budget.notifications.inApp) - setIsDirty(false) - setNewThreshold('') - setNewEmail('') - } - }, [budget]) - - if (!budget) return null - - const percentage = budget.limit > 0 ? (budget.spent / budget.limit) * 100 : 0 - const status = percentage >= 100 ? 'critical' : percentage >= 80 ? 'warning' : 'healthy' - const remaining = Math.max(0, budget.limit - budget.spent) - - const TypeIcon = typeIcons[budget.type] || DollarSign - - const formatCurrency = (value: number) => - new Intl.NumberFormat('en-US', { - style: 'currency', - currency: 'USD', - minimumFractionDigits: 0, - maximumFractionDigits: 0, - }).format(value) - - const handleChange = () => { - setIsDirty(true) - } - - const handleAddThreshold = () => { - const threshold = parseInt(newThreshold) - if (threshold > 0 && threshold <= 100 && !alerts.some(a => a.threshold === threshold)) { - setAlerts([...alerts, { threshold, enabled: true }].sort((a, b) => a.threshold - b.threshold)) - setNewThreshold('') - handleChange() - } - } - - const handleRemoveThreshold = (threshold: number) => { - setAlerts(alerts.filter(a => a.threshold !== threshold)) - handleChange() - } - - const handleToggleThreshold = (threshold: number) => { - setAlerts(alerts.map(a => - a.threshold === threshold ? { ...a, enabled: !a.enabled } : a - )) - handleChange() - } - - const handleSubmit = async () => { - if (!policyId || !budget) return - - try { - await updateBudget.mutateAsync({ - policyId, - budgetId: budget.id, - updates: { - limit: parseFloat(limit), - limitAction, - throttleRate: limitAction === 'throttle' ? parseFloat(throttleRate) : undefined, - alerts, - notifications: { - inApp: inAppEnabled, - email: emailEnabled, - emailRecipients, - webhook: budget.notifications.webhook, - }, - }, - existingBudgets, - }) - addNotification({ - type: 'success', - title: 'Budget updated', - message: `"${budget.name}" has been updated successfully.`, - }) - onOpenChange(false) - } catch (error) { - console.error('Failed to update budget:', error) - addNotification({ - type: 'error', - title: 'Update failed', - message: 'Failed to update budget. Please try again.', - }) - } - } - - const handleDelete = async () => { - if (!policyId || !budget) return - - if (confirm(`Are you sure you want to delete "${budget.name}"? This action cannot be undone.`)) { - try { - await deleteBudgetMutation.mutateAsync({ - policyId, - budgetId: budget.id, - existingBudgets, - }) - addNotification({ - type: 'success', - title: 'Budget deleted', - message: `"${budget.name}" has been deleted.`, - }) - onOpenChange(false) - } catch (error) { - console.error('Failed to delete budget:', error) - addNotification({ - type: 'error', - title: 'Delete failed', - message: 'Failed to delete budget. Please try again.', - }) - } - } - } - - return ( - - - {/* Header */} - -
-
- -
-
- {budget.name} -
- - {budget.type} - - {budget.tagCategory && ( - - {budget.tagCategory} - - )} -
-
-
-

- {formatCurrency(budget.spent)} of {formatCurrency(budget.limit)} used -

-
- - {/* Scrollable Content */} -
- {/* Budget Usage Section */} -
-

Budget Usage

-
-
- Progress - - {Math.round(percentage)}% - -
- div]:bg-green-500', - status === 'warning' && '[&>div]:bg-orange-500', - status === 'critical' && '[&>div]:bg-red-500' - )} - /> -
- Spent: {formatCurrency(budget.spent)} - Remaining: {formatCurrency(remaining)} -
-
-
- - - - {/* Monthly Limit Section */} -
- -
- $ - { - setLimit(e.target.value) - handleChange() - }} - className="pl-7" - /> -
-
- - - - {/* At Limit Action Section */} -
- - -

- {limitActions.find(a => a.value === limitAction)?.description} -

- - {/* Throttle Rate Config - shown when throttle is selected */} - {limitAction === 'throttle' && ( -
- - { - setThrottleRate(e.target.value) - handleChange() - }} - /> -

- Maximum requests per second when budget limit is reached -

-
- )} -
- - - - {/* Alert Thresholds Section */} -
- - - {alerts.length === 0 ? ( -

No alert thresholds configured

- ) : ( -
- {alerts.map((alert) => ( -
-
- handleToggleThreshold(alert.threshold)} - /> - - {alert.threshold}% - - - ({formatCurrency(budget.limit * alert.threshold / 100)}) - -
- -
- ))} -
- )} - - {/* Add new threshold */} -
-
- setNewThreshold(e.target.value)} - className="pr-8" - /> - % -
- -
-
- - - - {/* Notification Channels Section */} -
- -
- - -
- {emailEnabled && ( -
- {emailRecipients.length > 0 && ( -
- {emailRecipients.map((email) => ( -
- {email} - -
- ))} -
- )} -
- setNewEmail(e.target.value)} - onKeyDown={(e) => { - if (e.key === 'Enter') { - e.preventDefault() - const email = newEmail.trim().toLowerCase() - if (email && email.includes('@') && !emailRecipients.includes(email)) { - setEmailRecipients([...emailRecipients, email]) - setNewEmail('') - handleChange() - } - } - }} - className="flex-1" - /> - -
-
- )} -
-
- - {/* Footer */} - - -
- - - - - - ) -} diff --git a/honeycomb/src/components/agent-control/charts/CostByModelChart.tsx b/honeycomb/src/components/agent-control/charts/CostByModelChart.tsx deleted file mode 100644 index 293676ea..00000000 --- a/honeycomb/src/components/agent-control/charts/CostByModelChart.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import { PieChart, Pie, Cell, ResponsiveContainer, Legend, Tooltip } from 'recharts' -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' -import type { CostByModelData } from '@/types/agentControl' - -// Extended type with index signature for recharts compatibility -interface ChartData extends CostByModelData { - [key: string]: string | number | undefined -} - -interface CostByModelChartProps { - data: CostByModelData[] - title?: string - className?: string -} - -const COLORS = [ - 'hsl(var(--primary))', - 'hsl(var(--primary) / 0.8)', - 'hsl(var(--primary) / 0.6)', - 'hsl(var(--primary) / 0.4)', - 'hsl(220 70% 50%)', - 'hsl(280 70% 50%)', - 'hsl(340 70% 50%)', - 'hsl(160 70% 50%)', -] - -/** - * Donut chart showing cost distribution by model. - */ -export function CostByModelChart({ - data, - title = 'Cost by Model', - className, -}: CostByModelChartProps) { - const formatCurrency = (value: number) => - new Intl.NumberFormat('en-US', { - style: 'currency', - currency: 'USD', - minimumFractionDigits: 0, - maximumFractionDigits: 2, - }).format(value) - - const formatPercent = (value: number) => `${(value * 100).toFixed(1)}%` - - const totalCost = data.reduce((sum, item) => sum + item.cost, 0) - - // Cast data to chart-compatible type - const chartData: ChartData[] = data.map((d) => ({ ...d })) - - return ( - - - {title} - - -
- - - - {data.map((item, index) => ( - - ))} - - [formatCurrency(Number(value) || 0), 'Cost']} - contentStyle={{ - backgroundColor: 'hsl(var(--card))', - border: '1px solid hsl(var(--border))', - borderRadius: '6px', - }} - /> - { - const item = data.find((d) => d.name === value) - return ( - - {value}{' '} - - ({item ? formatPercent(item.cost / totalCost) : ''}) - - - ) - }} - /> - - -
-
- {formatCurrency(totalCost)} - Total Cost -
-
-
- ) -} diff --git a/honeycomb/src/components/agent-control/charts/CostTrendChart.tsx b/honeycomb/src/components/agent-control/charts/CostTrendChart.tsx deleted file mode 100644 index f7318503..00000000 --- a/honeycomb/src/components/agent-control/charts/CostTrendChart.tsx +++ /dev/null @@ -1,111 +0,0 @@ -import { - AreaChart, - Area, - XAxis, - YAxis, - CartesianGrid, - Tooltip, - ResponsiveContainer, - ReferenceLine, -} from 'recharts' -import { ReactNode } from 'react' -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' -import type { CostTrendData } from '@/types/agentControl' - -interface CostTrendChartProps { - data: CostTrendData[] - budgetLine?: number - title?: string - className?: string -} - -/** - * Area chart showing cost trends over time with optional budget line. - */ -export function CostTrendChart({ - data, - budgetLine, - title = 'Cost Trend', - className, -}: CostTrendChartProps) { - const formatCurrency = (value: number) => - new Intl.NumberFormat('en-US', { - style: 'currency', - currency: 'USD', - minimumFractionDigits: 0, - maximumFractionDigits: 0, - }).format(value) - - const formatDate = (label: ReactNode) => { - if (typeof label !== 'string') return String(label || '') - const date = new Date(label) - return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' }) - } - - return ( - - - {title} - - -
- - - - - - - - - - - - [formatCurrency(Number(value) || 0), 'Cost']} - labelFormatter={formatDate} - contentStyle={{ - backgroundColor: 'hsl(var(--card))', - border: '1px solid hsl(var(--border))', - borderRadius: '6px', - }} - /> - {budgetLine && ( - - )} - - - -
-
-
- ) -} diff --git a/honeycomb/src/components/agent-control/charts/LatencyChart.tsx b/honeycomb/src/components/agent-control/charts/LatencyChart.tsx deleted file mode 100644 index e71f904b..00000000 --- a/honeycomb/src/components/agent-control/charts/LatencyChart.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import { - BarChart, - Bar, - XAxis, - YAxis, - CartesianGrid, - Tooltip, - ResponsiveContainer, -} from 'recharts' -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' -import type { LatencyData } from '@/types/agentControl' - -interface LatencyChartProps { - data: LatencyData[] - title?: string - className?: string -} - -/** - * Bar chart showing latency distribution. - */ -export function LatencyChart({ - data, - title = 'Latency Distribution', - className, -}: LatencyChartProps) { - const formatCount = (value: number) => { - if (value >= 1000) return `${(value / 1000).toFixed(1)}K` - return value.toString() - } - - return ( - - - {title} - - -
- - - - - - [formatCount(Number(value) || 0), 'Requests']} - contentStyle={{ - backgroundColor: 'hsl(var(--card))', - border: '1px solid hsl(var(--border))', - borderRadius: '6px', - }} - /> - - - -
-
-
- ) -} diff --git a/honeycomb/src/components/agent-control/charts/ModelUsageChart.tsx b/honeycomb/src/components/agent-control/charts/ModelUsageChart.tsx deleted file mode 100644 index 38c8aa2f..00000000 --- a/honeycomb/src/components/agent-control/charts/ModelUsageChart.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import { - BarChart, - Bar, - XAxis, - YAxis, - CartesianGrid, - Tooltip, - ResponsiveContainer, -} from 'recharts' -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' -import type { ModelUsageData } from '@/types/agentControl' - -interface ModelUsageChartProps { - data: ModelUsageData[] - title?: string - className?: string -} - -/** - * Bar chart showing model usage by requests. - */ -export function ModelUsageChart({ - data, - title = 'Model Usage', - className, -}: ModelUsageChartProps) { - const formatNumber = (value: number) => { - if (value >= 1000000) return `${(value / 1000000).toFixed(1)}M` - if (value >= 1000) return `${(value / 1000).toFixed(1)}K` - return value.toString() - } - - // Sort by requests descending - const sortedData = [...data].sort((a, b) => b.requests - a.requests) - - return ( - - - {title} - - -
- - - - - - { - const numValue = Number(value) || 0 - if (name === 'requests') return [formatNumber(numValue), 'Requests'] - return [numValue, String(name)] - }} - contentStyle={{ - backgroundColor: 'hsl(var(--card))', - border: '1px solid hsl(var(--border))', - borderRadius: '6px', - }} - /> - - - -
-
-
- ) -} diff --git a/honeycomb/src/components/agent-control/charts/TokenUsageChart.tsx b/honeycomb/src/components/agent-control/charts/TokenUsageChart.tsx deleted file mode 100644 index f2bcd824..00000000 --- a/honeycomb/src/components/agent-control/charts/TokenUsageChart.tsx +++ /dev/null @@ -1,98 +0,0 @@ -import { - BarChart, - Bar, - XAxis, - YAxis, - CartesianGrid, - Tooltip, - ResponsiveContainer, - Legend, -} from 'recharts' -import { ReactNode } from 'react' -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' -import type { TokenUsageData } from '@/types/agentControl' - -interface TokenUsageChartProps { - data: TokenUsageData[] - title?: string - className?: string -} - -/** - * Stacked bar chart showing input/output token usage over time. - */ -export function TokenUsageChart({ - data, - title = 'Token Usage', - className, -}: TokenUsageChartProps) { - const formatNumber = (value: number) => { - if (value >= 1000000) return `${(value / 1000000).toFixed(1)}M` - if (value >= 1000) return `${(value / 1000).toFixed(1)}K` - return value.toString() - } - - const formatDate = (label: ReactNode) => { - if (typeof label !== 'string') return String(label || '') - const date = new Date(label) - return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' }) - } - - return ( - - - {title} - - -
- - - - - - [ - formatNumber(Number(value) || 0), - name === 'input' ? 'Input Tokens' : 'Output Tokens', - ]} - labelFormatter={formatDate} - contentStyle={{ - backgroundColor: 'hsl(var(--card))', - border: '1px solid hsl(var(--border))', - borderRadius: '6px', - }} - /> - - - - - -
-
-
- ) -} diff --git a/honeycomb/src/components/agent-control/charts/TopAgentsChart.tsx b/honeycomb/src/components/agent-control/charts/TopAgentsChart.tsx deleted file mode 100644 index 218f0d83..00000000 --- a/honeycomb/src/components/agent-control/charts/TopAgentsChart.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import { - BarChart, - Bar, - XAxis, - YAxis, - CartesianGrid, - Tooltip, - ResponsiveContainer, - Cell, -} from 'recharts' -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' -import type { TopAgentData } from '@/types/agentControl' - -interface TopAgentsChartProps { - data: TopAgentData[] - title?: string - className?: string -} - -/** - * Horizontal bar chart showing top agents by spend. - */ -export function TopAgentsChart({ - data, - title = 'Top Agents by Spend', - className, -}: TopAgentsChartProps) { - const formatCurrency = (value: number) => - new Intl.NumberFormat('en-US', { - style: 'currency', - currency: 'USD', - minimumFractionDigits: 0, - maximumFractionDigits: 0, - }).format(value) - - // Sort by spend descending and take top 10 - const sortedData = [...data].sort((a, b) => b.spend - a.spend).slice(0, 10) - - return ( - - - {title} - - -
- - - - - - { - const numValue = Number(value) || 0 - if (name === 'spend') return [formatCurrency(numValue), 'Spend'] - return [numValue, String(name)] - }} - contentStyle={{ - backgroundColor: 'hsl(var(--card))', - border: '1px solid hsl(var(--border))', - borderRadius: '6px', - }} - /> - - {sortedData.map((entry, index) => { - // Color based on limit usage - const limitRatio = entry.limit ? entry.spend / entry.limit : 0 - let fill = 'hsl(var(--primary))' - if (limitRatio >= 0.9) fill = 'hsl(var(--destructive))' - else if (limitRatio >= 0.75) fill = 'hsl(38 92% 50%)' - - return - })} - - - -
-
-
- ) -} diff --git a/honeycomb/src/components/agent-control/charts/VegaLiteChart.tsx b/honeycomb/src/components/agent-control/charts/VegaLiteChart.tsx deleted file mode 100644 index 4ecbcf70..00000000 --- a/honeycomb/src/components/agent-control/charts/VegaLiteChart.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import { useRef, useEffect, useState } from 'react' -import vegaEmbed, { type Result, type VisualizationSpec, type EmbedOptions } from 'vega-embed' -import { cn } from '@/lib/utils' - -interface VegaLiteChartProps { - spec: VisualizationSpec - className?: string - options?: EmbedOptions -} - -/** - * React wrapper component for VegaLite charts using vega-embed. - * Uses ResizeObserver to ensure container has valid dimensions before rendering. - * Handles mounting, updating, and cleanup of Vega views. - */ -export function VegaLiteChart({ spec, className, options }: VegaLiteChartProps) { - const containerRef = useRef(null) - const vegaResultRef = useRef(null) - const [isReady, setIsReady] = useState(false) - - // Wait for container to be ready with valid dimensions - useEffect(() => { - if (!containerRef.current) return - - const resizeObserver = new ResizeObserver((entries) => { - for (const entry of entries) { - if (entry.contentRect.width > 0) { - setIsReady(true) - } - } - }) - - resizeObserver.observe(containerRef.current) - - // Check initial dimensions - if (containerRef.current.clientWidth > 0) { - setIsReady(true) - } - - return () => resizeObserver.disconnect() - }, []) - - // Render chart when ready - useEffect(() => { - if (!containerRef.current || !spec || !isReady) return - - const renderChart = async () => { - // Cleanup previous render to prevent memory leaks - if (vegaResultRef.current) { - vegaResultRef.current.finalize() - vegaResultRef.current = null - } - - try { - const result = await vegaEmbed(containerRef.current!, spec, { - actions: false, - tooltip: { theme: 'dark' }, - ...options, - }) - vegaResultRef.current = result - } catch (error) { - console.error('Failed to render VegaLite chart:', error) - } - } - - renderChart() - - return () => { - // Cleanup on unmount or before re-render - if (vegaResultRef.current) { - vegaResultRef.current.finalize() - vegaResultRef.current = null - } - } - }, [spec, options, isReady]) - - return
-} diff --git a/honeycomb/src/components/agent-control/charts/index.ts b/honeycomb/src/components/agent-control/charts/index.ts deleted file mode 100644 index 799db1d2..00000000 --- a/honeycomb/src/components/agent-control/charts/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export { CostTrendChart } from './CostTrendChart' -export { TokenUsageChart } from './TokenUsageChart' -export { LatencyChart } from './LatencyChart' -export { CostByModelChart } from './CostByModelChart' -export { TopAgentsChart } from './TopAgentsChart' -export { ModelUsageChart } from './ModelUsageChart' diff --git a/honeycomb/src/components/agent-control/charts/specs.ts b/honeycomb/src/components/agent-control/charts/specs.ts deleted file mode 100644 index 8292cea0..00000000 --- a/honeycomb/src/components/agent-control/charts/specs.ts +++ /dev/null @@ -1,257 +0,0 @@ -/** - * VegaLite spec builders for analytics charts. - * Based on patterns from acho-launchpad's AnalyticsPanel.vue - */ - -import type { VisualizationSpec } from 'vega-embed' -import type { - CostTrendData, - TokenUsageData, - CostByModelData, - LatencyDistributionData, - LatencyPercentilesData, -} from './transformers' - -// ============================================================================= -// Cost Trend Chart (Area Chart with optional budget line) -// ============================================================================= - -export function createCostTrendSpec(data: CostTrendData[]): VisualizationSpec { - return { - $schema: 'https://vega.github.io/schema/vega-lite/v5.json', - width: 'container', - height: 220, - padding: { left: 10, right: 10, top: 10, bottom: 10 }, - data: { values: data }, - layer: [ - { - mark: { type: 'area', line: true, color: '#263A99', opacity: 0.3 }, - encoding: { - x: { - field: 'date', - type: 'ordinal', - sort: null, - axis: { title: null, labelAngle: -45 }, - }, - y: { - field: 'cost', - type: 'quantitative', - axis: { title: 'Cost ($)', format: '$.2f' }, - }, - tooltip: [ - { field: 'date', title: 'Date' }, - { field: 'cost', title: 'Cost', format: '$.4f' }, - ], - }, - }, - // Budget reference line (optional) - { - mark: { type: 'rule', color: '#c1392b', strokeDash: [5, 5], strokeWidth: 2 }, - encoding: { - y: { datum: 66.67 }, - }, - }, - ], - config: { view: { stroke: null } }, - } as VisualizationSpec -} - -// ============================================================================= -// Request Volume Chart (Bar Chart) -// ============================================================================= - -export function createRequestVolumeSpec(data: CostTrendData[]): VisualizationSpec { - return { - $schema: 'https://vega.github.io/schema/vega-lite/v5.json', - width: 'container', - height: 220, - padding: { left: 10, right: 10, top: 10, bottom: 10 }, - data: { values: data }, - mark: { - type: 'bar', - color: '#22c55e', - cornerRadiusTopLeft: 4, - cornerRadiusTopRight: 4, - }, - encoding: { - x: { - field: 'date', - type: 'ordinal', - sort: null, - axis: { title: null, labelAngle: -45 }, - }, - y: { - field: 'requests', - type: 'quantitative', - axis: { title: 'Requests' }, - }, - tooltip: [ - { field: 'date', title: 'Date' }, - { field: 'requests', title: 'Requests' }, - ], - }, - config: { view: { stroke: null } }, - } as VisualizationSpec -} - -// ============================================================================= -// Token Usage Chart (Stacked Bar Chart) -// ============================================================================= - -export function createTokenUsageSpec(data: TokenUsageData[]): VisualizationSpec { - return { - $schema: 'https://vega.github.io/schema/vega-lite/v5.json', - width: 'container', - height: 220, - padding: { left: 10, right: 10, top: 10, bottom: 10 }, - data: { values: data }, - mark: { - type: 'bar', - cornerRadiusTopLeft: 4, - cornerRadiusTopRight: 4, - }, - encoding: { - x: { - field: 'date', - type: 'ordinal', - sort: null, - axis: { title: null, labelAngle: -45 }, - }, - y: { - field: 'tokens', - type: 'quantitative', - axis: { title: 'Tokens', format: '.2s' }, - stack: true, - }, - color: { - field: 'type', - type: 'nominal', - scale: { domain: ['Input', 'Output'], range: ['#263A99', '#22c55e'] }, - legend: { orient: 'bottom', title: null }, - }, - tooltip: [ - { field: 'date', title: 'Date' }, - { field: 'type', title: 'Type' }, - { field: 'tokens', title: 'Tokens', format: ',.0f' }, - ], - }, - config: { view: { stroke: null } }, - } as VisualizationSpec -} - -// ============================================================================= -// Cost by Model Chart (Donut Chart) -// ============================================================================= - -export function createCostByModelSpec(data: CostByModelData[]): VisualizationSpec { - return { - $schema: 'https://vega.github.io/schema/vega-lite/v5.json', - width: 180, - height: 180, - data: { values: data }, - mark: { type: 'arc', innerRadius: 50 }, - encoding: { - theta: { field: 'value', type: 'quantitative' }, - color: { - field: 'name', - type: 'nominal', - scale: { - domain: data.map((m) => m.name), - range: data.map((m) => m.color), - }, - legend: null, - }, - tooltip: [ - { field: 'name', title: 'Model' }, - { field: 'value', title: 'Share (%)', format: '.0f' }, - { field: 'cost', title: 'Cost', format: '$.4f' }, - ], - }, - config: { view: { stroke: null } }, - } as VisualizationSpec -} - -// ============================================================================= -// Latency Distribution Chart (Bar Chart) -// ============================================================================= - -export function createLatencyDistributionSpec( - data: LatencyDistributionData[] -): VisualizationSpec { - return { - $schema: 'https://vega.github.io/schema/vega-lite/v5.json', - width: 'container', - height: 220, - padding: { left: 10, right: 10, top: 10, bottom: 10 }, - data: { values: data }, - mark: { - type: 'bar', - color: '#263A99', - cornerRadiusTopLeft: 4, - cornerRadiusTopRight: 4, - }, - encoding: { - x: { - field: 'range', - type: 'ordinal', - axis: { title: 'Latency Range' }, - sort: null, - }, - y: { - field: 'count', - type: 'quantitative', - axis: { title: 'Count' }, - }, - tooltip: [ - { field: 'range', title: 'Range' }, - { field: 'count', title: 'Count' }, - ], - }, - config: { view: { stroke: null } }, - } as VisualizationSpec -} - -// ============================================================================= -// Latency Percentiles Chart (Multi-line Chart) -// ============================================================================= - -export function createLatencyPercentilesSpec( - data: LatencyPercentilesData[] -): VisualizationSpec { - return { - $schema: 'https://vega.github.io/schema/vega-lite/v5.json', - width: 'container', - height: 220, - padding: { left: 10, right: 10, top: 10, bottom: 10 }, - data: { values: data }, - mark: { type: 'line', point: true }, - encoding: { - x: { - field: 'date', - type: 'ordinal', - sort: null, - axis: { title: null, labelAngle: -45 }, - }, - y: { - field: 'latency', - type: 'quantitative', - axis: { title: 'Latency (ms)' }, - }, - color: { - field: 'percentile', - type: 'nominal', - scale: { - domain: ['P50', 'P95', 'P99'], - range: ['#263A99', '#f59e0b', '#c1392b'], - }, - legend: null, - }, - tooltip: [ - { field: 'date', title: 'Date' }, - { field: 'percentile', title: 'Percentile' }, - { field: 'latency', title: 'Latency (ms)', format: '.0f' }, - ], - }, - config: { view: { stroke: null } }, - } as VisualizationSpec -} diff --git a/honeycomb/src/components/agent-control/charts/transformers.ts b/honeycomb/src/components/agent-control/charts/transformers.ts deleted file mode 100644 index 9538c3b2..00000000 --- a/honeycomb/src/components/agent-control/charts/transformers.ts +++ /dev/null @@ -1,339 +0,0 @@ -/** - * Data transformation utilities for converting API responses to chart-ready data. - * Based on patterns from acho-launchpad's useAgentControlData.ts - */ - -// Color palette for models (matches launchpad) -export const MODEL_COLORS = ['#263A99', '#22c55e', '#6b21a8', '#f59e0b', '#c1392b', '#06b6d4'] - -// ============================================================================= -// API Response Types (for type safety with unknown API data) -// ============================================================================= - -interface TimelineCostItem { - bucket: string - cost_total?: number -} - -interface TimelineRequestItem { - bucket: string - requests?: number -} - -interface TimelineTokenItem { - bucket: string - input_tokens?: number - output_tokens?: number -} - -interface TimelineLatencyItem { - bucket: string - p50_ms?: number - p95_ms?: number - p99_ms?: number -} - -interface TimelineData { - cost?: TimelineCostItem[] - requests?: TimelineRequestItem[] - tokens?: TimelineTokenItem[] - latency_percentiles?: TimelineLatencyItem[] -} - -interface CostByModelItem { - model?: string - cost_total?: number - share?: number -} - -interface CostByModelResponse { - models?: CostByModelItem[] -} - -interface LatencyBucketItem { - bucket: string - count?: number -} - -interface LatencyDistributionResponse { - buckets?: LatencyBucketItem[] -} - -interface CostByAgentItem { - agent?: string - cost_total?: number - requests?: number -} - -interface CostByAgentResponse { - agents?: CostByAgentItem[] -} - -interface AnalyticsData { - analytics?: { - timeline?: { - resolution?: string - hourly?: TimelineData - daily?: TimelineData - } - cost_by_model?: CostByModelResponse - latency_distribution?: LatencyDistributionResponse - cost_by_agent?: CostByAgentResponse - } -} - -// ============================================================================= -// Types for transformed chart data -// ============================================================================= - -export interface CostTrendData { - date: string - cost: number - requests: number - budget?: number -} - -export interface TokenUsageData { - date: string - type: 'Input' | 'Output' - tokens: number -} - -export interface CostByModelData { - name: string - cost: number - value: number // percentage - color: string -} - -export interface LatencyDistributionData { - range: string - count: number -} - -export interface LatencyPercentilesData { - date: string - percentile: 'P50' | 'P95' | 'P99' - latency: number -} - -export interface TopAgentData { - name: string - spend: number - requests: number - avgCost: number -} - -// ============================================================================= -// Format helpers -// ============================================================================= - -/** - * Format bucket label based on resolution - * For hourly: "2 PM", "3 PM", etc. - * For daily: "Dec 14", "Dec 15", etc. - */ -export function formatBucketLabel(bucket: string, resolution: 'day' | 'hour'): string { - const date = new Date(bucket) - if (resolution === 'hour') { - return date.toLocaleTimeString('en-US', { hour: 'numeric', hour12: true }) - } - return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }) -} - -// ============================================================================= -// Data transformers -// ============================================================================= - -/** - * Transform analytics API response to chart-ready data - */ -export function transformAnalyticsData(data: AnalyticsData | undefined) { - if (!data?.analytics) { - return { - costTrends: [], - tokenUsage: [], - costByModel: [], - latencyDistribution: [], - latencyPercentiles: [], - topAgents: [], - } - } - - const analytics = data.analytics - const resolution: 'day' | 'hour' = analytics.timeline?.resolution === 'hour' ? 'hour' : 'day' - const timeline = resolution === 'hour' ? analytics.timeline?.hourly : analytics.timeline?.daily - - return { - costTrends: transformCostTrends(timeline, resolution), - tokenUsage: transformTokenUsage(timeline, resolution), - costByModel: transformCostByModel(analytics.cost_by_model), - latencyDistribution: transformLatencyDistribution(analytics.latency_distribution), - latencyPercentiles: transformLatencyPercentiles(timeline, resolution), - topAgents: transformTopAgents(analytics.cost_by_agent), - } -} - -/** - * Transform cost timeline to cost trend data - */ -function transformCostTrends( - timeline: TimelineData | undefined, - resolution: 'day' | 'hour' -): CostTrendData[] { - if (!timeline?.cost || !Array.isArray(timeline.cost)) { - return [] - } - - // Create requests lookup map - const requestsMap = new Map( - (timeline.requests || []).map((r: TimelineRequestItem) => [r.bucket, r.requests ?? 0]) - ) - - return timeline.cost.map((d: TimelineCostItem) => ({ - date: formatBucketLabel(d.bucket, resolution), - cost: d.cost_total || 0, - requests: requestsMap.get(d.bucket) || 0, - budget: 66.67, // Default daily budget (~$2000/month / 30 days) - })) -} - -/** - * Transform token timeline to stacked bar chart data (flattened) - */ -function transformTokenUsage( - timeline: TimelineData | undefined, - resolution: 'day' | 'hour' -): TokenUsageData[] { - if (!timeline?.tokens || !Array.isArray(timeline.tokens)) { - return [] - } - - return timeline.tokens.flatMap((d: TimelineTokenItem) => [ - { - date: formatBucketLabel(d.bucket, resolution), - type: 'Input' as const, - tokens: d.input_tokens || 0, - }, - { - date: formatBucketLabel(d.bucket, resolution), - type: 'Output' as const, - tokens: d.output_tokens || 0, - }, - ]) -} - -/** - * Transform cost by model to pie/donut chart data - */ -function transformCostByModel(costByModel: CostByModelResponse | undefined): CostByModelData[] { - if (!costByModel?.models || !Array.isArray(costByModel.models)) { - return [] - } - - return costByModel.models.map((m: CostByModelItem, i: number) => ({ - name: m.model?.split('/').pop() || m.model || 'Unknown', - cost: m.cost_total || 0, - value: Math.round((m.share || 0) * 100), - color: MODEL_COLORS[i % MODEL_COLORS.length], - })) -} - -/** - * Aggregate API latency buckets to UI buckets - * API: 0-1s, 1-2s, 2-5s, 5-10s, 10-20s, 20s+ - * UI: 0-2s, 2-5s, 5-10s, 10-20s, 20s+ - */ -function transformLatencyDistribution( - latencyDistribution: LatencyDistributionResponse | undefined -): LatencyDistributionData[] { - if (!latencyDistribution?.buckets || !Array.isArray(latencyDistribution.buckets)) { - return [] - } - - const aggregated: Record = { - '0-2s': 0, - '2-5s': 0, - '5-10s': 0, - '10-20s': 0, - '20s+': 0, - } - - latencyDistribution.buckets.forEach((b: LatencyBucketItem) => { - switch (b.bucket) { - case '0-1s': - case '1-2s': - aggregated['0-2s'] += b.count || 0 - break - case '2-5s': - aggregated['2-5s'] += b.count || 0 - break - case '5-10s': - aggregated['5-10s'] += b.count || 0 - break - case '10-20s': - aggregated['10-20s'] += b.count || 0 - break - case '20s+': - aggregated['20s+'] += b.count || 0 - break - } - }) - - // Only return data if there are actual counts - const totalCount = Object.values(aggregated).reduce((sum, count) => sum + count, 0) - if (totalCount === 0) { - return [] - } - - return Object.entries(aggregated).map(([range, count]) => ({ range, count })) -} - -/** - * Transform latency percentiles to multi-line chart data (flattened) - */ -function transformLatencyPercentiles( - timeline: TimelineData | undefined, - resolution: 'day' | 'hour' -): LatencyPercentilesData[] { - if (!timeline?.latency_percentiles || !Array.isArray(timeline.latency_percentiles)) { - return [] - } - - return timeline.latency_percentiles.flatMap((d: TimelineLatencyItem) => [ - { - date: formatBucketLabel(d.bucket, resolution), - percentile: 'P50' as const, - latency: d.p50_ms || 0, - }, - { - date: formatBucketLabel(d.bucket, resolution), - percentile: 'P95' as const, - latency: d.p95_ms || 0, - }, - { - date: formatBucketLabel(d.bucket, resolution), - percentile: 'P99' as const, - latency: d.p99_ms || d.p95_ms || 0, - }, - ]) -} - -/** - * Transform cost by agent to top agents list - */ -function transformTopAgents(costByAgent: CostByAgentResponse | undefined): TopAgentData[] { - if (!costByAgent?.agents || !Array.isArray(costByAgent.agents)) { - return [] - } - - return costByAgent.agents.map((a: CostByAgentItem) => { - const requests = a.requests || 0 - return { - name: a.agent || 'Unknown', - spend: a.cost_total || 0, - requests, - avgCost: requests > 0 ? (a.cost_total || 0) / requests : 0, - } - }) -} diff --git a/honeycomb/src/components/agent-control/index.ts b/honeycomb/src/components/agent-control/index.ts deleted file mode 100644 index a1671983..00000000 --- a/honeycomb/src/components/agent-control/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -// Layout -export { AgentControlLayout } from './AgentControlLayout' - -// Main Panels -export { DataPanel } from './DataPanel' -export { AnalyticsPanel } from './AnalyticsPanel' -export { CostControls } from './CostControls' -export { WorkersPanel } from './WorkersPanel' - -// Shared components -export { LiveIndicator } from './shared/LiveIndicator' -export { KpiCard } from './shared/KpiCard' -export { BudgetCard } from './shared/BudgetCard' -export { NotificationBell } from './shared/NotificationBell' - -// Budget -export { AddBudgetDialog } from './budget/AddBudgetDialog' -export { BudgetDetailPanel } from './budget/BudgetDetailPanel' - -// Workers -export { WorkerProfilePanel } from './workers/WorkerProfilePanel' - -// Charts -export * from './charts' diff --git a/honeycomb/src/components/agent-control/shared/BudgetCard.tsx b/honeycomb/src/components/agent-control/shared/BudgetCard.tsx deleted file mode 100644 index 13dca7b4..00000000 --- a/honeycomb/src/components/agent-control/shared/BudgetCard.tsx +++ /dev/null @@ -1,172 +0,0 @@ -import { Progress } from '@/components/ui/progress' -import { Badge } from '@/components/ui/badge' -import { cn } from '@/lib/utils' -import { - DollarSign, - Bot, - User, - LayoutGrid, - Tag, - Ban, - Gauge, - ArrowDown, - Bell, - Mail, - Webhook, - ChevronRight, -} from 'lucide-react' -import type { BudgetConfig, BudgetType, LimitAction } from '@/types/agentControl' - -interface BudgetCardProps { - budget: BudgetConfig - onClick?: () => void - className?: string -} - -const typeIcons: Record = { - global: DollarSign, - agent: Bot, - customer: User, - feature: LayoutGrid, - tag: Tag, -} - -const typeColors: Record = { - global: 'bg-blue-100 text-blue-700', - agent: 'bg-red-100 text-red-700', - customer: 'bg-purple-100 text-purple-700', - feature: 'bg-orange-100 text-orange-700', - tag: 'bg-green-100 text-green-700', -} - -const actionIcons: Record = { - kill: Ban, - throttle: Gauge, - degrade: ArrowDown, - notify: Bell, -} - -const actionColors: Record = { - kill: 'bg-red-100 text-red-700', - throttle: 'bg-orange-100 text-orange-700', - degrade: 'bg-blue-100 text-blue-700', - notify: 'bg-green-100 text-green-700', -} - -const actionLabels: Record = { - kill: 'Block', - throttle: 'Throttle', - degrade: 'Degrade', - notify: 'Notify', -} - -/** - * Budget row with horizontal layout matching launchpad style. - */ -export function BudgetCard({ budget, onClick, className }: BudgetCardProps) { - const percentage = budget.limit > 0 ? (budget.spent / budget.limit) * 100 : 0 - const status = percentage >= 100 ? 'critical' : percentage >= 80 ? 'warning' : 'healthy' - - const TypeIcon = typeIcons[budget.type] || DollarSign - const ActionIcon = actionIcons[budget.limitAction] || Gauge - - const formatCurrency = (value: number) => - new Intl.NumberFormat('en-US', { - style: 'currency', - currency: 'USD', - minimumFractionDigits: 0, - maximumFractionDigits: 0, - }).format(value) - - return ( -
-
- {/* Left: Icon + Name + Badges */} -
-
- -
-
-

{budget.name}

-
- - {budget.type} - - {budget.tagCategory && ( - - {budget.tagCategory} - - )} -
-
-
- - {/* Middle: Progress */} -
-
- - {formatCurrency(budget.spent)} / {formatCurrency(budget.limit)} - - - {Math.round(percentage)}% - -
- div]:bg-green-500', - status === 'warning' && '[&>div]:bg-orange-500', - status === 'critical' && '[&>div]:bg-red-500' - )} - /> -
- - {/* Right: Actions + Notifications + Chevron */} -
- - - {actionLabels[budget.limitAction]} - - -
- {budget.notifications.inApp && ( - - )} - {budget.notifications.email && ( - - )} - {budget.notifications.webhook && ( - - )} -
- - -
-
-
- ) -} diff --git a/honeycomb/src/components/agent-control/shared/HelpDialog.tsx b/honeycomb/src/components/agent-control/shared/HelpDialog.tsx deleted file mode 100644 index eb17b84a..00000000 --- a/honeycomb/src/components/agent-control/shared/HelpDialog.tsx +++ /dev/null @@ -1,331 +0,0 @@ -import { useState } from 'react' -import { useNavigate, useLocation } from 'react-router-dom' -import { - KeyRound, - Code, - BarChart3, - AlertTriangle, - BookOpen, - Check, - Copy, - ChevronLeft, - ChevronRight, -} from 'lucide-react' -import { - Dialog, - DialogContent, - DialogTitle, - DialogDescription, -} from '@/components/ui/dialog' -import { Button } from '@/components/ui/button' -import { cn } from '@/lib/utils' - -interface HelpDialogProps { - open: boolean - onOpenChange: (open: boolean) => void -} - -const steps = [ - { - title: 'Get Your API Token', - description: 'Generate an API token to authenticate SDK requests and start tracking.', - icon: KeyRound, - }, - { - title: 'Complete SDK Quickstart', - description: 'Follow the SDK Quickstart to install, configure, and instrument your code.', - icon: Code, - }, - { - title: 'Verify Integration', - description: 'Confirm your setup is working and start monitoring your LLM usage.', - icon: BarChart3, - }, -] - -const envContent = `ADEN_API_KEY=your-api-token -ADEN_API_URL=https://kube.acho.io` - -export function HelpDialog({ open, onOpenChange }: HelpDialogProps) { - const [currentStep, setCurrentStep] = useState(0) - const [copied, setCopied] = useState(false) - const navigate = useNavigate() - const location = useLocation() - - const isFirstStep = currentStep === 0 - const isLastStep = currentStep === steps.length - 1 - const CurrentIcon = steps[currentStep].icon - - const goBack = () => { - if (!isFirstStep) { - setCurrentStep((prev) => prev - 1) - } - } - - const goNext = () => { - if (!isLastStep) { - setCurrentStep((prev) => prev + 1) - } - } - - const finish = () => { - onOpenChange(false) - setCurrentStep(0) - navigate(`${location.pathname}#settings/developers`) - } - - const copyEnvToClipboard = async () => { - try { - await navigator.clipboard.writeText(envContent) - setCopied(true) - setTimeout(() => setCopied(false), 2000) - } catch { - console.error('Failed to copy') - } - } - - const handleOpenChange = (open: boolean) => { - if (!open) { - setCurrentStep(0) - } - onOpenChange(open) - } - - return ( - - - {/* Header */} -
-
- -
-
- - Step {currentStep + 1} of {steps.length} - - - {steps[currentStep].title} - -
-
- - {/* Scrollable Content */} -
- - SDK onboarding walkthrough - -

- {steps[currentStep].description} -

- - {/* Step 1: Get Your API Token */} - {currentStep === 0 && ( -
- {/* Warning box */} -
- - - Keep your API token secure. Never commit it to version control or expose it in client-side code. - -
- - {/* Numbered steps */} -
- - - -
- - {/* Code block */} -
-

Add to your .env file:

-
-
-                    {envContent}
-                  
- -
-
-
- )} - - {/* Step 2: Complete SDK Quickstart */} - {currentStep === 1 && ( -
- {/* Info box */} -
-
- -
-
-

SDK Quickstart Guide

-

- Navigate to Settings → Developers → SDK Quickstart for complete setup instructions. -

-
-
- - {/* Checklist */} -
-

The quickstart covers:

-
    - - - - -
-
- - {/* Tip box */} -
- Tip: The SDK Quickstart includes copy-paste code snippets tailored to your account. -
-
- )} - - {/* Step 3: Verify Integration */} - {currentStep === 2 && ( -
- {/* Numbered steps */} -
- -
-
- 2 -
-
-

Check your dashboard

-

- Within 30 seconds, you should see data appear in: -

-
    -
  • - - Analytics tab — Request counts and cost trends -
  • -
  • - - Data tab — Detailed request logs -
  • -
-
-
-
- - {/* Warning/troubleshooting box */} -
- -
-

Not seeing data?

-
    -
  • Verify your API key is correct in .env
  • -
  • Ensure the SDK is initialized before LLM calls
  • -
  • Check for network/firewall issues
  • -
  • Review the troubleshooting section in Documentation
  • -
-
-
- - {/* Help text */} -

- Need more help? Return to Settings → Developers → Documentation for detailed troubleshooting. -

-
- )} -
- - {/* Progress Dots */} -
- {steps.map((_, index) => ( -
- - {/* Footer */} -
- {!isFirstStep ? ( - - ) : ( -
- )} - {!isLastStep ? ( - - ) : ( - - )} -
- -
- ) -} - -function NumberedStep({ - number, - title, - subtitle, -}: { - number: number - title: string - subtitle: string -}) { - return ( -
-
- {number} -
-
-

{title}

-

{subtitle}

-
-
- ) -} - -function ChecklistItem({ text }: { text: string }) { - return ( -
  • - - {text} -
  • - ) -} diff --git a/honeycomb/src/components/agent-control/shared/KpiCard.tsx b/honeycomb/src/components/agent-control/shared/KpiCard.tsx deleted file mode 100644 index b01c1c2c..00000000 --- a/honeycomb/src/components/agent-control/shared/KpiCard.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { Card, CardContent } from '@/components/ui/card' -import { Skeleton } from '@/components/ui/skeleton' -import { cn } from '@/lib/utils' - -interface KpiCardProps { - label: string - value: string | number - icon?: React.ReactNode - trend?: { value: number; direction: 'up' | 'down' } - highlight?: boolean - loading?: boolean - className?: string -} - -/** - * Real-time KPI display card with optional trend indicator. - */ -export function KpiCard({ - label, - value, - icon, - trend, - highlight, - loading, - className, -}: KpiCardProps) { - if (loading) { - return ( - - - - - - - ) - } - - return ( - - -
    - {label} - {icon && {icon}} -
    -
    - {value} - {trend && ( - - {trend.direction === 'up' ? '↑' : '↓'} {Math.abs(trend.value)}% - - )} -
    -
    -
    - ) -} diff --git a/honeycomb/src/components/agent-control/shared/LiveIndicator.test.tsx b/honeycomb/src/components/agent-control/shared/LiveIndicator.test.tsx deleted file mode 100644 index 8ff9beea..00000000 --- a/honeycomb/src/components/agent-control/shared/LiveIndicator.test.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { render, screen } from '@testing-library/react' -import { describe, it, expect } from 'vitest' -import { LiveIndicator } from './LiveIndicator' - -describe('LiveIndicator', () => { - it('renders "Live" text when isLive is true (default)', () => { - render() - - expect(screen.getByText('Live')).toBeInTheDocument() - }) - - it('renders the pulsing indicator dot', () => { - const { container } = render() - - const dot = container.querySelector('.bg-green-500') - expect(dot).toBeInTheDocument() - }) - - it('returns null when isLive is false', () => { - const { container } = render() - - expect(container.firstChild).toBeNull() - }) - - it('applies custom className', () => { - const { container } = render() - - const wrapper = container.firstChild as HTMLElement - expect(wrapper).toHaveClass('custom-class') - }) -}) diff --git a/honeycomb/src/components/agent-control/shared/LiveIndicator.tsx b/honeycomb/src/components/agent-control/shared/LiveIndicator.tsx deleted file mode 100644 index 9cf2314d..00000000 --- a/honeycomb/src/components/agent-control/shared/LiveIndicator.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { cn } from '@/lib/utils' - -interface LiveIndicatorProps { - isLive?: boolean - className?: string -} - -/** - * Pulsing dot indicator for live/active status. - */ -export function LiveIndicator({ isLive = true, className }: LiveIndicatorProps) { - if (!isLive) return null - - return ( -
    - - - - - Live -
    - ) -} diff --git a/honeycomb/src/components/agent-control/shared/NotificationBell.tsx b/honeycomb/src/components/agent-control/shared/NotificationBell.tsx deleted file mode 100644 index 022ec1da..00000000 --- a/honeycomb/src/components/agent-control/shared/NotificationBell.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import { useNavigate } from 'react-router-dom' -import { Button } from '@/components/ui/button' -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuSeparator, - DropdownMenuTrigger, -} from '@/components/ui/dropdown-menu' -import { ScrollArea } from '@/components/ui/scroll-area' -import { useNotificationStore } from '@/stores/notificationStore' -import { cn } from '@/lib/utils' - -/** - * Header notification bell with dropdown list. - */ -export function NotificationBell() { - const navigate = useNavigate() - const { notifications, unreadCount, markAsRead, markAllAsRead } = useNotificationStore() - - const handleNotificationClick = (notification: (typeof notifications)[0]) => { - markAsRead(notification.id) - - // Navigate to relevant panel based on notification type - if (notification.type === 'budget') { - navigate('/cost-control') - } - } - - const formatTime = (timestamp: string) => { - const date = new Date(timestamp) - const now = new Date() - const diffMs = now.getTime() - date.getTime() - const diffMins = Math.floor(diffMs / 60000) - const diffHours = Math.floor(diffMs / 3600000) - const diffDays = Math.floor(diffMs / 86400000) - - if (diffMins < 1) return 'Just now' - if (diffMins < 60) return `${diffMins}m ago` - if (diffHours < 24) return `${diffHours}h ago` - return `${diffDays}d ago` - } - - const typeIcons: Record = { - info: 'text-blue-500', - success: 'text-green-500', - warning: 'text-yellow-500', - error: 'text-red-500', - budget: 'text-purple-500', - } - - return ( - - - - - - -
    - Notifications - {unreadCount > 0 && ( - - )} -
    - - - - {notifications.length === 0 ? ( -
    - No notifications -
    - ) : ( - - {notifications.map((notification) => ( - handleNotificationClick(notification)} - > -
    - -
    -
    - - {notification.title} - - - {formatTime(notification.timestamp)} - -
    -

    - {notification.message} -

    -
    -
    -
    - ))} -
    - )} -
    -
    - ) -} diff --git a/honeycomb/src/components/agent-control/workers/WorkerProfilePanel.tsx b/honeycomb/src/components/agent-control/workers/WorkerProfilePanel.tsx deleted file mode 100644 index cb4d4106..00000000 --- a/honeycomb/src/components/agent-control/workers/WorkerProfilePanel.tsx +++ /dev/null @@ -1,171 +0,0 @@ -import { - Sheet, - SheetContent, - SheetDescription, - SheetHeader, - SheetTitle, -} from '@/components/ui/sheet' -import { Avatar, AvatarFallback } from '@/components/ui/avatar' -import { Badge } from '@/components/ui/badge' -import { Separator } from '@/components/ui/separator' -import { cn } from '@/lib/utils' -import type { AgentInfo } from '@/types/agentControl' - -interface WorkerProfilePanelProps { - worker: AgentInfo | null - open: boolean - onOpenChange: (open: boolean) => void -} - -/** - * Sidebar sheet showing detailed worker/agent information. - */ -export function WorkerProfilePanel({ - worker, - open, - onOpenChange, -}: WorkerProfilePanelProps) { - if (!worker) return null - - const isOnline = worker.status === 'connected' - - const formatDate = (dateString: string) => { - return new Date(dateString).toLocaleString(undefined, { - dateStyle: 'medium', - timeStyle: 'short', - }) - } - - const formatCurrency = (value: number) => - new Intl.NumberFormat('en-US', { - style: 'currency', - currency: 'USD', - minimumFractionDigits: 2, - }).format(value) - - const stats = [ - { - label: 'Total Requests', - value: worker.total_requests.toLocaleString(), - }, - { - label: 'Total Cost', - value: formatCurrency(worker.total_cost), - }, - { - label: 'First Seen', - value: formatDate(worker.first_seen), - }, - { - label: 'Last Seen', - value: formatDate(worker.last_seen), - }, - ] - - return ( - - - -
    - - - {(worker.agent_name || worker.agent).slice(0, 2).toUpperCase()} - - -
    - - {worker.agent_name || worker.agent} - - - {worker.agent} - -
    -
    -
    - -
    - {/* Status */} -
    - Status - - - {isOnline ? 'Online' : 'Offline'} - -
    - - {/* Connection Type */} - {worker.connection_type && ( -
    - Connection - {worker.connection_type} -
    - )} - - {/* Instance ID */} - {worker.instance_id && ( -
    - Instance ID - - {worker.instance_id.slice(0, 8)}... - -
    - )} - - - - {/* Stats */} -
    -

    Statistics

    -
    - {stats.map((stat) => ( -
    -
    {stat.label}
    -
    {stat.value}
    -
    - ))} -
    -
    - - - - {/* Activity Timeline (placeholder) */} -
    -

    Recent Activity

    -
    -
    -
    -
    -
    Connected
    -
    - {formatDate(worker.last_seen)} -
    -
    -
    -
    -
    -
    -
    First request
    -
    - {formatDate(worker.first_seen)} -
    -
    -
    -
    -
    -
    - - - ) -} diff --git a/honeycomb/src/components/auth/LoginForm.tsx b/honeycomb/src/components/auth/LoginForm.tsx deleted file mode 100644 index 4fdad098..00000000 --- a/honeycomb/src/components/auth/LoginForm.tsx +++ /dev/null @@ -1,127 +0,0 @@ -import { useForm } from 'react-hook-form' -import { zodResolver } from '@hookform/resolvers/zod' -import * as z from 'zod/v3' -import { Button } from '@/components/ui/button' -import { Input } from '@/components/ui/input' -import { useState } from 'react' -import { submitLogin } from '@/services/authApi' -import { useUserStore } from '@/stores/userStore' -import { useNavigate, useSearchParams, Link } from 'react-router-dom' - -const loginSchema = z.object({ - email: z.string().email('Please enter a valid email'), - password: z.string().min(1, 'Please enter your password'), -}) - -type LoginFormData = z.infer - -interface LoginFormProps { - orgPath?: string - orgName?: string - showSignup?: boolean -} - -export function LoginForm({ orgPath, orgName, showSignup = true }: LoginFormProps) { - const [error, setError] = useState('') - const [isSubmitting, setIsSubmitting] = useState(false) - const navigate = useNavigate() - const [searchParams] = useSearchParams() - const initUserProfile = useUserStore((s) => s.initUserProfile) - - const { - register, - handleSubmit, - formState: { errors }, - } = useForm({ - resolver: zodResolver(loginSchema), - }) - - const handleRedirect = () => { - const redirect = searchParams.get('redirect') - navigate(redirect ? decodeURIComponent(redirect) : '/') - } - - const handleLogin = async (data: LoginFormData) => { - setError('') - setIsSubmitting(true) - - try { - const res = await submitLogin(data) - - localStorage.removeItem('context_session_id') - localStorage.setItem('token', `jwt ${res.token}`) - - if (res.mustResetPassword) { - navigate(`/reset-password?token=${res.token}`) - return - } - - await initUserProfile() - handleRedirect() - } catch (err) { - setError((err as Error)?.message || 'Failed to login. Please check your credentials.') - } finally { - setIsSubmitting(false) - } - } - - return ( -
    - {orgName && ( -

    - Welcome to {orgName}'s ARP Platform -

    - )} - - {error &&

    {error}

    } - -
    -
    - - {errors.email && ( -

    {errors.email.message}

    - )} -
    - -
    - - {errors.password && ( -

    {errors.password.message}

    - )} -
    - - -
    - -
    - - Forgot password? - - - {showSignup && ( - - Don't have an account?{' '} - - Sign up - - - )} -
    -
    - ) -} diff --git a/honeycomb/src/components/auth/ProtectedRoute.tsx b/honeycomb/src/components/auth/ProtectedRoute.tsx deleted file mode 100644 index 1bcb45c2..00000000 --- a/honeycomb/src/components/auth/ProtectedRoute.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { Navigate, useLocation } from 'react-router-dom' -import { useUserStore } from '@/stores/userStore' -import { useEffect, useState } from 'react' - -interface ProtectedRouteProps { - children: React.ReactNode -} - -export function ProtectedRoute({ children }: ProtectedRouteProps) { - const location = useLocation() - const [isChecking, setIsChecking] = useState(true) - const [isAuthenticated, setIsAuthenticated] = useState(false) - const initUserProfile = useUserStore((s) => s.initUserProfile) - const user = useUserStore((s) => s.user) - - useEffect(() => { - const checkAuth = async () => { - const token = localStorage.getItem('token') - if (!token) { - setIsChecking(false) - return - } - - if (user) { - setIsAuthenticated(true) - setIsChecking(false) - return - } - - const result = await initUserProfile() - setIsAuthenticated(!!result) - setIsChecking(false) - } - - checkAuth() - }, [initUserProfile, user]) - - if (isChecking) { - return ( -
    -
    -
    - ) - } - - if (!isAuthenticated) { - const returnUrl = encodeURIComponent(location.pathname + location.search) - return - } - - return <>{children} -} diff --git a/honeycomb/src/components/auth/RegisterForm.tsx b/honeycomb/src/components/auth/RegisterForm.tsx deleted file mode 100644 index 2942f950..00000000 --- a/honeycomb/src/components/auth/RegisterForm.tsx +++ /dev/null @@ -1,205 +0,0 @@ -import { useForm } from 'react-hook-form' -import { zodResolver } from '@hookform/resolvers/zod' -import * as z from 'zod/v3' -import { Button } from '@/components/ui/button' -import { Input } from '@/components/ui/input' -import { useState } from 'react' -import { submitRegister } from '@/services/authApi' -import { useUserStore } from '@/stores/userStore' -import { useNavigate, useSearchParams, Link } from 'react-router-dom' -import { Eye, EyeOff } from 'lucide-react' - -const registerSchema = z - .object({ - firstname: z.string().min(1, 'First name is required'), - lastname: z.string().min(1, 'Last name is required'), - email: z.string().email('Please enter a valid email'), - password: z.string().min(8, 'Password must be at least 8 characters'), - confirmPassword: z.string().min(1, 'Please confirm your password'), - }) - .refine((data) => data.password === data.confirmPassword, { - message: 'Passwords do not match', - path: ['confirmPassword'], - }) - -type RegisterFormData = z.infer - -interface RegisterFormProps { - orgPath?: string - orgName?: string -} - -export function RegisterForm({ orgPath, orgName }: RegisterFormProps) { - const [error, setError] = useState('') - const [isSubmitting, setIsSubmitting] = useState(false) - const [showPassword, setShowPassword] = useState(false) - const [showConfirmPassword, setShowConfirmPassword] = useState(false) - const navigate = useNavigate() - const [searchParams] = useSearchParams() - const initUserProfile = useUserStore((s) => s.initUserProfile) - - const { - register, - handleSubmit, - watch, - formState: { errors, isValid }, - } = useForm({ - resolver: zodResolver(registerSchema), - mode: 'onChange', - }) - - const password = watch('password') - const confirmPassword = watch('confirmPassword') - const passwordsMatch = !confirmPassword || password === confirmPassword - - const handleRedirect = () => { - const redirect = searchParams.get('redirect') - navigate(redirect ? decodeURIComponent(redirect) : '/') - } - - const handleRegister = async (data: RegisterFormData) => { - setError('') - setIsSubmitting(true) - - try { - const res = await submitRegister({ - email: data.email, - password: data.password, - firstname: data.firstname, - lastname: data.lastname, - }) - - localStorage.removeItem('context_session_id') - localStorage.setItem('token', `jwt ${res.token}`) - - await initUserProfile() - handleRedirect() - } catch (err) { - setError((err as Error)?.message || 'Failed to register. Please try again.') - } finally { - setIsSubmitting(false) - } - } - - return ( -
    - {orgName && ( -

    - Join {orgName}'s ARP Platform -

    - )} - - {!orgName && ( -

    Create your account

    - )} - - {error &&

    {error}

    } - -
    -
    -
    - - {errors.firstname && ( -

    {errors.firstname.message}

    - )} -
    -
    - - {errors.lastname && ( -

    {errors.lastname.message}

    - )} -
    -
    - -
    - - {errors.email && ( -

    {errors.email.message}

    - )} -
    - -
    -
    - - -
    - {errors.password && ( -

    {errors.password.message}

    - )} -
    - -
    -
    - - -
    - {errors.confirmPassword && ( -

    {errors.confirmPassword.message}

    - )} - {!errors.confirmPassword && confirmPassword && !passwordsMatch && ( -

    Passwords do not match

    - )} -
    - - -
    - -
    - Already have an account? - - Sign in - -
    -
    - ) -} diff --git a/honeycomb/src/components/quickstart/AgentStatusIndicator.tsx b/honeycomb/src/components/quickstart/AgentStatusIndicator.tsx deleted file mode 100644 index 474b0728..00000000 --- a/honeycomb/src/components/quickstart/AgentStatusIndicator.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { cn } from '@/lib/utils' -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from '@/components/ui/tooltip' -import { useAgentStatus } from '@/hooks/useAgentStatus' - -interface AgentStatusIndicatorProps { - className?: string - showDetails?: boolean -} - -export function AgentStatusIndicator({ - className, - showDetails = true, -}: AgentStatusIndicatorProps) { - const { status, isConnected, error, hasActiveAgents, agentCount } = - useAgentStatus({ autoConnect: true, autoReconnect: true }) - - const formatTime = (timestamp: string) => { - return new Date(timestamp).toLocaleTimeString() - } - - const tooltipContent = () => { - if (error) { - return {error} - } - - if (!isConnected) { - return Connecting... - } - - if (!hasActiveAgents) { - return No agents connected - } - - if (showDetails && status?.instances?.length) { - return ( -
    -
    - {agentCount} agent{agentCount !== 1 ? 's' : ''} connected -
    -
    - {status.instances.slice(0, 5).map((instance) => ( -
    - {instance.instance_id.slice(0, 8)}... -{' '} - {formatTime(instance.connected_at)} -
    - ))} - {status.instances.length > 5 && ( -
    +{status.instances.length - 5} more
    - )} -
    -
    - ) - } - - return `${agentCount} agent${agentCount !== 1 ? 's' : ''} connected` - } - - const indicator = ( -
    - - {hasActiveAgents ? ( - <> - - - - ) : ( - - )} - - - {hasActiveAgents ? `${agentCount} connected` : 'No agents'} - -
    - ) - - return ( - - - {indicator} - - {tooltipContent()} - - - - ) -} diff --git a/honeycomb/src/components/quickstart/CodeBlock.tsx b/honeycomb/src/components/quickstart/CodeBlock.tsx deleted file mode 100644 index 6ed8c3fd..00000000 --- a/honeycomb/src/components/quickstart/CodeBlock.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { useState, useCallback } from 'react' -import { Copy, Check } from 'lucide-react' -import { Button } from '@/components/ui/button' -import { cn } from '@/lib/utils' -import { copyToClipboard } from '@/lib/quickstart' -import { useNotificationStore } from '@/stores/notificationStore' - -interface CodeBlockProps { - code: string - language?: string - className?: string -} - -export function CodeBlock({ code, language, className }: CodeBlockProps) { - const [copied, setCopied] = useState(false) - const addNotification = useNotificationStore((s) => s.addNotification) - - const handleCopy = useCallback(async () => { - const success = await copyToClipboard(code) - if (success) { - setCopied(true) - setTimeout(() => setCopied(false), 2000) - } else { - addNotification({ - type: 'error', - title: 'Copy failed', - message: 'Failed to copy code to clipboard', - }) - } - }, [code, addNotification]) - - return ( -
    -
    - {language && ( - - {language} - - )} - -
    -
    -        {code.trimEnd()}
    -      
    -
    - ) -} diff --git a/honeycomb/src/components/quickstart/MarkdownRenderer.tsx b/honeycomb/src/components/quickstart/MarkdownRenderer.tsx deleted file mode 100644 index 20378971..00000000 --- a/honeycomb/src/components/quickstart/MarkdownRenderer.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import ReactMarkdown from 'react-markdown' -import type { Components } from 'react-markdown' -import { CodeBlock } from './CodeBlock' - -interface MarkdownRendererProps { - content: string -} - -export function MarkdownRenderer({ content }: MarkdownRendererProps) { - const components: Components = { - // Handle fenced code blocks (wrapped in pre) - pre({ children }) { - return <>{children} - }, - // Handle all code elements - code({ className, children, node }) { - const match = /language-(\w+)/.exec(className || '') - const language = match ? match[1] : undefined - const codeContent = String(children).replace(/\n$/, '') - - // Check if this is inside a pre tag (block code) by looking at parent - const isBlock = node?.position && codeContent.includes('\n') || language - - if (isBlock) { - return - } - - // Inline code - return ( - - {children} - - ) - }, - h1: ({ children }) => ( -

    {children}

    - ), - h2: ({ children }) => ( -

    {children}

    - ), - h3: ({ children }) => ( -

    {children}

    - ), - p: ({ children }) =>

    {children}

    , - ul: ({ children }) =>
      {children}
    , - ol: ({ children }) => ( -
      {children}
    - ), - li: ({ children }) =>
  • {children}
  • , - a: ({ href, children }) => ( - - {children} - - ), - blockquote: ({ children }) => ( -
    - {children} -
    - ), - } - - return ( -
    - {content} -
    - ) -} diff --git a/honeycomb/src/components/quickstart/QuickstartToolbar.tsx b/honeycomb/src/components/quickstart/QuickstartToolbar.tsx deleted file mode 100644 index a813b076..00000000 --- a/honeycomb/src/components/quickstart/QuickstartToolbar.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import { Copy, Download } from 'lucide-react' -import { Button } from '@/components/ui/button' -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@/components/ui/select' -import type { SdkLanguage, AgentFramework } from '@/types/quickstart' - -interface QuickstartToolbarProps { - languages: SdkLanguage[] - frameworks: AgentFramework[] - selectedLanguage: string - selectedFramework: string - onLanguageChange: (value: string) => void - onFrameworkChange: (value: string) => void - onCopyAll: () => void - onDownload: () => void - isCopyDisabled: boolean - isDownloadDisabled: boolean -} - -export function QuickstartToolbar({ - languages, - frameworks, - selectedLanguage, - selectedFramework, - onLanguageChange, - onFrameworkChange, - onCopyAll, - onDownload, - isCopyDisabled, - isDownloadDisabled, -}: QuickstartToolbarProps) { - return ( -
    -
    - - - -
    - -
    - - -
    -
    - ) -} diff --git a/honeycomb/src/components/quickstart/SDKQuickstart.tsx b/honeycomb/src/components/quickstart/SDKQuickstart.tsx deleted file mode 100644 index 5a45a6c0..00000000 --- a/honeycomb/src/components/quickstart/SDKQuickstart.tsx +++ /dev/null @@ -1,229 +0,0 @@ -import { useState, useEffect, useMemo, useCallback } from 'react' -import { Loader2, RefreshCw } from 'lucide-react' -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' -import { Button } from '@/components/ui/button' -import { Skeleton } from '@/components/ui/skeleton' -import { - useQuickstartOptions, - useGenerateQuickstart, -} from '@/hooks/queries/useQuickstart' -import { useNotificationStore } from '@/stores/notificationStore' -import { - extractCodeBlocks, - copyToClipboard, - downloadAsFile, -} from '@/lib/quickstart' -import { QuickstartToolbar } from './QuickstartToolbar' -import { MarkdownRenderer } from './MarkdownRenderer' -import { AgentStatusIndicator } from './AgentStatusIndicator' -import type { AgentFramework } from '@/types/quickstart' - -export function SDKQuickstart() { - const [selectedLanguage, setSelectedLanguage] = useState('python') - const [selectedFramework, setSelectedFramework] = useState('') - - const addNotification = useNotificationStore((s) => s.addNotification) - - const { - data: options, - isLoading: optionsLoading, - error: optionsError, - } = useQuickstartOptions() - - const generateMutation = useGenerateQuickstart() - - // Filter frameworks by language support - const availableFrameworks = useMemo(() => { - if (!options?.agentFrameworks) return [] - return options.agentFrameworks.filter((fw) => - selectedLanguage === 'python' ? fw.pythonSupport : fw.typescriptSupport - ) - }, [options, selectedLanguage]) - - // Auto-select first framework when options load or language changes - useEffect(() => { - if (availableFrameworks.length > 0 && !selectedFramework) { - setSelectedFramework(availableFrameworks[0].id) - } - }, [availableFrameworks, selectedFramework]) - - // Generate docs - const generateDocs = useCallback(() => { - if (!selectedFramework) return - generateMutation.mutate({ - agentFramework: selectedFramework, - sdkLanguage: selectedLanguage, - }) - }, [selectedFramework, selectedLanguage, generateMutation]) - - // Auto-generate on initial load and when selections change - useEffect(() => { - if (selectedFramework && options) { - generateDocs() - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [selectedFramework, selectedLanguage]) - - // Handle language change - const handleLanguageChange = useCallback( - (newLanguage: string) => { - setSelectedLanguage(newLanguage) - - // Check if current framework supports new language - const newFrameworks = options?.agentFrameworks?.filter((fw) => - newLanguage === 'python' ? fw.pythonSupport : fw.typescriptSupport - ) - const frameworkStillValid = newFrameworks?.some( - (fw) => fw.id === selectedFramework - ) - - if (!frameworkStillValid) { - // Will auto-select via useEffect - setSelectedFramework('') - } - }, - [options, selectedFramework] - ) - - // Handle framework change - const handleFrameworkChange = useCallback((frameworkId: string) => { - setSelectedFramework(frameworkId) - }, []) - - // Copy all code blocks - const handleCopyAll = useCallback(async () => { - if (!generateMutation.data?.markdown) return - - const codeBlocks = extractCodeBlocks(generateMutation.data.markdown) - if (codeBlocks.length === 0) { - addNotification({ - type: 'warning', - title: 'No code to copy', - message: 'No code blocks found in the documentation', - }) - return - } - - const success = await copyToClipboard(codeBlocks.join('\n\n')) - if (success) { - addNotification({ - type: 'success', - title: 'Copied', - message: 'All code blocks copied to clipboard', - }) - } - }, [generateMutation.data, addNotification]) - - // Download markdown - const handleDownload = useCallback(() => { - if (!generateMutation.data?.markdown) return - - const filename = `aden-sdk-quickstart-${selectedFramework}-${selectedLanguage}.md` - downloadAsFile(generateMutation.data.markdown, filename) - }, [generateMutation.data, selectedFramework, selectedLanguage]) - - // Error state - if (optionsError) { - return ( - - - SDK Quickstart - - -
    -

    - Failed to load quickstart options -

    - -
    -
    -
    - ) - } - - // Loading state - if (optionsLoading) { - return ( - - - SDK Quickstart - - -
    -
    - - -
    - -
    -
    -
    - ) - } - - const markdown = generateMutation.data?.markdown - const tokenName = generateMutation.data?.metadata?.tokenName - const codeBlocks = markdown ? extractCodeBlocks(markdown) : [] - - return ( - - - SDK Quickstart - - - - {options && ( - - )} - - {/* Token info */} - {tokenName && ( -

    - Using API Key: {tokenName} -

    - )} - - {/* Generation error */} - {generateMutation.isError && ( -
    -

    Failed to generate documentation

    - -
    - )} - - {/* Loading overlay */} - {generateMutation.isPending && ( -
    - - - Generating documentation... - -
    - )} - - {/* Rendered markdown */} - {markdown && !generateMutation.isPending && ( - - )} -
    -
    - ) -} diff --git a/honeycomb/src/components/quickstart/index.ts b/honeycomb/src/components/quickstart/index.ts deleted file mode 100644 index 382a0631..00000000 --- a/honeycomb/src/components/quickstart/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { SDKQuickstart } from './SDKQuickstart' -export { CodeBlock } from './CodeBlock' -export { MarkdownRenderer } from './MarkdownRenderer' -export { QuickstartToolbar } from './QuickstartToolbar' -export { AgentStatusIndicator } from './AgentStatusIndicator' diff --git a/honeycomb/src/components/settings/ChangePasswordDialog.tsx b/honeycomb/src/components/settings/ChangePasswordDialog.tsx deleted file mode 100644 index 3114b7df..00000000 --- a/honeycomb/src/components/settings/ChangePasswordDialog.tsx +++ /dev/null @@ -1,160 +0,0 @@ -import { useState, useEffect } from 'react' -import { - Dialog, - DialogContent, - DialogHeader, - DialogTitle, - DialogFooter, -} from '@/components/ui/dialog' -import { Button } from '@/components/ui/button' -import { Input } from '@/components/ui/input' -import { useUpdatePassword } from '@/hooks/queries/useUser' -import { useNotificationStore } from '@/stores/notificationStore' - -interface ChangePasswordDialogProps { - open: boolean - onOpenChange: (open: boolean) => void -} - -interface FormErrors { - oldPassword?: string - newPassword?: string - confirmPassword?: string -} - -export function ChangePasswordDialog({ - open, - onOpenChange, -}: ChangePasswordDialogProps) { - const [oldPassword, setOldPassword] = useState('') - const [newPassword, setNewPassword] = useState('') - const [confirmPassword, setConfirmPassword] = useState('') - const [errors, setErrors] = useState({}) - - const updatePassword = useUpdatePassword() - const addNotification = useNotificationStore((s) => s.addNotification) - - // Reset form when dialog opens/closes - useEffect(() => { - if (open) { - setOldPassword('') - setNewPassword('') - setConfirmPassword('') - setErrors({}) - } - }, [open]) - - const validate = (): boolean => { - const newErrors: FormErrors = {} - - if (!oldPassword) { - newErrors.oldPassword = 'Please enter your old password' - } else if (oldPassword.length < 10) { - newErrors.oldPassword = 'Password must be at least 10 characters' - } - - if (!newPassword) { - newErrors.newPassword = 'Please enter your new password' - } else if (newPassword.length < 10) { - newErrors.newPassword = 'Password must be at least 10 characters' - } - - if (!confirmPassword) { - newErrors.confirmPassword = 'Please confirm your new password' - } else if (newPassword !== confirmPassword) { - newErrors.confirmPassword = "Passwords don't match" - } - - setErrors(newErrors) - return Object.keys(newErrors).length === 0 - } - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault() - - if (!validate()) return - - try { - await updatePassword.mutateAsync({ - oldPassword, - newPassword, - }) - addNotification({ - type: 'success', - title: 'Password updated', - message: 'Your password has been updated successfully.', - }) - onOpenChange(false) - } catch { - addNotification({ - type: 'error', - title: 'Update failed', - message: 'Failed to update password. Please check your old password.', - }) - } - } - - const handleClose = () => { - onOpenChange(false) - } - - return ( - - - - Change password - - -
    -
    - - setOldPassword(e.target.value)} - placeholder="Enter your current password" - /> - {errors.oldPassword && ( -

    {errors.oldPassword}

    - )} -
    - -
    - - setNewPassword(e.target.value)} - placeholder="Enter your new password" - /> - {errors.newPassword && ( -

    {errors.newPassword}

    - )} -
    - -
    - - setConfirmPassword(e.target.value)} - placeholder="Confirm your new password" - /> - {errors.confirmPassword && ( -

    {errors.confirmPassword}

    - )} -
    - - - - - -
    -
    -
    - ) -} diff --git a/honeycomb/src/components/settings/CreateAPIKeyDialog.tsx b/honeycomb/src/components/settings/CreateAPIKeyDialog.tsx deleted file mode 100644 index dfa5aff4..00000000 --- a/honeycomb/src/components/settings/CreateAPIKeyDialog.tsx +++ /dev/null @@ -1,165 +0,0 @@ -import { useState, useEffect } from 'react' -import { Copy, Check } from 'lucide-react' -import { - Dialog, - DialogContent, - DialogHeader, - DialogTitle, - DialogFooter, -} from '@/components/ui/dialog' -import { Button } from '@/components/ui/button' -import { Input } from '@/components/ui/input' -import { Textarea } from '@/components/ui/textarea' -import { useCreateAPIToken } from '@/hooks/queries/useUser' -import { useNotificationStore } from '@/stores/notificationStore' -import { isValidTokenLabel } from '@/lib/user' - -interface CreateAPIKeyDialogProps { - open: boolean - onOpenChange: (open: boolean) => void -} - -export function CreateAPIKeyDialog({ - open, - onOpenChange, -}: CreateAPIKeyDialogProps) { - const [tokenName, setTokenName] = useState('') - const [newToken, setNewToken] = useState('') - const [showToken, setShowToken] = useState(false) - const [error, setError] = useState('') - const [copied, setCopied] = useState(false) - - const createToken = useCreateAPIToken() - const addNotification = useNotificationStore((s) => s.addNotification) - - // Reset state when dialog opens/closes - useEffect(() => { - if (open) { - setTokenName('') - setNewToken('') - setShowToken(false) - setError('') - setCopied(false) - } - }, [open]) - - const handleCreate = async () => { - if (!tokenName.trim()) { - setError('Please enter a name for the API key') - return - } - - if (!isValidTokenLabel(tokenName)) { - setError('Please only use letters, numbers, and underscores') - return - } - - setError('') - - try { - const result = await createToken.mutateAsync(tokenName) - setNewToken(result.token) - setShowToken(true) - addNotification({ - type: 'success', - title: 'API key created', - message: 'Your new API key has been created successfully.', - }) - } catch { - addNotification({ - type: 'error', - title: 'Creation failed', - message: 'Failed to create API key. Please try again.', - }) - } - } - - const handleCopy = async () => { - try { - await navigator.clipboard.writeText(newToken) - setCopied(true) - setTimeout(() => setCopied(false), 2000) - } catch { - addNotification({ - type: 'error', - title: 'Copy failed', - message: 'Failed to copy to clipboard.', - }) - } - } - - const handleClose = () => { - onOpenChange(false) - } - - return ( - - - - Create an API Key - - -
    -

    - Please enter a name for the API key -

    - - setTokenName(e.target.value)} - placeholder="Enter letters, numbers, and underscores" - disabled={showToken} - onKeyDown={(e) => { - if (e.key === 'Enter' && !showToken) handleCreate() - }} - /> - - {error &&

    {error}

    } - - {!showToken && ( - - - - )} - - {showToken && ( -
    - -

    - Make sure to copy your API key now. You won't be able to see it again! -

    -
    -

    + English | + 简体中文 | + Español | + Português | + 日本語 | + Русский +