diff --git a/surfsense_backend/alembic/versions/98_add_user_id_to_llm_and_image_configs.py b/surfsense_backend/alembic/versions/98_add_user_id_to_llm_and_image_configs.py new file mode 100644 index 000000000..07a287231 --- /dev/null +++ b/surfsense_backend/alembic/versions/98_add_user_id_to_llm_and_image_configs.py @@ -0,0 +1,143 @@ +"""Add user_id to new_llm_configs and image_generation_configs + +Revision ID: 98 +Revises: 97 +""" + +from collections.abc import Sequence + +from alembic import op + +# revision identifiers, used by Alembic. +revision: str = "98" +down_revision: str | None = "97" +branch_labels: str | Sequence[str] | None = None +depends_on: str | Sequence[str] | None = None + + +def upgrade() -> None: + """Add user_id column to new_llm_configs and image_generation_configs. + + Backfills existing rows with the search space owner's user_id. + """ + # --- new_llm_configs --- + # 1. Add nullable column first + op.execute( + """ + ALTER TABLE new_llm_configs + ADD COLUMN IF NOT EXISTS user_id UUID; + """ + ) + + # 2. Backfill from search space owner + op.execute( + """ + UPDATE new_llm_configs nlc + SET user_id = ss.user_id + FROM searchspaces ss + WHERE nlc.search_space_id = ss.id + AND nlc.user_id IS NULL; + """ + ) + + # 3. Make NOT NULL + op.execute( + """ + ALTER TABLE new_llm_configs + ALTER COLUMN user_id SET NOT NULL; + """ + ) + + # 4. Add FK constraint + op.execute( + """ + DO $$ + BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.table_constraints + WHERE constraint_name = 'fk_new_llm_configs_user_id' + AND table_name = 'new_llm_configs' + ) THEN + ALTER TABLE new_llm_configs + ADD CONSTRAINT fk_new_llm_configs_user_id + FOREIGN KEY (user_id) REFERENCES "user"(id) ON DELETE CASCADE; + END IF; + END$$; + """ + ) + + # 5. Add index for user_id lookups + op.execute( + """ + CREATE INDEX IF NOT EXISTS ix_new_llm_configs_user_id + ON new_llm_configs (user_id); + """ + ) + + # --- image_generation_configs --- + # 1. Add nullable column first + op.execute( + """ + ALTER TABLE image_generation_configs + ADD COLUMN IF NOT EXISTS user_id UUID; + """ + ) + + # 2. Backfill from search space owner + op.execute( + """ + UPDATE image_generation_configs igc + SET user_id = ss.user_id + FROM searchspaces ss + WHERE igc.search_space_id = ss.id + AND igc.user_id IS NULL; + """ + ) + + # 3. Make NOT NULL + op.execute( + """ + ALTER TABLE image_generation_configs + ALTER COLUMN user_id SET NOT NULL; + """ + ) + + # 4. Add FK constraint + op.execute( + """ + DO $$ + BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.table_constraints + WHERE constraint_name = 'fk_image_generation_configs_user_id' + AND table_name = 'image_generation_configs' + ) THEN + ALTER TABLE image_generation_configs + ADD CONSTRAINT fk_image_generation_configs_user_id + FOREIGN KEY (user_id) REFERENCES "user"(id) ON DELETE CASCADE; + END IF; + END$$; + """ + ) + + # 5. Add index for user_id lookups + op.execute( + """ + CREATE INDEX IF NOT EXISTS ix_image_generation_configs_user_id + ON image_generation_configs (user_id); + """ + ) + + +def downgrade() -> None: + """Remove user_id from new_llm_configs and image_generation_configs.""" + op.execute( + """ + ALTER TABLE new_llm_configs DROP COLUMN IF EXISTS user_id; + """ + ) + op.execute( + """ + ALTER TABLE image_generation_configs DROP COLUMN IF EXISTS user_id; + """ + ) diff --git a/surfsense_backend/app/agents/new_chat/llm_config.py b/surfsense_backend/app/agents/new_chat/llm_config.py index 4ffc6e623..bf16b2fe9 100644 --- a/surfsense_backend/app/agents/new_chat/llm_config.py +++ b/surfsense_backend/app/agents/new_chat/llm_config.py @@ -109,7 +109,7 @@ class AgentConfig: use_default_system_instructions=True, citations_enabled=True, config_id=AUTO_MODE_ID, - config_name="Auto (Load Balanced)", + config_name="Auto (Fastest)", is_auto_mode=True, ) diff --git a/surfsense_backend/app/db.py b/surfsense_backend/app/db.py index d58145f23..90c839980 100644 --- a/surfsense_backend/app/db.py +++ b/surfsense_backend/app/db.py @@ -1066,6 +1066,12 @@ class ImageGenerationConfig(BaseModel, TimestampMixin): "SearchSpace", back_populates="image_generation_configs" ) + # User who created this config + user_id = Column( + UUID(as_uuid=True), ForeignKey("user.id", ondelete="CASCADE"), nullable=False + ) + user = relationship("User", back_populates="image_generation_configs") + class ImageGeneration(BaseModel, TimestampMixin): """ @@ -1284,6 +1290,7 @@ class SearchSourceConnector(BaseModel, TimestampMixin): user_id = Column( UUID(as_uuid=True), ForeignKey("user.id", ondelete="CASCADE"), nullable=False ) + user = relationship("User", back_populates="search_source_connectors") # Documents created by this connector (for cleanup on connector deletion) documents = relationship("Document", back_populates="connector") @@ -1340,6 +1347,12 @@ class NewLLMConfig(BaseModel, TimestampMixin): ) search_space = relationship("SearchSpace", back_populates="new_llm_configs") + # User who created this config + user_id = Column( + UUID(as_uuid=True), ForeignKey("user.id", ondelete="CASCADE"), nullable=False + ) + user = relationship("User", back_populates="new_llm_configs") + class Log(BaseModel, TimestampMixin): __tablename__ = "logs" @@ -1608,6 +1621,27 @@ if config.AUTH_TYPE == "GOOGLE": passive_deletes=True, ) + # Connectors created by this user + search_source_connectors = relationship( + "SearchSourceConnector", + back_populates="user", + passive_deletes=True, + ) + + # LLM configs created by this user + new_llm_configs = relationship( + "NewLLMConfig", + back_populates="user", + passive_deletes=True, + ) + + # Image generation configs created by this user + image_generation_configs = relationship( + "ImageGenerationConfig", + back_populates="user", + passive_deletes=True, + ) + # User memories for personalized AI responses memories = relationship( "UserMemory", @@ -1687,6 +1721,27 @@ else: passive_deletes=True, ) + # Connectors created by this user + search_source_connectors = relationship( + "SearchSourceConnector", + back_populates="user", + passive_deletes=True, + ) + + # LLM configs created by this user + new_llm_configs = relationship( + "NewLLMConfig", + back_populates="user", + passive_deletes=True, + ) + + # Image generation configs created by this user + image_generation_configs = relationship( + "ImageGenerationConfig", + back_populates="user", + passive_deletes=True, + ) + # User memories for personalized AI responses memories = relationship( "UserMemory", diff --git a/surfsense_backend/app/routes/image_generation_routes.py b/surfsense_backend/app/routes/image_generation_routes.py index 9406867c6..97a3559b9 100644 --- a/surfsense_backend/app/routes/image_generation_routes.py +++ b/surfsense_backend/app/routes/image_generation_routes.py @@ -69,7 +69,7 @@ def _get_global_image_gen_config(config_id: int) -> dict | None: if config_id == IMAGE_GEN_AUTO_MODE_ID: return { "id": IMAGE_GEN_AUTO_MODE_ID, - "name": "Auto (Load Balanced)", + "name": "Auto (Fastest)", "provider": "AUTO", "model_name": "auto", "is_auto_mode": True, @@ -215,7 +215,7 @@ async def get_global_image_gen_configs( safe_configs.append( { "id": 0, - "name": "Auto (Load Balanced)", + "name": "Auto (Fastest)", "description": "Automatically routes across available image generation providers.", "provider": "AUTO", "custom_provider": None, @@ -273,7 +273,7 @@ async def create_image_gen_config( "You don't have permission to create image generation configs in this search space", ) - db_config = ImageGenerationConfig(**config_data.model_dump()) + db_config = ImageGenerationConfig(**config_data.model_dump(), user_id=user.id) session.add(db_config) await session.commit() await session.refresh(db_config) diff --git a/surfsense_backend/app/routes/new_llm_config_routes.py b/surfsense_backend/app/routes/new_llm_config_routes.py index ed7d62d31..f784bd273 100644 --- a/surfsense_backend/app/routes/new_llm_config_routes.py +++ b/surfsense_backend/app/routes/new_llm_config_routes.py @@ -64,7 +64,7 @@ async def get_global_new_llm_configs( safe_configs.append( { "id": 0, - "name": "Auto (Load Balanced)", + "name": "Auto (Fastest)", "description": "Automatically routes requests across available LLM providers for optimal performance and rate limit handling. Recommended for most users.", "provider": "AUTO", "custom_provider": None, @@ -149,8 +149,8 @@ async def create_new_llm_config( detail=f"Invalid LLM configuration: {error_message}", ) - # Create the config - db_config = NewLLMConfig(**config_data.model_dump()) + # Create the config with user association + db_config = NewLLMConfig(**config_data.model_dump(), user_id=user.id) session.add(db_config) await session.commit() await session.refresh(db_config) diff --git a/surfsense_backend/app/routes/search_spaces_routes.py b/surfsense_backend/app/routes/search_spaces_routes.py index fd84c0f45..d115c31e2 100644 --- a/surfsense_backend/app/routes/search_spaces_routes.py +++ b/surfsense_backend/app/routes/search_spaces_routes.py @@ -324,7 +324,7 @@ async def _get_llm_config_by_id( if config_id == 0: return { "id": 0, - "name": "Auto (Load Balanced)", + "name": "Auto (Fastest)", "description": "Automatically routes requests across available LLM providers for optimal performance and rate limit handling", "provider": "AUTO", "custom_provider": None, @@ -402,7 +402,7 @@ async def _get_image_gen_config_by_id( if config_id == 0: return { "id": 0, - "name": "Auto (Load Balanced)", + "name": "Auto (Fastest)", "description": "Automatically routes requests across available image generation providers", "provider": "AUTO", "model_name": "auto", diff --git a/surfsense_backend/app/schemas/image_generation.py b/surfsense_backend/app/schemas/image_generation.py index 6ef4feff8..69f534e20 100644 --- a/surfsense_backend/app/schemas/image_generation.py +++ b/surfsense_backend/app/schemas/image_generation.py @@ -6,6 +6,7 @@ ImageGeneration: Schemas for the actual image generation requests/results. GlobalImageGenConfigRead: Schema for admin-configured YAML configs. """ +import uuid from datetime import datetime from typing import Any @@ -79,6 +80,7 @@ class ImageGenerationConfigRead(ImageGenerationConfigBase): id: int created_at: datetime search_space_id: int + user_id: uuid.UUID model_config = ConfigDict(from_attributes=True) @@ -97,6 +99,7 @@ class ImageGenerationConfigPublic(BaseModel): litellm_params: dict[str, Any] | None = None created_at: datetime search_space_id: int + user_id: uuid.UUID model_config = ConfigDict(from_attributes=True) diff --git a/surfsense_backend/app/schemas/new_chat.py b/surfsense_backend/app/schemas/new_chat.py index aa95e49e6..efa314979 100644 --- a/surfsense_backend/app/schemas/new_chat.py +++ b/surfsense_backend/app/schemas/new_chat.py @@ -233,6 +233,7 @@ class PublicChatSnapshotDetail(BaseModel): message_count: int thread_id: int thread_title: str + created_by_user_id: str | None = None class PublicChatSnapshotsBySpaceResponse(BaseModel): diff --git a/surfsense_backend/app/schemas/new_llm_config.py b/surfsense_backend/app/schemas/new_llm_config.py index a6294fba2..9863665b6 100644 --- a/surfsense_backend/app/schemas/new_llm_config.py +++ b/surfsense_backend/app/schemas/new_llm_config.py @@ -7,6 +7,7 @@ NewLLMConfig combines LLM model settings with prompt configuration: - Citation toggle """ +import uuid from datetime import datetime from typing import Any @@ -90,6 +91,7 @@ class NewLLMConfigRead(NewLLMConfigBase): id: int created_at: datetime search_space_id: int + user_id: uuid.UUID model_config = ConfigDict(from_attributes=True) @@ -118,6 +120,7 @@ class NewLLMConfigPublic(BaseModel): created_at: datetime search_space_id: int + user_id: uuid.UUID model_config = ConfigDict(from_attributes=True) diff --git a/surfsense_backend/app/services/llm_service.py b/surfsense_backend/app/services/llm_service.py index 0a805b31f..24bc4138b 100644 --- a/surfsense_backend/app/services/llm_service.py +++ b/surfsense_backend/app/services/llm_service.py @@ -41,7 +41,7 @@ def get_global_llm_config(llm_config_id: int) -> dict | None: if llm_config_id == AUTO_MODE_ID: return { "id": AUTO_MODE_ID, - "name": "Auto (Load Balanced)", + "name": "Auto (Fastest)", "description": "Automatically routes requests across available LLM providers for optimal performance and rate limit handling", "provider": "AUTO", "model_name": "auto", diff --git a/surfsense_backend/app/services/public_chat_service.py b/surfsense_backend/app/services/public_chat_service.py index 4da316240..ba2dd0079 100644 --- a/surfsense_backend/app/services/public_chat_service.py +++ b/surfsense_backend/app/services/public_chat_service.py @@ -439,6 +439,9 @@ async def list_snapshots_for_search_space( "message_count": len(s.message_ids) if s.message_ids else 0, "thread_id": s.thread_id, "thread_title": thread_titles.get(s.thread_id, "Untitled"), + "created_by_user_id": str(s.created_by_user_id) + if s.created_by_user_id + else None, } for s in snapshots ] diff --git a/surfsense_web/components/icons/providers/ai21.svg b/surfsense_web/components/icons/providers/ai21.svg new file mode 100644 index 000000000..b5e8bf4d1 --- /dev/null +++ b/surfsense_web/components/icons/providers/ai21.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/anthropic.svg b/surfsense_web/components/icons/providers/anthropic.svg new file mode 100644 index 000000000..35be6f954 --- /dev/null +++ b/surfsense_web/components/icons/providers/anthropic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/anyscale.svg b/surfsense_web/components/icons/providers/anyscale.svg new file mode 100644 index 000000000..3a551131e --- /dev/null +++ b/surfsense_web/components/icons/providers/anyscale.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/bedrock.svg b/surfsense_web/components/icons/providers/bedrock.svg new file mode 100644 index 000000000..195aa6594 --- /dev/null +++ b/surfsense_web/components/icons/providers/bedrock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/cerebras.svg b/surfsense_web/components/icons/providers/cerebras.svg new file mode 100644 index 000000000..92a9d5a2e --- /dev/null +++ b/surfsense_web/components/icons/providers/cerebras.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/cohere.svg b/surfsense_web/components/icons/providers/cohere.svg new file mode 100644 index 000000000..a3e3ecd6c --- /dev/null +++ b/surfsense_web/components/icons/providers/cohere.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/cometapi.svg b/surfsense_web/components/icons/providers/cometapi.svg new file mode 100644 index 000000000..9e59c1f56 --- /dev/null +++ b/surfsense_web/components/icons/providers/cometapi.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/dbrx.svg b/surfsense_web/components/icons/providers/dbrx.svg new file mode 100644 index 000000000..80c6c7ef7 --- /dev/null +++ b/surfsense_web/components/icons/providers/dbrx.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/deepinfra.svg b/surfsense_web/components/icons/providers/deepinfra.svg new file mode 100644 index 000000000..c4391ca86 --- /dev/null +++ b/surfsense_web/components/icons/providers/deepinfra.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/deepseek.svg b/surfsense_web/components/icons/providers/deepseek.svg new file mode 100644 index 000000000..518097be8 --- /dev/null +++ b/surfsense_web/components/icons/providers/deepseek.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/fireworksai.svg b/surfsense_web/components/icons/providers/fireworksai.svg new file mode 100644 index 000000000..9555f015b --- /dev/null +++ b/surfsense_web/components/icons/providers/fireworksai.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/gemini.svg b/surfsense_web/components/icons/providers/gemini.svg new file mode 100644 index 000000000..0f09f0613 --- /dev/null +++ b/surfsense_web/components/icons/providers/gemini.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/groq.svg b/surfsense_web/components/icons/providers/groq.svg new file mode 100644 index 000000000..bd5d4fe0a --- /dev/null +++ b/surfsense_web/components/icons/providers/groq.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/huggingface.svg b/surfsense_web/components/icons/providers/huggingface.svg new file mode 100644 index 000000000..6982b8942 --- /dev/null +++ b/surfsense_web/components/icons/providers/huggingface.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/index.ts b/surfsense_web/components/icons/providers/index.ts new file mode 100644 index 000000000..73c03a6cc --- /dev/null +++ b/surfsense_web/components/icons/providers/index.ts @@ -0,0 +1,31 @@ +export { default as Ai21Icon } from "./ai21.svg"; +export { default as AnthropicIcon } from "./anthropic.svg"; +export { default as AnyscaleIcon } from "./anyscale.svg"; +export { default as BedrockIcon } from "./bedrock.svg"; +export { default as CerebrasIcon } from "./cerebras.svg"; +export { default as CloudflareIcon } from "./workersai-cloudflare.svg"; +export { default as CohereIcon } from "./cohere.svg"; +export { default as CometApiIcon } from "./cometapi.svg"; +export { default as DatabricksIcon } from "./dbrx.svg"; +export { default as DeepInfraIcon } from "./deepinfra.svg"; +export { default as DeepSeekIcon } from "./deepseek.svg"; +export { default as FireworksAiIcon } from "./fireworksai.svg"; +export { default as GeminiIcon } from "./gemini.svg"; +export { default as GroqIcon } from "./groq.svg"; +export { default as HuggingFaceIcon } from "./huggingface.svg"; +export { default as MistralIcon } from "./mistral.svg"; +export { default as MoonshotIcon } from "./moonshot.svg"; +export { default as NscaleIcon } from "./nscale.svg"; +export { default as OllamaIcon } from "./ollama.svg"; +export { default as OpenaiIcon } from "./openai.svg"; +export { default as OpenRouterIcon } from "./openrouter.svg"; +export { default as PerplexityIcon } from "./perplexity.svg"; +export { default as QwenIcon } from "./qwen.svg"; +export { default as RecraftIcon } from "./recraft.svg"; +export { default as ReplicateIcon } from "./replicate.svg"; +export { default as SambaNovaIcon } from "./sambanova.svg"; +export { default as TogetherAiIcon } from "./togetherai.svg"; +export { default as VertexAiIcon } from "./vertexai.svg"; +export { default as XaiIcon } from "./xai.svg"; +export { default as XinferenceIcon } from "./xinference.svg"; +export { default as ZhipuIcon } from "./zhipu.svg"; diff --git a/surfsense_web/components/icons/providers/mistral.svg b/surfsense_web/components/icons/providers/mistral.svg new file mode 100644 index 000000000..8719b0952 --- /dev/null +++ b/surfsense_web/components/icons/providers/mistral.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/moonshot.svg b/surfsense_web/components/icons/providers/moonshot.svg new file mode 100644 index 000000000..79c885069 --- /dev/null +++ b/surfsense_web/components/icons/providers/moonshot.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/nscale.svg b/surfsense_web/components/icons/providers/nscale.svg new file mode 100644 index 000000000..cfac91523 --- /dev/null +++ b/surfsense_web/components/icons/providers/nscale.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/surfsense_web/components/icons/providers/ollama.svg b/surfsense_web/components/icons/providers/ollama.svg new file mode 100644 index 000000000..abd5a67db --- /dev/null +++ b/surfsense_web/components/icons/providers/ollama.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/openai.svg b/surfsense_web/components/icons/providers/openai.svg new file mode 100644 index 000000000..6d10e2cef --- /dev/null +++ b/surfsense_web/components/icons/providers/openai.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/openrouter.svg b/surfsense_web/components/icons/providers/openrouter.svg new file mode 100644 index 000000000..4a5d19753 --- /dev/null +++ b/surfsense_web/components/icons/providers/openrouter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/perplexity.svg b/surfsense_web/components/icons/providers/perplexity.svg new file mode 100644 index 000000000..8e38646da --- /dev/null +++ b/surfsense_web/components/icons/providers/perplexity.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/qwen.svg b/surfsense_web/components/icons/providers/qwen.svg new file mode 100644 index 000000000..dd128325e --- /dev/null +++ b/surfsense_web/components/icons/providers/qwen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/recraft.svg b/surfsense_web/components/icons/providers/recraft.svg new file mode 100644 index 000000000..6860900c1 --- /dev/null +++ b/surfsense_web/components/icons/providers/recraft.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/replicate.svg b/surfsense_web/components/icons/providers/replicate.svg new file mode 100644 index 000000000..80c67741a --- /dev/null +++ b/surfsense_web/components/icons/providers/replicate.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/sambanova.svg b/surfsense_web/components/icons/providers/sambanova.svg new file mode 100644 index 000000000..46b6270fc --- /dev/null +++ b/surfsense_web/components/icons/providers/sambanova.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/togetherai.svg b/surfsense_web/components/icons/providers/togetherai.svg new file mode 100644 index 000000000..1c6441d69 --- /dev/null +++ b/surfsense_web/components/icons/providers/togetherai.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/vertexai.svg b/surfsense_web/components/icons/providers/vertexai.svg new file mode 100644 index 000000000..45adce83b --- /dev/null +++ b/surfsense_web/components/icons/providers/vertexai.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/workersai-cloudflare.svg b/surfsense_web/components/icons/providers/workersai-cloudflare.svg new file mode 100644 index 000000000..4894b1918 --- /dev/null +++ b/surfsense_web/components/icons/providers/workersai-cloudflare.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/xai.svg b/surfsense_web/components/icons/providers/xai.svg new file mode 100644 index 000000000..dee9b47e3 --- /dev/null +++ b/surfsense_web/components/icons/providers/xai.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/xinference.svg b/surfsense_web/components/icons/providers/xinference.svg new file mode 100644 index 000000000..deec84ca1 --- /dev/null +++ b/surfsense_web/components/icons/providers/xinference.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/icons/providers/zhipu.svg b/surfsense_web/components/icons/providers/zhipu.svg new file mode 100644 index 000000000..3d89b0ed9 --- /dev/null +++ b/surfsense_web/components/icons/providers/zhipu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/surfsense_web/components/layout/ui/sidebar/MobileSidebar.tsx b/surfsense_web/components/layout/ui/sidebar/MobileSidebar.tsx index 377bf65f5..567236498 100644 --- a/surfsense_web/components/layout/ui/sidebar/MobileSidebar.tsx +++ b/surfsense_web/components/layout/ui/sidebar/MobileSidebar.tsx @@ -113,10 +113,6 @@ export function MobileSidebar({ isShared={space.memberCount > 1} isOwner={space.isOwner} onClick={() => handleSearchSpaceSelect(space.id)} - onDelete={onSearchSpaceDelete ? () => onSearchSpaceDelete(space) : undefined} - onSettings={ - onSearchSpaceSettings ? () => onSearchSpaceSettings(space) : undefined - } size="md" disableTooltip /> diff --git a/surfsense_web/components/new-chat/chat-header.tsx b/surfsense_web/components/new-chat/chat-header.tsx index 8a8fa11a0..2f1d9d845 100644 --- a/surfsense_web/components/new-chat/chat-header.tsx +++ b/surfsense_web/components/new-chat/chat-header.tsx @@ -8,7 +8,6 @@ import type { NewLLMConfigPublic, } from "@/contracts/types/new-llm-config.types"; import { ImageConfigSidebar } from "./image-config-sidebar"; -import { ImageModelSelector } from "./image-model-selector"; import { ModelConfigSidebar } from "./model-config-sidebar"; import { ModelSelector } from "./model-selector"; @@ -34,7 +33,7 @@ export function ChatHeader({ searchSpaceId }: ChatHeaderProps) { const [imageSidebarMode, setImageSidebarMode] = useState<"create" | "edit" | "view">("view"); // LLM handlers - const handleEditConfig = useCallback( + const handleEditLLMConfig = useCallback( (config: NewLLMConfigPublic | GlobalNewLLMConfig, global: boolean) => { setSelectedConfig(config); setIsGlobal(global); @@ -44,7 +43,7 @@ export function ChatHeader({ searchSpaceId }: ChatHeaderProps) { [] ); - const handleAddNew = useCallback(() => { + const handleAddNewLLM = useCallback(() => { setSelectedConfig(null); setIsGlobal(false); setSidebarMode("create"); @@ -81,8 +80,12 @@ export function ChatHeader({ searchSpaceId }: ChatHeaderProps) { return (
- - + { if (mode === "create") return "Add Image Model"; - if (isAutoMode) return "Auto Mode (Load Balanced)"; + if (isAutoMode) return "Auto Mode (Fastest)"; if (isGlobal) return "View Global Image Model"; return "Edit Image Model"; }; diff --git a/surfsense_web/components/new-chat/image-model-selector.tsx b/surfsense_web/components/new-chat/image-model-selector.tsx deleted file mode 100644 index 05a8a1456..000000000 --- a/surfsense_web/components/new-chat/image-model-selector.tsx +++ /dev/null @@ -1,361 +0,0 @@ -"use client"; - -import { useAtomValue } from "jotai"; -import { - Check, - ChevronDown, - ChevronRight, - Edit3, - Globe, - ImageIcon, - Plus, - Shuffle, - User, -} from "lucide-react"; -import { useCallback, useMemo, useState } from "react"; -import { toast } from "sonner"; -import { - createImageGenConfigMutationAtom, - updateImageGenConfigMutationAtom, -} from "@/atoms/image-gen-config/image-gen-config-mutation.atoms"; -import { - globalImageGenConfigsAtom, - imageGenConfigsAtom, -} from "@/atoms/image-gen-config/image-gen-config-query.atoms"; -import { updateLLMPreferencesMutationAtom } from "@/atoms/new-llm-config/new-llm-config-mutation.atoms"; -import { llmPreferencesAtom } from "@/atoms/new-llm-config/new-llm-config-query.atoms"; -import { activeSearchSpaceIdAtom } from "@/atoms/search-spaces/search-space-query.atoms"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; -import { - Command, - CommandEmpty, - CommandGroup, - CommandInput, - CommandItem, - CommandList, - CommandSeparator, -} from "@/components/ui/command"; -import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; -import { Spinner } from "@/components/ui/spinner"; -import type { - GlobalImageGenConfig, - ImageGenerationConfig, -} from "@/contracts/types/new-llm-config.types"; -import { cn } from "@/lib/utils"; - -interface ImageModelSelectorProps { - className?: string; - onAddNew?: () => void; - onEdit?: (config: ImageGenerationConfig | GlobalImageGenConfig, isGlobal: boolean) => void; -} - -export function ImageModelSelector({ className, onAddNew, onEdit }: ImageModelSelectorProps) { - const [open, setOpen] = useState(false); - const [searchQuery, setSearchQuery] = useState(""); - - const { data: globalConfigs, isLoading: globalLoading } = useAtomValue(globalImageGenConfigsAtom); - const { data: userConfigs, isLoading: userLoading } = useAtomValue(imageGenConfigsAtom); - const { data: preferences, isLoading: prefsLoading } = useAtomValue(llmPreferencesAtom); - const searchSpaceId = useAtomValue(activeSearchSpaceIdAtom); - const { mutateAsync: updatePreferences } = useAtomValue(updateLLMPreferencesMutationAtom); - - const isLoading = globalLoading || userLoading || prefsLoading; - - const currentConfig = useMemo(() => { - if (!preferences) return null; - const id = preferences.image_generation_config_id; - if (id === null || id === undefined) return null; - const globalMatch = globalConfigs?.find((c) => c.id === id); - if (globalMatch) return globalMatch; - return userConfigs?.find((c) => c.id === id) ?? null; - }, [preferences, globalConfigs, userConfigs]); - - const isCurrentAutoMode = useMemo(() => { - return currentConfig && "is_auto_mode" in currentConfig && currentConfig.is_auto_mode; - }, [currentConfig]); - - const filteredGlobal = useMemo(() => { - if (!globalConfigs) return []; - if (!searchQuery) return globalConfigs; - const q = searchQuery.toLowerCase(); - return globalConfigs.filter( - (c) => - c.name.toLowerCase().includes(q) || - c.model_name.toLowerCase().includes(q) || - c.provider.toLowerCase().includes(q) - ); - }, [globalConfigs, searchQuery]); - - const filteredUser = useMemo(() => { - if (!userConfigs) return []; - if (!searchQuery) return userConfigs; - const q = searchQuery.toLowerCase(); - return userConfigs.filter( - (c) => - c.name.toLowerCase().includes(q) || - c.model_name.toLowerCase().includes(q) || - c.provider.toLowerCase().includes(q) - ); - }, [userConfigs, searchQuery]); - - const totalModels = (globalConfigs?.length ?? 0) + (userConfigs?.length ?? 0); - - const handleSelect = useCallback( - async (configId: number) => { - if (currentConfig?.id === configId) { - setOpen(false); - return; - } - if (!searchSpaceId) { - toast.error("No search space selected"); - return; - } - try { - await updatePreferences({ - search_space_id: Number(searchSpaceId), - data: { image_generation_config_id: configId }, - }); - toast.success("Image model updated"); - setOpen(false); - } catch { - toast.error("Failed to switch image model"); - } - }, - [currentConfig, searchSpaceId, updatePreferences] - ); - - // Don't render if no configs at all - if (!isLoading && totalModels === 0) { - return ( - - ); - } - - return ( - - - - - - - - {totalModels > 3 && ( -
- -
- )} - - -
- -

No image models found

-
-
- - {/* Global Image Gen Configs */} - {filteredGlobal.length > 0 && ( - -
- - Global Image Models -
- {filteredGlobal.map((config) => { - const isSelected = currentConfig?.id === config.id; - const isAuto = "is_auto_mode" in config && config.is_auto_mode; - return ( - handleSelect(config.id)} - className={cn( - "mx-2 rounded-lg mb-1 cursor-pointer group transition-all hover:bg-accent/50", - isSelected && "bg-accent/80", - isAuto && "border border-violet-200 dark:border-violet-800/50" - )} - > -
-
- {isAuto ? ( - - ) : ( - - )} -
-
-
- {config.name} - {isAuto && ( - - Recommended - - )} - {isSelected && } -
- - {isAuto ? "Auto load balancing" : config.model_name} - -
- {onEdit && ( - { - e.stopPropagation(); - setOpen(false); - onEdit(config, true); - }} - /> - )} -
-
- ); - })} -
- )} - - {/* User Image Gen Configs */} - {filteredUser.length > 0 && ( - <> - {filteredGlobal.length > 0 && } - -
- - Your Image Models -
- {filteredUser.map((config) => { - const isSelected = currentConfig?.id === config.id; - return ( - handleSelect(config.id)} - className={cn( - "mx-2 rounded-lg mb-1 cursor-pointer group transition-all hover:bg-accent/50", - isSelected && "bg-accent/80" - )} - > -
-
- -
-
-
- {config.name} - {isSelected && } -
- - {config.model_name} - -
- {onEdit && ( - - )} -
-
- ); - })} -
- - )} - - {/* Add New */} - {onAddNew && ( -
- -
- )} -
-
-
-
- ); -} diff --git a/surfsense_web/components/new-chat/model-config-sidebar.tsx b/surfsense_web/components/new-chat/model-config-sidebar.tsx index 3e731c164..90fb95c88 100644 --- a/surfsense_web/components/new-chat/model-config-sidebar.tsx +++ b/surfsense_web/components/new-chat/model-config-sidebar.tsx @@ -68,7 +68,7 @@ export function ModelConfigSidebar({ // Get title based on mode const getTitle = () => { if (mode === "create") return "Add New Configuration"; - if (isAutoMode) return "Auto Mode (Load Balanced)"; + if (isAutoMode) return "Auto Mode (Fastest)"; if (isGlobal) return "View Global Configuration"; return "Edit Configuration"; }; @@ -307,7 +307,7 @@ export function ModelConfigSidebar({

- Automatic Load Balancing + Automatic (Fastest)

Distributes requests across all configured LLM providers diff --git a/surfsense_web/components/new-chat/model-selector.tsx b/surfsense_web/components/new-chat/model-selector.tsx index ec1143e04..98911fe38 100644 --- a/surfsense_web/components/new-chat/model-selector.tsx +++ b/surfsense_web/components/new-chat/model-selector.tsx @@ -1,22 +1,13 @@ "use client"; import { useAtomValue } from "jotai"; -import { - Bot, - Check, - ChevronDown, - Cloud, - Edit3, - Globe, - Plus, - Settings2, - Shuffle, - Sparkles, - User, - Zap, -} from "lucide-react"; +import { Bot, Check, ChevronDown, Edit3, ImageIcon, Plus, Zap } from "lucide-react"; import { useCallback, useMemo, useState } from "react"; import { toast } from "sonner"; +import { + globalImageGenConfigsAtom, + imageGenConfigsAtom, +} from "@/atoms/image-gen-config/image-gen-config-query.atoms"; import { updateLLMPreferencesMutationAtom } from "@/atoms/new-llm-config/new-llm-config-mutation.atoms"; import { globalNewLLMConfigsAtom, @@ -37,128 +28,152 @@ import { } from "@/components/ui/command"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Spinner } from "@/components/ui/spinner"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import type { + GlobalImageGenConfig, GlobalNewLLMConfig, + ImageGenerationConfig, NewLLMConfigPublic, } from "@/contracts/types/new-llm-config.types"; +import { getProviderIcon } from "@/lib/provider-icons"; import { cn } from "@/lib/utils"; -// Provider icons mapping -const getProviderIcon = (provider: string, isAutoMode?: boolean) => { - const iconClass = "size-4"; - - // Special icon for Auto mode - if (isAutoMode || provider?.toUpperCase() === "AUTO") { - return ; - } - - switch (provider?.toUpperCase()) { - case "OPENAI": - return ; - case "ANTHROPIC": - return ; - case "GOOGLE": - return ; - case "GROQ": - return ; - case "OLLAMA": - return ; - case "XAI": - return ; - default: - return ; - } -}; - interface ModelSelectorProps { - onEdit: (config: NewLLMConfigPublic | GlobalNewLLMConfig, isGlobal: boolean) => void; - onAddNew: () => void; + onEditLLM: (config: NewLLMConfigPublic | GlobalNewLLMConfig, isGlobal: boolean) => void; + onAddNewLLM: () => void; + onEditImage?: (config: ImageGenerationConfig | GlobalImageGenConfig, isGlobal: boolean) => void; + onAddNewImage?: () => void; className?: string; } -export function ModelSelector({ onEdit, onAddNew, className }: ModelSelectorProps) { +export function ModelSelector({ + onEditLLM, + onAddNewLLM, + onEditImage, + onAddNewImage, + className, +}: ModelSelectorProps) { const [open, setOpen] = useState(false); - const [searchQuery, setSearchQuery] = useState(""); + const [activeTab, setActiveTab] = useState<"llm" | "image">("llm"); + const [llmSearchQuery, setLlmSearchQuery] = useState(""); + const [imageSearchQuery, setImageSearchQuery] = useState(""); - // Fetch configs - const { data: userConfigs, isLoading: userConfigsLoading } = useAtomValue(newLLMConfigsAtom); - const { data: globalConfigs, isLoading: globalConfigsLoading } = + // LLM data + const { data: llmUserConfigs, isLoading: llmUserLoading } = useAtomValue(newLLMConfigsAtom); + const { data: llmGlobalConfigs, isLoading: llmGlobalLoading } = useAtomValue(globalNewLLMConfigsAtom); - const { data: preferences, isLoading: preferencesLoading } = useAtomValue(llmPreferencesAtom); + const { data: preferences, isLoading: prefsLoading } = useAtomValue(llmPreferencesAtom); const searchSpaceId = useAtomValue(activeSearchSpaceIdAtom); const { mutateAsync: updatePreferences } = useAtomValue(updateLLMPreferencesMutationAtom); - const isLoading = userConfigsLoading || globalConfigsLoading || preferencesLoading; + // Image data + const { data: imageGlobalConfigs, isLoading: imageGlobalLoading } = + useAtomValue(globalImageGenConfigsAtom); + const { data: imageUserConfigs, isLoading: imageUserLoading } = useAtomValue(imageGenConfigsAtom); - // Get current agent LLM config - const currentConfig = useMemo(() => { + const isLoading = + llmUserLoading || llmGlobalLoading || prefsLoading || imageGlobalLoading || imageUserLoading; + + // ─── LLM current config ─── + const currentLLMConfig = useMemo(() => { if (!preferences) return null; - const agentLlmId = preferences.agent_llm_id; if (agentLlmId === null || agentLlmId === undefined) return null; - - // Check if it's Auto mode (ID 0) or global config (negative ID) if (agentLlmId <= 0) { - return globalConfigs?.find((c) => c.id === agentLlmId) ?? null; + return llmGlobalConfigs?.find((c) => c.id === agentLlmId) ?? null; } - // Otherwise, check user configs - return userConfigs?.find((c) => c.id === agentLlmId) ?? null; - }, [preferences, globalConfigs, userConfigs]); + return llmUserConfigs?.find((c) => c.id === agentLlmId) ?? null; + }, [preferences, llmGlobalConfigs, llmUserConfigs]); - // Check if current config is Auto mode - const isCurrentAutoMode = useMemo(() => { - return currentConfig && "is_auto_mode" in currentConfig && currentConfig.is_auto_mode; - }, [currentConfig]); + const isLLMAutoMode = useMemo(() => { + return currentLLMConfig && "is_auto_mode" in currentLLMConfig && currentLLMConfig.is_auto_mode; + }, [currentLLMConfig]); - // Filter configs based on search - const filteredGlobalConfigs = useMemo(() => { - if (!globalConfigs) return []; - if (!searchQuery) return globalConfigs; - const query = searchQuery.toLowerCase(); - return globalConfigs.filter( - (c) => - c.name.toLowerCase().includes(query) || - c.model_name.toLowerCase().includes(query) || - c.provider.toLowerCase().includes(query) + // ─── Image current config ─── + const currentImageConfig = useMemo(() => { + if (!preferences) return null; + const id = preferences.image_generation_config_id; + if (id === null || id === undefined) return null; + const globalMatch = imageGlobalConfigs?.find((c) => c.id === id); + if (globalMatch) return globalMatch; + return imageUserConfigs?.find((c) => c.id === id) ?? null; + }, [preferences, imageGlobalConfigs, imageUserConfigs]); + + const isImageAutoMode = useMemo(() => { + return ( + currentImageConfig && "is_auto_mode" in currentImageConfig && currentImageConfig.is_auto_mode ); - }, [globalConfigs, searchQuery]); + }, [currentImageConfig]); - const filteredUserConfigs = useMemo(() => { - if (!userConfigs) return []; - if (!searchQuery) return userConfigs; - const query = searchQuery.toLowerCase(); - return userConfigs.filter( + // ─── LLM filtering ─── + const filteredLLMGlobal = useMemo(() => { + if (!llmGlobalConfigs) return []; + if (!llmSearchQuery) return llmGlobalConfigs; + const q = llmSearchQuery.toLowerCase(); + return llmGlobalConfigs.filter( (c) => - c.name.toLowerCase().includes(query) || - c.model_name.toLowerCase().includes(query) || - c.provider.toLowerCase().includes(query) + c.name.toLowerCase().includes(q) || + c.model_name.toLowerCase().includes(q) || + c.provider.toLowerCase().includes(q) ); - }, [userConfigs, searchQuery]); + }, [llmGlobalConfigs, llmSearchQuery]); - // Total model count for conditional search display - const totalModels = useMemo(() => { - return (globalConfigs?.length ?? 0) + (userConfigs?.length ?? 0); - }, [globalConfigs, userConfigs]); + const filteredLLMUser = useMemo(() => { + if (!llmUserConfigs) return []; + if (!llmSearchQuery) return llmUserConfigs; + const q = llmSearchQuery.toLowerCase(); + return llmUserConfigs.filter( + (c) => + c.name.toLowerCase().includes(q) || + c.model_name.toLowerCase().includes(q) || + c.provider.toLowerCase().includes(q) + ); + }, [llmUserConfigs, llmSearchQuery]); - const handleSelectConfig = useCallback( + const totalLLMModels = (llmGlobalConfigs?.length ?? 0) + (llmUserConfigs?.length ?? 0); + + // ─── Image filtering ─── + const filteredImageGlobal = useMemo(() => { + if (!imageGlobalConfigs) return []; + if (!imageSearchQuery) return imageGlobalConfigs; + const q = imageSearchQuery.toLowerCase(); + return imageGlobalConfigs.filter( + (c) => + c.name.toLowerCase().includes(q) || + c.model_name.toLowerCase().includes(q) || + c.provider.toLowerCase().includes(q) + ); + }, [imageGlobalConfigs, imageSearchQuery]); + + const filteredImageUser = useMemo(() => { + if (!imageUserConfigs) return []; + if (!imageSearchQuery) return imageUserConfigs; + const q = imageSearchQuery.toLowerCase(); + return imageUserConfigs.filter( + (c) => + c.name.toLowerCase().includes(q) || + c.model_name.toLowerCase().includes(q) || + c.provider.toLowerCase().includes(q) + ); + }, [imageUserConfigs, imageSearchQuery]); + + const totalImageModels = (imageGlobalConfigs?.length ?? 0) + (imageUserConfigs?.length ?? 0); + + // ─── Handlers ─── + const handleSelectLLM = useCallback( async (config: NewLLMConfigPublic | GlobalNewLLMConfig) => { - // If already selected, just close - if (currentConfig?.id === config.id) { + if (currentLLMConfig?.id === config.id) { setOpen(false); return; } - if (!searchSpaceId) { toast.error("No search space selected"); return; } - try { await updatePreferences({ search_space_id: Number(searchSpaceId), - data: { - agent_llm_id: config.id, - }, + data: { agent_llm_id: config.id }, }); toast.success(`Switched to ${config.name}`); setOpen(false); @@ -167,16 +182,40 @@ export function ModelSelector({ onEdit, onAddNew, className }: ModelSelectorProp toast.error("Failed to switch model"); } }, - [currentConfig, searchSpaceId, updatePreferences] + [currentLLMConfig, searchSpaceId, updatePreferences] ); - const handleEditConfig = useCallback( + const handleEditLLMConfig = useCallback( (e: React.MouseEvent, config: NewLLMConfigPublic | GlobalNewLLMConfig, isGlobal: boolean) => { e.stopPropagation(); - onEdit(config, isGlobal); + onEditLLM(config, isGlobal); setOpen(false); }, - [onEdit] + [onEditLLM] + ); + + const handleSelectImage = useCallback( + async (configId: number) => { + if (currentImageConfig?.id === configId) { + setOpen(false); + return; + } + if (!searchSpaceId) { + toast.error("No search space selected"); + return; + } + try { + await updatePreferences({ + search_space_id: Number(searchSpaceId), + data: { image_generation_config_id: configId }, + }); + toast.success("Image model updated"); + setOpen(false); + } catch { + toast.error("Failed to switch image model"); + } + }, + [currentImageConfig, searchSpaceId, updatePreferences] ); return ( @@ -194,30 +233,41 @@ export function ModelSelector({ onEdit, onAddNew, className }: ModelSelectorProp Loading - ) : currentConfig ? ( - <> - {getProviderIcon(currentConfig.provider, isCurrentAutoMode ?? false)} - - {currentConfig.name} - - {isCurrentAutoMode ? ( - - Balanced - - ) : ( - - {currentConfig.model_name.split("/").pop()?.slice(0, 10) || - currentConfig.model_name.slice(0, 10)} - - )} - ) : ( <> - - Select Model + {/* LLM section */} + {currentLLMConfig ? ( + <> + {getProviderIcon(currentLLMConfig.provider, { + isAutoMode: isLLMAutoMode ?? false, + })} + + {currentLLMConfig.name} + + + ) : ( + <> + + Select Model + + )} + + {/* Divider */} +

+ + {/* Image section */} + {currentImageConfig ? ( + <> + {getProviderIcon(currentImageConfig.provider, { + isAutoMode: isImageAutoMode ?? false, + })} + + {currentImageConfig.name} + + + ) : ( + + )} )} - setActiveTab(v as "llm" | "image")} + className="w-full" > - {totalModels > 3 && ( -
- -
- )} - - - -
- -

No models found

-

Try a different search term

-
-
- - {/* Global Configs Section */} - {filteredGlobalConfigs.length > 0 && ( - -
- - Global Models -
- {filteredGlobalConfigs.map((config) => { - const isSelected = currentConfig?.id === config.id; - const isAutoMode = "is_auto_mode" in config && config.is_auto_mode; - return ( - handleSelectConfig(config)} - className={cn( - "mx-2 rounded-lg mb-1 cursor-pointer group transition-all", - "hover:bg-accent/50", - isSelected && "bg-accent/80", - isAutoMode && "border border-violet-200 dark:border-violet-800/50" - )} - > -
-
-
- {getProviderIcon(config.provider, isAutoMode)} -
-
-
- {config.name} - {isAutoMode && ( - - Recommended - - )} - {isSelected && } -
-
- - {isAutoMode ? "Auto load balancing" : config.model_name} - - {!isAutoMode && config.citations_enabled && ( - - Citations - - )} -
-
-
- {!isAutoMode && ( - - )} -
-
- ); - })} -
- )} - - {filteredGlobalConfigs.length > 0 && filteredUserConfigs.length > 0 && ( - - )} - - {/* User Configs Section */} - {filteredUserConfigs.length > 0 && ( - -
- - Your Configurations -
- {filteredUserConfigs.map((config) => { - const isSelected = currentConfig?.id === config.id; - return ( - handleSelectConfig(config)} - className={cn( - "mx-2 rounded-lg mb-1 cursor-pointer group transition-all", - "hover:bg-accent/50", - isSelected && "bg-accent/80" - )} - > -
-
-
{getProviderIcon(config.provider)}
-
-
- {config.name} - {isSelected && } -
-
- - {config.model_name} - - {config.citations_enabled && ( - - Citations - - )} -
-
-
- -
-
- ); - })} -
- )} - - {/* Add New Config Button */} -
- -
-
-
+ + LLM + + + + Image + + +
+ + {/* ─── LLM Tab ─── */} + + + {totalLLMModels > 3 && ( +
+ +
+ )} + + + +
+ +

No models found

+

Try a different search term

+
+
+ + {/* Global LLM Configs */} + {filteredLLMGlobal.length > 0 && ( + +
+ Global Models +
+ {filteredLLMGlobal.map((config) => { + const isSelected = currentLLMConfig?.id === config.id; + const isAutoMode = "is_auto_mode" in config && config.is_auto_mode; + return ( + handleSelectLLM(config)} + className={cn( + "mx-2 rounded-lg mb-1 cursor-pointer group transition-all", + "hover:bg-accent/50", + isSelected && "bg-accent/80", + isAutoMode && "border border-violet-800" + )} + > +
+
+
+ {getProviderIcon(config.provider, { isAutoMode })} +
+
+
+ {config.name} + {isAutoMode && ( + + Recommended + + )} + {isSelected && ( + + )} +
+
+ + {isAutoMode ? "Auto Mode" : config.model_name} + + {!isAutoMode && config.citations_enabled && ( + + Citations + + )} +
+
+
+ {!isAutoMode && ( + + )} +
+
+ ); + })} +
+ )} + + {filteredLLMGlobal.length > 0 && filteredLLMUser.length > 0 && ( + + )} + + {/* User LLM Configs */} + {filteredLLMUser.length > 0 && ( + +
+ Your Configurations +
+ {filteredLLMUser.map((config) => { + const isSelected = currentLLMConfig?.id === config.id; + return ( + handleSelectLLM(config)} + className={cn( + "mx-2 rounded-lg mb-1 cursor-pointer group transition-all", + "hover:bg-accent/50", + isSelected && "bg-accent/80" + )} + > +
+
+
{getProviderIcon(config.provider)}
+
+
+ {config.name} + {isSelected && ( + + )} +
+
+ + {config.model_name} + + {config.citations_enabled && ( + + Citations + + )} +
+
+
+ +
+
+ ); + })} +
+ )} + + {/* Add New LLM Config */} +
+ +
+
+
+
+ + {/* ─── Image Tab ─── */} + + + {totalImageModels > 3 && ( +
+ +
+ )} + + +
+ +

No image models found

+
+
+ + {/* Global Image Configs */} + {filteredImageGlobal.length > 0 && ( + +
+ Global Image Models +
+ {filteredImageGlobal.map((config) => { + const isSelected = currentImageConfig?.id === config.id; + const isAuto = "is_auto_mode" in config && config.is_auto_mode; + return ( + handleSelectImage(config.id)} + className={cn( + "mx-2 rounded-lg mb-1 cursor-pointer group transition-all hover:bg-accent/50", + isSelected && "bg-accent/80", + isAuto && "border border-violet-800" + )} + > +
+
+ {getProviderIcon(config.provider, { isAutoMode: isAuto })} +
+
+
+ {config.name} + {isAuto && ( + + Recommended + + )} + {isSelected && } +
+ + {isAuto ? "Auto Mode" : config.model_name} + +
+ {onEditImage && !isAuto && ( + + )} +
+
+ ); + })} +
+ )} + + {/* User Image Configs */} + {filteredImageUser.length > 0 && ( + <> + {filteredImageGlobal.length > 0 && ( + + )} + +
+ Your Image Models +
+ {filteredImageUser.map((config) => { + const isSelected = currentImageConfig?.id === config.id; + return ( + handleSelectImage(config.id)} + className={cn( + "mx-2 rounded-lg mb-1 cursor-pointer group transition-all hover:bg-accent/50", + isSelected && "bg-accent/80" + )} + > +
+
{getProviderIcon(config.provider)}
+
+
+ {config.name} + {isSelected && ( + + )} +
+ + {config.model_name} + +
+ {onEditImage && ( + + )} +
+
+ ); + })} +
+ + )} + + {/* Add New Image Config */} + {onAddNewImage && ( +
+ +
+ )} +
+
+
+ ); diff --git a/surfsense_web/components/public-chat-snapshots/public-chat-snapshot-row.tsx b/surfsense_web/components/public-chat-snapshots/public-chat-snapshot-row.tsx index 5f0048100..568c52ded 100644 --- a/surfsense_web/components/public-chat-snapshots/public-chat-snapshot-row.tsx +++ b/surfsense_web/components/public-chat-snapshots/public-chat-snapshot-row.tsx @@ -1,15 +1,29 @@ "use client"; -import { Copy, MessageSquare, Trash2 } from "lucide-react"; +import { Check, Copy, ExternalLink, MessageSquare, Trash2 } from "lucide-react"; +import Image from "next/image"; +import { useCallback, useRef, useState } from "react"; +import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; +import { Card, CardContent } from "@/components/ui/card"; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; import type { PublicChatSnapshotDetail } from "@/contracts/types/chat-threads.types"; +function getInitials(name: string): string { + const parts = name.trim().split(/\s+/); + if (parts.length >= 2) { + return (parts[0][0] + parts[1][0]).toUpperCase(); + } + return name.slice(0, 2).toUpperCase(); +} + interface PublicChatSnapshotRowProps { snapshot: PublicChatSnapshotDetail; canDelete: boolean; onCopy: (snapshot: PublicChatSnapshotDetail) => void; onDelete: (snapshot: PublicChatSnapshotDetail) => void; isDeleting?: boolean; + memberMap: Map; } export function PublicChatSnapshotRow({ @@ -18,57 +32,155 @@ export function PublicChatSnapshotRow({ onCopy, onDelete, isDeleting = false, + memberMap, }: PublicChatSnapshotRowProps) { + const [copied, setCopied] = useState(false); + const copyTimeoutRef = useRef>(); + + const handleCopyClick = useCallback(() => { + onCopy(snapshot); + setCopied(true); + clearTimeout(copyTimeoutRef.current); + copyTimeoutRef.current = setTimeout(() => setCopied(false), 2000); + }, [onCopy, snapshot]); + const formattedDate = new Date(snapshot.created_at).toLocaleDateString(undefined, { year: "numeric", month: "short", day: "numeric", }); + const member = snapshot.created_by_user_id ? memberMap.get(snapshot.created_by_user_id) : null; + return ( -
-
-

- {snapshot.thread_title} -

-
- {formattedDate} - - - {snapshot.message_count} - + + + {/* Header: Title + Actions */} +
+
+

+ {snapshot.thread_title} +

+
+
+ + + + + + Open link + + + {canDelete && ( + + + + + + Delete + + + )} +
- (e.target as HTMLInputElement).select()} - /> -
-
- - {canDelete && ( - - )} -
-
+ + {snapshot.message_count} messages + +
+ + {/* Public URL – selectable fallback for manual copy */} +
+

+ {snapshot.public_url} +

+ + + + + + {copied ? "Copied!" : "Copy link"} + + +
+ + {/* Footer: Date + Creator */} +
+ {formattedDate} + {member && ( + <> + · + + + +
+ {member.avatarUrl ? ( + {member.name} + ) : ( +
+ + {getInitials(member.name)} + +
+ )} + + {member.name} + +
+
+ {member.email || member.name} +
+
+ + )} +
+ + ); } diff --git a/surfsense_web/components/public-chat-snapshots/public-chat-snapshots-list.tsx b/surfsense_web/components/public-chat-snapshots/public-chat-snapshots-list.tsx index 38c435059..7a07c62ee 100644 --- a/surfsense_web/components/public-chat-snapshots/public-chat-snapshots-list.tsx +++ b/surfsense_web/components/public-chat-snapshots/public-chat-snapshots-list.tsx @@ -10,6 +10,7 @@ interface PublicChatSnapshotsListProps { onCopy: (snapshot: PublicChatSnapshotDetail) => void; onDelete: (snapshot: PublicChatSnapshotDetail) => void; deletingId?: number; + memberMap: Map; } export function PublicChatSnapshotsList({ @@ -18,13 +19,14 @@ export function PublicChatSnapshotsList({ onCopy, onDelete, deletingId, + memberMap, }: PublicChatSnapshotsListProps) { if (snapshots.length === 0) { return ; } return ( -
+
{snapshots.map((snapshot) => ( ))}
diff --git a/surfsense_web/components/public-chat-snapshots/public-chat-snapshots-manager.tsx b/surfsense_web/components/public-chat-snapshots/public-chat-snapshots-manager.tsx index 167443f66..24d801409 100644 --- a/surfsense_web/components/public-chat-snapshots/public-chat-snapshots-manager.tsx +++ b/surfsense_web/components/public-chat-snapshots/public-chat-snapshots-manager.tsx @@ -1,14 +1,14 @@ "use client"; import { useAtomValue } from "jotai"; -import { AlertCircle, Globe, Info } from "lucide-react"; +import { AlertCircle, Info } from "lucide-react"; import { useCallback, useMemo, useState } from "react"; import { toast } from "sonner"; -import { myAccessAtom } from "@/atoms/members/members-query.atoms"; +import { membersAtom, myAccessAtom } from "@/atoms/members/members-query.atoms"; import { deletePublicChatSnapshotMutationAtom } from "@/atoms/public-chat-snapshots/public-chat-snapshots-mutation.atoms"; import { publicChatSnapshotsAtom } from "@/atoms/public-chat-snapshots/public-chat-snapshots-query.atoms"; import { Alert, AlertDescription } from "@/components/ui/alert"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Card, CardContent } from "@/components/ui/card"; import { Skeleton } from "@/components/ui/skeleton"; import type { PublicChatSnapshotDetail } from "@/contracts/types/chat-threads.types"; import { PublicChatSnapshotsList } from "./public-chat-snapshots-list"; @@ -25,6 +25,22 @@ export function PublicChatSnapshotsManager({ // Data fetching const { data: snapshotsData, isLoading, isError } = useAtomValue(publicChatSnapshotsAtom); + // Members for user resolution + const { data: members } = useAtomValue(membersAtom); + const memberMap = useMemo(() => { + const map = new Map(); + if (members) { + for (const m of members) { + map.set(m.user_id, { + name: m.user_display_name || m.user_email || "Unknown", + email: m.user_email || undefined, + avatarUrl: m.user_avatar_url || undefined, + }); + } + } + return map; + }, [members]); + // Permissions const { data: access } = useAtomValue(myAccessAtom); const canView = useMemo(() => { @@ -46,7 +62,6 @@ export function PublicChatSnapshotsManager({ const handleCopy = useCallback((snapshot: PublicChatSnapshotDetail) => { const publicUrl = `${window.location.origin}/public/${snapshot.share_token}`; navigator.clipboard.writeText(publicUrl); - toast.success("Link copied to clipboard"); }, []); const handleDelete = useCallback( @@ -69,16 +84,35 @@ export function PublicChatSnapshotsManager({ // Loading state if (isLoading) { return ( -
- - - - - - - - - +
+ {/* Info alert skeleton */} + + + {/* Cards grid skeleton */} +
+ {["skeleton-a", "skeleton-b", "skeleton-c"].map((key) => ( + + + {/* Header: Title */} +
+ +
+ {/* Message count badge */} +
+ +
+ {/* URL skeleton */} + + {/* Footer: Date + Creator */} +
+ + + +
+
+
+ ))} +
); } @@ -110,35 +144,23 @@ export function PublicChatSnapshotsManager({ const snapshots = snapshotsData?.snapshots ?? []; return ( -
- - +
+ + Public chat links allow anyone with the URL to view a snapshot of a chat. These links do not update when the original chat changes. - - - - - Public Chat Links - - - Manage public links to chats in this search space. - - - - - - +
); } diff --git a/surfsense_web/components/settings/general-settings-manager.tsx b/surfsense_web/components/settings/general-settings-manager.tsx index 64d9ed876..bd22e9180 100644 --- a/surfsense_web/components/settings/general-settings-manager.tsx +++ b/surfsense_web/components/settings/general-settings-manager.tsx @@ -108,7 +108,7 @@ export function GeneralSettingsManager({ searchSpaceId }: GeneralSettingsManager return (
- + Update your search space name and description. These details help identify and organize diff --git a/surfsense_web/components/settings/image-model-manager.tsx b/surfsense_web/components/settings/image-model-manager.tsx index 017bb5a79..80828f825 100644 --- a/surfsense_web/components/settings/image-model-manager.tsx +++ b/surfsense_web/components/settings/image-model-manager.tsx @@ -5,20 +5,19 @@ import { AlertCircle, Check, ChevronsUpDown, - Clock, Edit3, - ImageIcon, Key, Plus, RefreshCw, - Shuffle, - Sparkles, + Info, Trash2, Wand2, } from "lucide-react"; import { AnimatePresence, motion } from "motion/react"; -import { useCallback, useEffect, useState } from "react"; +import Image from "next/image"; +import { useCallback, useMemo, useState } from "react"; import { toast } from "sonner"; +import { membersAtom, myAccessAtom } from "@/atoms/members/members-query.atoms"; import { createImageGenConfigMutationAtom, deleteImageGenConfigMutationAtom, @@ -29,7 +28,6 @@ import { imageGenConfigsAtom, } from "@/atoms/image-gen-config/image-gen-config-query.atoms"; import { updateLLMPreferencesMutationAtom } from "@/atoms/new-llm-config/new-llm-config-mutation.atoms"; -import { llmPreferencesAtom } from "@/atoms/new-llm-config/new-llm-config-query.atoms"; import { Alert, AlertDescription } from "@/components/ui/alert"; import { AlertDialog, @@ -41,9 +39,8 @@ import { AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; -import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Card, CardContent } from "@/components/ui/card"; import { Command, CommandEmpty, @@ -70,6 +67,7 @@ import { SelectValue, } from "@/components/ui/select"; import { Separator } from "@/components/ui/separator"; +import { Skeleton } from "@/components/ui/skeleton"; import { Spinner } from "@/components/ui/spinner"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; import { @@ -78,6 +76,7 @@ import { } from "@/contracts/enums/image-gen-providers"; import type { ImageGenerationConfig } from "@/contracts/types/new-llm-config.types"; import { cn } from "@/lib/utils"; +import { getProviderIcon } from "@/lib/provider-icons"; interface ImageModelManagerProps { searchSpaceId: number; @@ -93,6 +92,14 @@ const item = { show: { opacity: 1, y: 0 }, }; +function getInitials(name: string): string { + const parts = name.trim().split(/\s+/); + if (parts.length >= 2) { + return (parts[0][0] + parts[1][0]).toUpperCase(); + } + return name.slice(0, 2).toUpperCase(); +} + export function ImageModelManager({ searchSpaceId }: ImageModelManagerProps) { // Image gen config atoms const { @@ -120,27 +127,46 @@ export function ImageModelManager({ searchSpaceId }: ImageModelManagerProps) { } = useAtomValue(imageGenConfigsAtom); const { data: globalConfigs = [], isFetching: globalLoading } = useAtomValue(globalImageGenConfigsAtom); - const { data: preferences = {}, isFetching: prefsLoading } = useAtomValue(llmPreferencesAtom); + + // Members for user resolution + const { data: members } = useAtomValue(membersAtom); + const memberMap = useMemo(() => { + const map = new Map(); + if (members) { + for (const m of members) { + map.set(m.user_id, { + name: m.user_display_name || m.user_email || "Unknown", + email: m.user_email || undefined, + avatarUrl: m.user_avatar_url || undefined, + }); + } + } + return map; + }, [members]); + + // Permissions + const { data: access } = useAtomValue(myAccessAtom); + const canCreate = useMemo(() => { + if (!access) return false; + if (access.is_owner) return true; + return access.permissions?.includes("image_generations:create") ?? false; + }, [access]); + const canDelete = useMemo(() => { + if (!access) return false; + if (access.is_owner) return true; + return access.permissions?.includes("image_generations:delete") ?? false; + }, [access]); + // Backend uses image_generations:create for update as well + const canUpdate = canCreate; + const isReadOnly = !canCreate && !canDelete; // Local state const [isDialogOpen, setIsDialogOpen] = useState(false); const [editingConfig, setEditingConfig] = useState(null); const [configToDelete, setConfigToDelete] = useState(null); - // Preference state - const [selectedPrefId, setSelectedPrefId] = useState( - preferences.image_generation_config_id ?? "" - ); - const [hasPrefChanges, setHasPrefChanges] = useState(false); - const [isSavingPref, setIsSavingPref] = useState(false); - - useEffect(() => { - setSelectedPrefId(preferences.image_generation_config_id ?? ""); - setHasPrefChanges(false); - }, [preferences]); - const isSubmitting = isCreating || isUpdating; - const isLoading = configsLoading || globalLoading || prefsLoading; + const isLoading = configsLoading || globalLoading; const errors = [createError, updateError, deleteError, fetchError].filter(Boolean) as Error[]; // Form state for create/edit dialog @@ -248,40 +274,6 @@ export function ImageModelManager({ searchSpaceId }: ImageModelManagerProps) { setIsDialogOpen(true); }; - const handlePrefChange = (value: string) => { - const newVal = value === "unassigned" ? "" : parseInt(value); - setSelectedPrefId(newVal); - setHasPrefChanges(newVal !== (preferences.image_generation_config_id ?? "")); - }; - - const handleSavePref = async () => { - setIsSavingPref(true); - try { - await updatePreferences({ - search_space_id: searchSpaceId, - data: { - image_generation_config_id: - typeof selectedPrefId === "string" - ? selectedPrefId - ? parseInt(selectedPrefId) - : undefined - : selectedPrefId, - }, - }); - setHasPrefChanges(false); - toast.success("Image generation model preference saved!"); - } catch { - toast.error("Failed to save preference"); - } finally { - setIsSavingPref(false); - } - }; - - const allConfigs = [ - ...globalConfigs.map((c) => ({ ...c, _source: "global" as const })), - ...(userConfigs ?? []).map((c) => ({ ...c, _source: "user" as const })), - ]; - const selectedProvider = IMAGE_GEN_PROVIDERS.find((p) => p.value === formData.provider); const suggestedModels = getImageGenModelsByProvider(formData.provider); @@ -299,6 +291,14 @@ export function ImageModelManager({ searchSpaceId }: ImageModelManagerProps) { Refresh + {canCreate && ( + + )}
{/* Errors */} @@ -318,11 +318,39 @@ export function ImageModelManager({ searchSpaceId }: ImageModelManagerProps) { ))} + {/* Read-only / Limited permissions notice */} + {access && !isLoading && isReadOnly && ( + + + + + You have read-only access to image generation + configurations. Contact a space owner to request additional permissions. + + + + )} + {access && !isLoading && !isReadOnly && (!canCreate || !canDelete) && ( + + + + + You can{" "} + {[canCreate && "create and edit", canDelete && "delete"] + .filter(Boolean) + .join(" and ")}{" "} + image model configurations + {!canDelete && ", but cannot delete them"}. + + + + )} + {/* Global info */} {globalConfigs.filter((g) => !("is_auto_mode" in g && g.is_auto_mode)).length > 0 && ( - - - + + + {globalConfigs.filter((g) => !("is_auto_mode" in g && g.is_auto_mode)).length} global image model(s) @@ -332,139 +360,50 @@ export function ImageModelManager({ searchSpaceId }: ImageModelManagerProps) { )} - {/* Active Preference Card */} - {!isLoading && allConfigs.length > 0 && ( - - - -
-
- -
-
- Active Image Model - - Select which model to use for image generation - -
-
-
- - - {hasPrefChanges && ( -
- - -
- )} -
-
-
- )} - - {/* Loading */} + {/* Loading Skeleton */} {isLoading && ( - - - - - +
+ {/* Your Image Models Section Skeleton */} +
+
+ + +
+ + {/* Cards Grid Skeleton */} +
+ {["skeleton-a", "skeleton-b", "skeleton-c"].map((key) => ( + + + {/* Header */} +
+
+ + +
+
+ {/* Provider + Model */} +
+ + +
+ {/* Footer */} +
+ + + +
+
+
+ ))} +
+
+
)} {/* User Configs */} {!isLoading && (
-
-

Your Image Models

- -
- {(userConfigs?.length ?? 0) === 0 ? ( @@ -473,99 +412,151 @@ export function ImageModelManager({ searchSpaceId }: ImageModelManagerProps) {

No Image Models Yet

- Add your own image generation model (DALL-E 3, GPT Image 1, etc.) + {canCreate + ? "Add your own image generation model (DALL-E 3, GPT Image 1, etc.)" + : "No image models have been added to this space yet. Contact a space owner to add one."}

- + {canCreate && ( + + )} ) : ( - + - {userConfigs?.map((config) => ( - - - -
-
-
-
-
-
- -
-
-
-

- {config.name} -

- - {config.provider} - -
- - {config.model_name} - - {config.description && ( -

- {config.description} -

- )} -
- - {new Date(config.created_at).toLocaleDateString()} -
-
-
-
- - - - - - Edit - - - - - - - - Delete - - -
+ {userConfigs?.map((config) => { + const member = config.user_id ? memberMap.get(config.user_id) : null; + + return ( + + + + {/* Header: Name + Actions */} +
+
+

+ {config.name} +

+ {config.description && ( +

+ {config.description} +

+ )}
+ {(canUpdate || canDelete) && ( +
+ {canUpdate && ( + + + + + + Edit + + + )} + {canDelete && ( + + + + + + Delete + + + )} +
+ )}
-
- - - - ))} + + {/* Provider + Model */} +
+ {getProviderIcon(config.provider, { className: "size-3.5 shrink-0" })} + + {config.model_name} + +
+ + {/* Footer: Date + Creator */} +
+ + {new Date(config.created_at).toLocaleDateString(undefined, { + year: "numeric", + month: "short", + day: "numeric", + })} + + {member && ( + <> + · + + + +
+ {member.avatarUrl ? ( + {member.name} + ) : ( +
+ + {getInitials(member.name)} + +
+ )} + + {member.name} + +
+
+ + {member.email || member.name} + +
+
+ + )} +
+ + + + ); + })} )} @@ -583,16 +574,12 @@ export function ImageModelManager({ searchSpaceId }: ImageModelManagerProps) { } }} > - + e.preventDefault()} + > - - {editingConfig ? ( - - ) : ( - - )} - {editingConfig ? "Edit Image Model" : "Add Image Model"} - + {editingConfig ? "Edit Image Model" : "Add Image Model"} {editingConfig ? "Update your image generation model" diff --git a/surfsense_web/components/settings/llm-role-manager.tsx b/surfsense_web/components/settings/llm-role-manager.tsx index dac68a358..8c6fbf4cf 100644 --- a/surfsense_web/components/settings/llm-role-manager.tsx +++ b/surfsense_web/components/settings/llm-role-manager.tsx @@ -5,15 +5,21 @@ import { AlertCircle, Bot, CheckCircle, + CircleDashed, FileText, + ImageIcon, RefreshCw, RotateCcw, Save, Shuffle, } from "lucide-react"; -import { motion } from "motion/react"; +import { AnimatePresence, motion } from "motion/react"; import { useEffect, useState } from "react"; import { toast } from "sonner"; +import { + globalImageGenConfigsAtom, + imageGenConfigsAtom, +} from "@/atoms/image-gen-config/image-gen-config-query.atoms"; import { updateLLMPreferencesMutationAtom } from "@/atoms/new-llm-config/new-llm-config-mutation.atoms"; import { globalNewLLMConfigsAtom, @@ -23,34 +29,48 @@ import { import { Alert, AlertDescription } from "@/components/ui/alert"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Card, CardContent } from "@/components/ui/card"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, + SelectGroup, SelectItem, + SelectLabel, SelectTrigger, SelectValue, } from "@/components/ui/select"; -import { Spinner } from "@/components/ui/spinner"; +import { Skeleton } from "@/components/ui/skeleton"; import { cn } from "@/lib/utils"; +import { getProviderIcon } from "@/lib/provider-icons"; const ROLE_DESCRIPTIONS = { agent: { icon: Bot, title: "Agent LLM", description: "Primary LLM for chat interactions and agent operations", - color: "bg-blue-100 text-blue-800 border-blue-200", - examples: "Chat responses, agent tasks, real-time interactions", - characteristics: ["Fast responses", "Conversational", "Agent operations"], + color: "text-blue-600 dark:text-blue-400", + bgColor: "bg-blue-500/10", + prefKey: "agent_llm_id" as const, + configType: "llm" as const, }, document_summary: { icon: FileText, title: "Document Summary LLM", - description: "Handles document summarization", - color: "bg-purple-100 text-purple-800 border-purple-200", - examples: "Document analysis, podcasts, research synthesis", - characteristics: ["Large context window", "Deep reasoning", "Summarization"], + description: "Handles document summarization and research synthesis", + color: "text-purple-600 dark:text-purple-400", + bgColor: "bg-purple-500/10", + prefKey: "document_summary_llm_id" as const, + configType: "llm" as const, + }, + image_generation: { + icon: ImageIcon, + title: "Image Generation Model", + description: "Model used for AI image generation (DALL-E, GPT Image, etc.)", + color: "text-teal-600 dark:text-teal-400", + bgColor: "bg-teal-500/10", + prefKey: "image_generation_config_id" as const, + configType: "image" as const, }, }; @@ -59,7 +79,7 @@ interface LLMRoleManagerProps { } export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) { - // Use new LLM config system + // LLM configs const { data: newLLMConfigs = [], isFetching: configsLoading, @@ -70,8 +90,21 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) { data: globalConfigs = [], isFetching: globalConfigsLoading, error: globalConfigsError, - refetch: refreshGlobalConfigs, } = useAtomValue(globalNewLLMConfigsAtom); + + // Image gen configs + const { + data: userImageConfigs = [], + isFetching: imageConfigsLoading, + error: imageConfigsError, + } = useAtomValue(imageGenConfigsAtom); + const { + data: globalImageConfigs = [], + isFetching: globalImageConfigsLoading, + error: globalImageConfigsError, + } = useAtomValue(globalImageGenConfigsAtom); + + // Preferences const { data: preferences = {}, isFetching: preferencesLoading, @@ -83,6 +116,7 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) { const [assignments, setAssignments] = useState({ agent_llm_id: preferences.agent_llm_id ?? "", document_summary_llm_id: preferences.document_summary_llm_id ?? "", + image_generation_config_id: preferences.image_generation_config_id ?? "", }); const [hasChanges, setHasChanges] = useState(false); @@ -92,23 +126,24 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) { const newAssignments = { agent_llm_id: preferences.agent_llm_id ?? "", document_summary_llm_id: preferences.document_summary_llm_id ?? "", + image_generation_config_id: preferences.image_generation_config_id ?? "", }; setAssignments(newAssignments); setHasChanges(false); }, [preferences]); - const handleRoleAssignment = (role: string, configId: string) => { + const handleRoleAssignment = (prefKey: string, configId: string) => { const newAssignments = { ...assignments, - [role]: configId === "unassigned" ? "" : parseInt(configId), + [prefKey]: configId === "unassigned" ? "" : parseInt(configId), }; setAssignments(newAssignments); - // Check if there are changes compared to current preferences const currentPrefs = { agent_llm_id: preferences.agent_llm_id ?? "", document_summary_llm_id: preferences.document_summary_llm_id ?? "", + image_generation_config_id: preferences.image_generation_config_id ?? "", }; const hasChangesNow = Object.keys(newAssignments).some( @@ -123,19 +158,13 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) { const handleSave = async () => { setIsSaving(true); + const toNumericOrUndefined = (val: string | number) => + typeof val === "string" ? (val ? parseInt(val) : undefined) : val; + const numericAssignments = { - agent_llm_id: - typeof assignments.agent_llm_id === "string" - ? assignments.agent_llm_id - ? parseInt(assignments.agent_llm_id) - : undefined - : assignments.agent_llm_id, - document_summary_llm_id: - typeof assignments.document_summary_llm_id === "string" - ? assignments.document_summary_llm_id - ? parseInt(assignments.document_summary_llm_id) - : undefined - : assignments.document_summary_llm_id, + agent_llm_id: toNumericOrUndefined(assignments.agent_llm_id), + document_summary_llm_id: toNumericOrUndefined(assignments.document_summary_llm_id), + image_generation_config_id: toNumericOrUndefined(assignments.image_generation_config_id), }; await updatePreferences({ @@ -144,7 +173,7 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) { }); setHasChanges(false); - toast.success("LLM role assignments saved successfully!"); + toast.success("Role assignments saved successfully!"); setIsSaving(false); }; @@ -153,6 +182,7 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) { setAssignments({ agent_llm_id: preferences.agent_llm_id ?? "", document_summary_llm_id: preferences.document_summary_llm_id ?? "", + image_generation_config_id: preferences.image_generation_config_id ?? "", }); setHasChanges(false); }; @@ -163,327 +193,396 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) { assignments.agent_llm_id !== undefined && assignments.document_summary_llm_id !== "" && assignments.document_summary_llm_id !== null && - assignments.document_summary_llm_id !== undefined; + assignments.document_summary_llm_id !== undefined && + assignments.image_generation_config_id !== "" && + assignments.image_generation_config_id !== null && + assignments.image_generation_config_id !== undefined; - // Combine global and custom configs (new system) - const allConfigs = [ + // Combine global and custom LLM configs + const allLLMConfigs = [ ...globalConfigs.map((config) => ({ ...config, is_global: true })), ...newLLMConfigs.filter((config) => config.id && config.id.toString().trim() !== ""), ]; - const availableConfigs = allConfigs; + // Combine global and custom image gen configs + const allImageConfigs = [ + ...globalImageConfigs.map((config) => ({ ...config, is_global: true })), + ...(userImageConfigs ?? []).filter((config) => config.id && config.id.toString().trim() !== ""), + ]; - const isLoading = configsLoading || preferencesLoading || globalConfigsLoading; - const hasError = configsError || preferencesError || globalConfigsError; + const isLoading = + configsLoading || + preferencesLoading || + globalConfigsLoading || + imageConfigsLoading || + globalImageConfigsLoading; + const hasError = + configsError || + preferencesError || + globalConfigsError || + imageConfigsError || + globalImageConfigsError; + const hasAnyConfigs = allLLMConfigs.length > 0 || allImageConfigs.length > 0; return ( -
- {/* Header */} -
-
- + {isAssignmentComplete && !isLoading && !hasError && ( + refreshConfigs()} - disabled={isLoading} - className="flex items-center gap-2 text-xs md:text-sm h-8 md:h-9" + className="text-xs gap-1.5 border-emerald-500/30 text-emerald-700 dark:text-emerald-300 bg-emerald-500/5" > - - Refresh Configs - Configs - -
+ + All roles assigned + + )}
{/* Error Alert */} - {hasError && ( + + {hasError && ( + + + + + {(configsError?.message ?? "Failed to load LLM configurations") || + (preferencesError?.message ?? "Failed to load preferences") || + (globalConfigsError?.message ?? "Failed to load global configurations")} + + + + )} + + + {/* Loading Skeleton */} + {isLoading && ( +
+ {["skeleton-a", "skeleton-b", "skeleton-c"].map((key) => ( + + + {/* Header: icon + title + status */} +
+
+ +
+ + +
+
+ +
+ {/* Label */} +
+ + +
+ {/* Summary block */} +
+
+ + +
+
+ + +
+
+
+
+ ))} +
+ )} + + {/* No configs warning */} + {!isLoading && !hasError && !hasAnyConfigs && ( - {(configsError?.message ?? "Failed to load LLM configurations") || - (preferencesError?.message ?? "Failed to load preferences") || - (globalConfigsError?.message ?? "Failed to load global configurations")} + No configurations found. Please add at least one LLM provider or image model in the + respective settings tabs before assigning roles. )} - {/* Loading State */} - {isLoading && ( - - -
- - - {configsLoading && preferencesLoading - ? "Loading configurations and preferences..." - : configsLoading - ? "Loading configurations..." - : "Loading preferences..."} - -
-
-
- )} + {/* Role Assignment Cards */} + {!isLoading && !hasError && hasAnyConfigs && ( + + {Object.entries(ROLE_DESCRIPTIONS).map(([key, role], index) => { + const IconComponent = role.icon; + const isImageRole = role.configType === "image"; + const currentAssignment = assignments[role.prefKey as keyof typeof assignments]; - {/* Info Alert */} - {!isLoading && !hasError && ( -
- {availableConfigs.length === 0 ? ( - - - - No LLM configurations found. Please add at least one LLM provider in the Agent - Configs tab before assigning roles. - - - ) : !isAssignmentComplete ? ( - - - - Complete all role assignments to enable full functionality. Each role serves - different purposes in your workflow. - - - ) : ( - - - - All roles are assigned and ready to use! Your LLM configuration is complete. - - - )} + // Pick the right config lists based on role type + const roleGlobalConfigs = isImageRole ? globalImageConfigs : globalConfigs; + const roleUserConfigs = isImageRole + ? (userImageConfigs ?? []).filter((c) => c.id && c.id.toString().trim() !== "") + : newLLMConfigs.filter((c) => c.id && c.id.toString().trim() !== ""); + const roleAllConfigs = isImageRole ? allImageConfigs : allLLMConfigs; - {/* Role Assignment Cards */} - {availableConfigs.length > 0 && ( -
- {Object.entries(ROLE_DESCRIPTIONS).map(([key, role]) => { - const IconComponent = role.icon; - const currentAssignment = assignments[`${key}_llm_id` as keyof typeof assignments]; - const assignedConfig = availableConfigs.find( - (config) => config.id === currentAssignment - ); + const assignedConfig = roleAllConfigs.find((config) => config.id === currentAssignment); + const isAssigned = + currentAssignment !== "" && + currentAssignment !== null && + currentAssignment !== undefined; + const isAutoMode = + assignedConfig && "is_auto_mode" in assignedConfig && assignedConfig.is_auto_mode; - return ( - - - -
-
-
- -
-
- {role.title} - - {role.description} - + return ( + + + + {/* Role Header */} +
+
+
+ +
+
+

{role.title}

+

+ {role.description} +

+
+
+ {isAssigned ? ( + + ) : ( + + )} +
+ + {/* Selector */} +
+ + +
+ + {/* Assigned Config Summary */} + {assignedConfig && ( +
+ {isAutoMode ? ( +
+ +
+

+ Auto Mode +

+

+ Routes across all available providers +

- {currentAssignment && ( - - )} -
- - -
- - -
- - {assignedConfig && ( -
-
- {"is_auto_mode" in assignedConfig && assignedConfig.is_auto_mode ? ( - - ) : ( - - )} - Assigned: - {"is_auto_mode" in assignedConfig && assignedConfig.is_auto_mode ? ( - - AUTO - - ) : ( - - {assignedConfig.provider} - - )} - {assignedConfig.name} - {"is_auto_mode" in assignedConfig && assignedConfig.is_auto_mode ? ( - - Recommended - - ) : ( - "is_global" in assignedConfig && - assignedConfig.is_global && ( - + ) : ( +
+ +
+
+ {assignedConfig.name} + {"is_global" in assignedConfig && assignedConfig.is_global && ( + 🌐 Global - ) + )} +
+
+ {getProviderIcon(assignedConfig.provider, { + className: "size-3 shrink-0", + })} + + {assignedConfig.model_name} + +
+ {assignedConfig.api_base && ( +

+ {assignedConfig.api_base} +

)}
- {"is_auto_mode" in assignedConfig && assignedConfig.is_auto_mode ? ( -
- Automatically load balances across all available LLM providers -
- ) : ( - <> -
- Model: {assignedConfig.model_name} -
- {assignedConfig.api_base && ( -
- Base: {assignedConfig.api_base} -
- )} - - )}
)} - - - - ); - })} -
- )} +
+ )} +
+
+
+ ); + })} + + )} - {/* Action Buttons */} - {hasChanges && ( -
- + {/* Save / Reset Bar */} + + {hasChanges && ( + +

You have unsaved changes

+
+
- )} -
- )} + + )} +
); } diff --git a/surfsense_web/components/settings/model-config-manager.tsx b/surfsense_web/components/settings/model-config-manager.tsx index bdd951349..7f228ff56 100644 --- a/surfsense_web/components/settings/model-config-manager.tsx +++ b/surfsense_web/components/settings/model-config-manager.tsx @@ -3,19 +3,19 @@ import { useAtomValue } from "jotai"; import { AlertCircle, - Bot, - Clock, Edit3, FileText, MessageSquareQuote, Plus, RefreshCw, - Sparkles, + Info, Trash2, Wand2, } from "lucide-react"; import { AnimatePresence, motion } from "motion/react"; -import { useCallback, useState } from "react"; +import Image from "next/image"; +import { useCallback, useMemo, useState } from "react"; +import { membersAtom, myAccessAtom } from "@/atoms/members/members-query.atoms"; import { createNewLLMConfigMutationAtom, deleteNewLLMConfigMutationAtom, @@ -47,10 +47,12 @@ import { DialogHeader, DialogTitle, } from "@/components/ui/dialog"; +import { Skeleton } from "@/components/ui/skeleton"; import { Spinner } from "@/components/ui/spinner"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; import type { NewLLMConfig } from "@/contracts/types/new-llm-config.types"; import { cn } from "@/lib/utils"; +import { getProviderIcon } from "@/lib/provider-icons"; interface ModelConfigManagerProps { searchSpaceId: number; @@ -71,23 +73,25 @@ const item = { show: { opacity: 1, y: 0 }, }; +function getInitials(name: string): string { + const parts = name.trim().split(/\s+/); + if (parts.length >= 2) { + return (parts[0][0] + parts[1][0]).toUpperCase(); + } + return name.slice(0, 2).toUpperCase(); +} + export function ModelConfigManager({ searchSpaceId }: ModelConfigManagerProps) { // Mutations - const { - mutateAsync: createConfig, - isPending: isCreating, - error: createError, - } = useAtomValue(createNewLLMConfigMutationAtom); - const { - mutateAsync: updateConfig, - isPending: isUpdating, - error: updateError, - } = useAtomValue(updateNewLLMConfigMutationAtom); - const { - mutateAsync: deleteConfig, - isPending: isDeleting, - error: deleteError, - } = useAtomValue(deleteNewLLMConfigMutationAtom); + const { mutateAsync: createConfig, isPending: isCreating } = useAtomValue( + createNewLLMConfigMutationAtom + ); + const { mutateAsync: updateConfig, isPending: isUpdating } = useAtomValue( + updateNewLLMConfigMutationAtom + ); + const { mutateAsync: deleteConfig, isPending: isDeleting } = useAtomValue( + deleteNewLLMConfigMutationAtom + ); // Queries const { @@ -98,13 +102,47 @@ export function ModelConfigManager({ searchSpaceId }: ModelConfigManagerProps) { } = useAtomValue(newLLMConfigsAtom); const { data: globalConfigs = [] } = useAtomValue(globalNewLLMConfigsAtom); + // Members for user resolution + const { data: members } = useAtomValue(membersAtom); + const memberMap = useMemo(() => { + const map = new Map(); + if (members) { + for (const m of members) { + map.set(m.user_id, { + name: m.user_display_name || m.user_email || "Unknown", + email: m.user_email || undefined, + avatarUrl: m.user_avatar_url || undefined, + }); + } + } + return map; + }, [members]); + + // Permissions + const { data: access } = useAtomValue(myAccessAtom); + const canCreate = useMemo(() => { + if (!access) return false; + if (access.is_owner) return true; + return access.permissions?.includes("llm_configs:create") ?? false; + }, [access]); + const canUpdate = useMemo(() => { + if (!access) return false; + if (access.is_owner) return true; + return access.permissions?.includes("llm_configs:update") ?? false; + }, [access]); + const canDelete = useMemo(() => { + if (!access) return false; + if (access.is_owner) return true; + return access.permissions?.includes("llm_configs:delete") ?? false; + }, [access]); + const isReadOnly = !canCreate && !canUpdate && !canDelete; + // Local state const [isDialogOpen, setIsDialogOpen] = useState(false); const [editingConfig, setEditingConfig] = useState(null); const [configToDelete, setConfigToDelete] = useState(null); const isSubmitting = isCreating || isUpdating; - const errors = [createError, updateError, deleteError, fetchError].filter(Boolean) as Error[]; const handleFormSubmit = useCallback( async (formData: LLMConfigFormData) => { @@ -121,7 +159,7 @@ export function ModelConfigManager({ searchSpaceId }: ModelConfigManagerProps) { setIsDialogOpen(false); setEditingConfig(null); } catch { - // Error handled by mutation + // Error is displayed inside the dialog by the form } }, [editingConfig, createConfig, updateConfig] @@ -133,7 +171,7 @@ export function ModelConfigManager({ searchSpaceId }: ModelConfigManagerProps) { await deleteConfig({ id: configToDelete.id }); setConfigToDelete(null); } catch { - // Error handled by mutation + // Error handled by mutation state } }; @@ -153,52 +191,86 @@ export function ModelConfigManager({ searchSpaceId }: ModelConfigManagerProps) { }; return ( -
- {/* Header */} -
-
+
+ {/* Header actions */} +
+ + {canCreate && ( -
+ )}
- {/* Error Alerts */} + {/* Fetch Error Alert */} - {errors.length > 0 && - errors.map((err) => ( - - - - - {err?.message ?? "Something went wrong"} - - - - ))} + {fetchError && ( + + + + + {fetchError?.message ?? "Failed to load configurations"} + + + + )} + {/* Read-only / Limited permissions notice */} + {access && !isLoading && isReadOnly && ( + + + + + You have read-only access to LLM configurations. + Contact a space owner to request additional permissions. + + + + )} + {access && !isLoading && !isReadOnly && (!canCreate || !canUpdate || !canDelete) && ( + + + + + You can{" "} + {[canCreate && "create", canUpdate && "edit", canDelete && "delete"] + .filter(Boolean) + .join(" and ")}{" "} + configurations + {!canDelete && ", but cannot delete them"}. + + + + )} + {/* Global Configs Info */} {globalConfigs.length > 0 && ( - - - + + + {globalConfigs.length} global configuration(s){" "} available from your administrator. These are pre-configured and ready to use.{" "} - + Global configs: {globalConfigs.map((g) => g.name).join(", ")} @@ -206,34 +278,44 @@ export function ModelConfigManager({ searchSpaceId }: ModelConfigManagerProps) { )} - {/* Loading State */} + {/* Loading Skeleton */} {isLoading && ( - - -
- - - Loading configurations... - -
-
-
+
+ {["skeleton-a", "skeleton-b", "skeleton-c"].map((key) => ( + + + {/* Header */} +
+
+ + +
+
+ {/* Provider + Model */} +
+ + +
+ {/* Feature badges */} +
+ + +
+ {/* Footer */} +
+ + + +
+
+
+ ))} +
)} {/* Configurations List */} {!isLoading && ( -
-
-

Your Configurations

- -
- +
{configs?.length === 0 ? ( @@ -244,24 +326,35 @@ export function ModelConfigManager({ searchSpaceId }: ModelConfigManagerProps) {

No Configurations Yet

- Create your first AI configuration to customize how your agent responds + {canCreate + ? "Create your first AI configuration to customize how your agent responds" + : "No AI configurations have been added to this space yet. Contact a space owner to add one."}

- + {canCreate && ( + + )}
) : ( - + {configs?.map((config) => { + const member = config.user_id ? memberMap.get(config.user_id) : null; + return ( - - -
- {/* Left accent bar */} -
- -
-
- {/* Main content */} -
-
- -
-
- {/* Title row */} -
-

- {config.name} -

-
- - {config.provider} - - {config.citations_enabled && ( - - - - - - Citations - - - - Citations are enabled for this configuration - - - - )} - {!config.use_default_system_instructions && - config.system_instructions && ( - - - - - - Custom - - - - Using custom system instructions - - - - )} -
-
- - {/* Model name */} - - {config.model_name} - - - {/* Description if any */} - {config.description && ( -

- {config.description} -

- )} - - {/* Footer row */} -
-
- - - {new Date(config.created_at).toLocaleDateString()} - -
-
-
-
- - {/* Actions */} -
+ + + {/* Header: Name + Actions */} +
+
+

+ {config.name} +

+ {config.description && ( +

+ {config.description} +

+ )} +
+ {(canUpdate || canDelete) && ( +
+ {canUpdate && ( Edit + )} + {canDelete && ( Delete -
+ )}
-
+ )} +
+ + {/* Provider + Model */} +
+ {getProviderIcon(config.provider, { className: "size-3.5 shrink-0" })} + + {config.model_name} + +
+ + {/* Feature badges */} +
+ {config.citations_enabled && ( + + + Citations + + )} + {!config.use_default_system_instructions && + config.system_instructions && ( + + + Custom + + )} +
+ + {/* Footer: Date + Creator */} +
+ + {new Date(config.created_at).toLocaleDateString(undefined, { + year: "numeric", + month: "short", + day: "numeric", + })} + + {member && ( + <> + · + + + +
+ {member.avatarUrl ? ( + {member.name} + ) : ( +
+ + {getInitials(member.name)} + +
+ )} + + {member.name} + +
+
+ + {member.email || member.name} + +
+
+ + )}
@@ -408,14 +504,12 @@ export function ModelConfigManager({ searchSpaceId }: ModelConfigManagerProps) { {/* Add/Edit Configuration Dialog */} !open && closeDialog()}> - + e.preventDefault()} + > - - {editingConfig ? ( - - ) : ( - - )} + {editingConfig ? "Edit Configuration" : "Create New Configuration"} diff --git a/surfsense_web/components/settings/prompt-config-manager.tsx b/surfsense_web/components/settings/prompt-config-manager.tsx index 64f6adf23..54058759f 100644 --- a/surfsense_web/components/settings/prompt-config-manager.tsx +++ b/surfsense_web/components/settings/prompt-config-manager.tsx @@ -122,7 +122,7 @@ export function PromptConfigManager({ searchSpaceId }: PromptConfigManagerProps) - + System instructions apply to all AI interactions in this search space. They guide how the diff --git a/surfsense_web/contracts/types/chat-threads.types.ts b/surfsense_web/contracts/types/chat-threads.types.ts index df561092e..d245a4168 100644 --- a/surfsense_web/contracts/types/chat-threads.types.ts +++ b/surfsense_web/contracts/types/chat-threads.types.ts @@ -55,6 +55,7 @@ export const publicChatSnapshotDetail = z.object({ message_count: z.number(), thread_id: z.number(), thread_title: z.string(), + created_by_user_id: z.string().nullable().optional(), }); /** diff --git a/surfsense_web/contracts/types/new-llm-config.types.ts b/surfsense_web/contracts/types/new-llm-config.types.ts index 8239505a1..b01e2abdf 100644 --- a/surfsense_web/contracts/types/new-llm-config.types.ts +++ b/surfsense_web/contracts/types/new-llm-config.types.ts @@ -63,6 +63,7 @@ export const newLLMConfig = z.object({ // Metadata created_at: z.string(), search_space_id: z.number(), + user_id: z.string(), }); /** @@ -76,6 +77,7 @@ export const newLLMConfigPublic = newLLMConfig.omit({ api_key: true }); export const createNewLLMConfigRequest = newLLMConfig.omit({ id: true, created_at: true, + user_id: true, }); export const createNewLLMConfigResponse = newLLMConfig; @@ -110,6 +112,7 @@ export const updateNewLLMConfigRequest = z.object({ id: true, created_at: true, search_space_id: true, + user_id: true, }) .partial(), }); @@ -201,11 +204,13 @@ export const imageGenerationConfig = z.object({ litellm_params: z.record(z.string(), z.any()).nullable().optional(), created_at: z.string(), search_space_id: z.number(), + user_id: z.string(), }); export const createImageGenConfigRequest = imageGenerationConfig.omit({ id: true, created_at: true, + user_id: true, }); export const createImageGenConfigResponse = imageGenerationConfig; @@ -214,7 +219,9 @@ export const getImageGenConfigsResponse = z.array(imageGenerationConfig); export const updateImageGenConfigRequest = z.object({ id: z.number(), - data: imageGenerationConfig.omit({ id: true, created_at: true, search_space_id: true }).partial(), + data: imageGenerationConfig + .omit({ id: true, created_at: true, search_space_id: true, user_id: true }) + .partial(), }); export const updateImageGenConfigResponse = imageGenerationConfig; diff --git a/surfsense_web/lib/provider-icons.tsx b/surfsense_web/lib/provider-icons.tsx new file mode 100644 index 000000000..11cef5bce --- /dev/null +++ b/surfsense_web/lib/provider-icons.tsx @@ -0,0 +1,119 @@ +import { Bot, Shuffle } from "lucide-react"; +import { cn } from "@/lib/utils"; +import { Ai21Icon } from "@/components/icons/providers"; +import { AnthropicIcon } from "@/components/icons/providers"; +import { AnyscaleIcon } from "@/components/icons/providers"; +import { BedrockIcon } from "@/components/icons/providers"; +import { CerebrasIcon } from "@/components/icons/providers"; +import { CloudflareIcon } from "@/components/icons/providers"; +import { CohereIcon } from "@/components/icons/providers"; +import { CometApiIcon } from "@/components/icons/providers"; +import { DatabricksIcon } from "@/components/icons/providers"; +import { DeepInfraIcon } from "@/components/icons/providers"; +import { DeepSeekIcon } from "@/components/icons/providers"; +import { FireworksAiIcon } from "@/components/icons/providers"; +import { GeminiIcon } from "@/components/icons/providers"; +import { GroqIcon } from "@/components/icons/providers"; +import { HuggingFaceIcon } from "@/components/icons/providers"; +import { MistralIcon } from "@/components/icons/providers"; +import { MoonshotIcon } from "@/components/icons/providers"; +import { NscaleIcon } from "@/components/icons/providers"; +import { OllamaIcon } from "@/components/icons/providers"; +import { OpenaiIcon } from "@/components/icons/providers"; +import { OpenRouterIcon } from "@/components/icons/providers"; +import { PerplexityIcon } from "@/components/icons/providers"; +import { QwenIcon } from "@/components/icons/providers"; +import { RecraftIcon } from "@/components/icons/providers"; +import { ReplicateIcon } from "@/components/icons/providers"; +import { SambaNovaIcon } from "@/components/icons/providers"; +import { TogetherAiIcon } from "@/components/icons/providers"; +import { VertexAiIcon } from "@/components/icons/providers"; +import { XaiIcon } from "@/components/icons/providers"; +import { XinferenceIcon } from "@/components/icons/providers"; +import { ZhipuIcon } from "@/components/icons/providers"; + +/** + * Returns a Lucide icon element for the given LLM / image-gen provider. + * Accepts an optional `className` override for the icon size. + */ +export function getProviderIcon( + provider: string, + { isAutoMode, className = "size-4" }: { isAutoMode?: boolean; className?: string } = {} +) { + if (isAutoMode || provider?.toUpperCase() === "AUTO") { + return ; + } + + switch (provider?.toUpperCase()) { + case "AI21": + return ; + case "ALIBABA_QWEN": + return ; + case "ANTHROPIC": + return ; + case "ANYSCALE": + return ; + case "AZURE": + case "AZURE_OPENAI": + return ; + case "AWS_BEDROCK": + case "BEDROCK": + return ; + case "CEREBRAS": + return ; + case "CLOUDFLARE": + return ; + case "COHERE": + return ; + case "COMETAPI": + return ; + case "CUSTOM": + return ; + case "DATABRICKS": + return ; + case "DEEPINFRA": + return ; + case "DEEPSEEK": + return ; + case "FIREWORKS_AI": + return ; + case "GOOGLE": + return ; + case "GROQ": + return ; + case "HUGGINGFACE": + return ; + case "MISTRAL": + return ; + case "MOONSHOT": + return ; + case "NSCALE": + return ; + case "OLLAMA": + return ; + case "OPENAI": + return ; + case "OPENROUTER": + return ; + case "PERPLEXITY": + return ; + case "RECRAFT": + return ; + case "REPLICATE": + return ; + case "SAMBANOVA": + return ; + case "TOGETHER_AI": + return ; + case "VERTEX_AI": + return ; + case "XAI": + return ; + case "XINFERENCE": + return ; + case "ZHIPU": + return ; + default: + return ; + } +} diff --git a/surfsense_web/next.config.ts b/surfsense_web/next.config.ts index f7491b4d3..3278b9f3d 100644 --- a/surfsense_web/next.config.ts +++ b/surfsense_web/next.config.ts @@ -23,12 +23,42 @@ const nextConfig: NextConfig = { // Mark BlockNote server packages as external serverExternalPackages: ["@blocknote/server-util"], - // Configure webpack to handle blocknote packages + // Turbopack config (used during `next dev --turbopack`) + turbopack: { + rules: { + "*.svg": { + loaders: ["@svgr/webpack"], + as: "*.js", + }, + }, + }, + + // Configure webpack to handle blocknote packages + SVGR webpack: (config, { isServer }) => { if (isServer) { // Don't bundle these packages on the server config.externals = [...(config.externals || []), "@blocknote/server-util"]; } + + // SVGR: import *.svg as React components + const fileLoaderRule = config.module.rules.find((rule: any) => rule.test?.test?.(".svg")); + config.module.rules.push( + // Re-apply the existing file loader for *.svg?url imports + { + ...fileLoaderRule, + test: /\.svg$/i, + resourceQuery: /url/, // e.g. import icon from './icon.svg?url' + }, + // Convert all other *.svg imports to React components + { + test: /\.svg$/i, + issuer: fileLoaderRule.issuer, + resourceQuery: { not: [...fileLoaderRule.resourceQuery.not, /url/] }, + use: ["@svgr/webpack"], + } + ); + fileLoaderRule.exclude = /\.svg$/i; + return config; }, diff --git a/surfsense_web/package.json b/surfsense_web/package.json index 5f3631128..038bdc47e 100644 --- a/surfsense_web/package.json +++ b/surfsense_web/package.json @@ -112,6 +112,7 @@ "devDependencies": { "@biomejs/biome": "2.1.2", "@eslint/eslintrc": "^3.3.1", + "@svgr/webpack": "^8.1.0", "@tailwindcss/postcss": "^4.1.11", "@tailwindcss/typography": "^0.5.16", "@types/canvas-confetti": "^1.9.0", diff --git a/surfsense_web/pnpm-lock.yaml b/surfsense_web/pnpm-lock.yaml index 40c80964b..d806fe5f9 100644 --- a/surfsense_web/pnpm-lock.yaml +++ b/surfsense_web/pnpm-lock.yaml @@ -166,22 +166,22 @@ importers: version: 1.4.8(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) fumadocs-core: specifier: ^16.3.1 - version: 16.3.1(@types/react@19.2.7)(lucide-react@0.477.0(react@19.2.3))(next@16.1.0(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(zod@4.2.1) + version: 16.3.1(@types/react@19.2.7)(lucide-react@0.477.0(react@19.2.3))(next@16.1.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(zod@4.2.1) fumadocs-mdx: specifier: ^14.2.1 - version: 14.2.1(fumadocs-core@16.3.1(@types/react@19.2.7)(lucide-react@0.477.0(react@19.2.3))(next@16.1.0(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(zod@4.2.1))(next@16.1.0(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)(vite@7.3.1(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)) + version: 14.2.1(fumadocs-core@16.3.1(@types/react@19.2.7)(lucide-react@0.477.0(react@19.2.3))(next@16.1.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(zod@4.2.1))(next@16.1.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)(vite@7.3.1(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)) fumadocs-ui: specifier: ^16.3.1 - version: 16.3.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(lucide-react@0.477.0(react@19.2.3))(next@16.1.0(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(tailwindcss@4.1.18)(zod@4.2.1) + version: 16.3.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(lucide-react@0.477.0(react@19.2.3))(next@16.1.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(tailwindcss@4.1.18)(zod@4.2.1) geist: specifier: ^1.4.2 - version: 1.5.1(next@16.1.0(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)) + version: 1.5.1(next@16.1.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)) jotai: specifier: ^2.15.1 - version: 2.16.0(@types/react@19.2.7)(react@19.2.3) + version: 2.16.0(@babel/core@7.29.0)(@babel/template@7.28.6)(@types/react@19.2.7)(react@19.2.3) jotai-tanstack-query: specifier: ^0.11.0 - version: 0.11.0(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(jotai@2.16.0(@types/react@19.2.7)(react@19.2.3))(react@19.2.3) + version: 0.11.0(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(jotai@2.16.0(@babel/core@7.29.0)(@babel/template@7.28.6)(@types/react@19.2.7)(react@19.2.3))(react@19.2.3) lucide-react: specifier: ^0.477.0 version: 0.477.0(react@19.2.3) @@ -190,10 +190,10 @@ importers: version: 12.23.26(react-dom@19.2.3(react@19.2.3))(react@19.2.3) next: specifier: ^16.1.0 - version: 16.1.0(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 16.1.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) next-intl: specifier: ^4.6.1 - version: 4.6.1(next@16.1.0(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + version: 4.6.1(next@16.1.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)(typescript@5.9.3) next-themes: specifier: ^0.4.6 version: 0.4.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -276,6 +276,9 @@ importers: '@eslint/eslintrc': specifier: ^3.3.1 version: 3.3.3 + '@svgr/webpack': + specifier: ^8.1.0 + version: 8.1.0(typescript@5.9.3) '@tailwindcss/postcss': specifier: ^4.1.11 version: 4.1.18 @@ -433,10 +436,561 @@ packages: react: optional: true + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.0': + resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-annotate-as-pure@7.27.3': + resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-create-class-features-plugin@7.28.6': + resolution: {integrity: sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-create-regexp-features-plugin@7.28.5': + resolution: {integrity: sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-define-polyfill-provider@0.6.6': + resolution: {integrity: sha512-mOAsxeeKkUKayvZR3HeTYD/fICpCPLJrU5ZjelT/PA6WHtNDBOE436YiaEUvHN454bRM3CebhDsIpieCc4texA==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-member-expression-to-functions@7.28.5': + resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-optimise-call-expression@7.27.1': + resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-plugin-utils@7.28.6': + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} + engines: {node: '>=6.9.0'} + + '@babel/helper-remap-async-to-generator@7.27.1': + resolution: {integrity: sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-replace-supers@7.28.6': + resolution: {integrity: sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-wrap-function@7.28.6': + resolution: {integrity: sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.28.6': + resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.0': + resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5': + resolution: {integrity: sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1': + resolution: {integrity: sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1': + resolution: {integrity: sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1': + resolution: {integrity: sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.13.0 + + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.6': + resolution: {integrity: sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2': + resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-assertions@7.28.6': + resolution: {integrity: sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-attributes@7.28.6': + resolution: {integrity: sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-jsx@7.28.6': + resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.28.6': + resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-unicode-sets-regex@7.18.6': + resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-arrow-functions@7.27.1': + resolution: {integrity: sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-async-generator-functions@7.29.0': + resolution: {integrity: sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-async-to-generator@7.28.6': + resolution: {integrity: sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-block-scoped-functions@7.27.1': + resolution: {integrity: sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-block-scoping@7.28.6': + resolution: {integrity: sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-class-properties@7.28.6': + resolution: {integrity: sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-class-static-block@7.28.6': + resolution: {integrity: sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.12.0 + + '@babel/plugin-transform-classes@7.28.6': + resolution: {integrity: sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-computed-properties@7.28.6': + resolution: {integrity: sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-destructuring@7.28.5': + resolution: {integrity: sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-dotall-regex@7.28.6': + resolution: {integrity: sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-duplicate-keys@7.27.1': + resolution: {integrity: sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.0': + resolution: {integrity: sha512-zBPcW2lFGxdiD8PUnPwJjag2J9otbcLQzvbiOzDxpYXyCuYX9agOwMPGn1prVH0a4qzhCKu24rlH4c1f7yA8rw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-dynamic-import@7.27.1': + resolution: {integrity: sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-explicit-resource-management@7.28.6': + resolution: {integrity: sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-exponentiation-operator@7.28.6': + resolution: {integrity: sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-export-namespace-from@7.27.1': + resolution: {integrity: sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-for-of@7.27.1': + resolution: {integrity: sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-function-name@7.27.1': + resolution: {integrity: sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-json-strings@7.28.6': + resolution: {integrity: sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-literals@7.27.1': + resolution: {integrity: sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-logical-assignment-operators@7.28.6': + resolution: {integrity: sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-member-expression-literals@7.27.1': + resolution: {integrity: sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-amd@7.27.1': + resolution: {integrity: sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-commonjs@7.28.6': + resolution: {integrity: sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-systemjs@7.29.0': + resolution: {integrity: sha512-PrujnVFbOdUpw4UHiVwKvKRLMMic8+eC0CuNlxjsyZUiBjhFdPsewdXCkveh2KqBA9/waD0W1b4hXSOBQJezpQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-umd@7.27.1': + resolution: {integrity: sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-named-capturing-groups-regex@7.29.0': + resolution: {integrity: sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-new-target@7.27.1': + resolution: {integrity: sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-nullish-coalescing-operator@7.28.6': + resolution: {integrity: sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-numeric-separator@7.28.6': + resolution: {integrity: sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-object-rest-spread@7.28.6': + resolution: {integrity: sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-object-super@7.27.1': + resolution: {integrity: sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-optional-catch-binding@7.28.6': + resolution: {integrity: sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-optional-chaining@7.28.6': + resolution: {integrity: sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-parameters@7.27.7': + resolution: {integrity: sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-private-methods@7.28.6': + resolution: {integrity: sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-private-property-in-object@7.28.6': + resolution: {integrity: sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-property-literals@7.27.1': + resolution: {integrity: sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-constant-elements@7.27.1': + resolution: {integrity: sha512-edoidOjl/ZxvYo4lSBOQGDSyToYVkTAwyVoa2tkuYTSmjrB1+uAedoL5iROVLXkxH+vRgA7uP4tMg2pUJpZ3Ug==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-display-name@7.28.0': + resolution: {integrity: sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-development@7.27.1': + resolution: {integrity: sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx@7.28.6': + resolution: {integrity: sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-pure-annotations@7.27.1': + resolution: {integrity: sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-regenerator@7.29.0': + resolution: {integrity: sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-regexp-modifiers@7.28.6': + resolution: {integrity: sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-reserved-words@7.27.1': + resolution: {integrity: sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-shorthand-properties@7.27.1': + resolution: {integrity: sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-spread@7.28.6': + resolution: {integrity: sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-sticky-regex@7.27.1': + resolution: {integrity: sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-template-literals@7.27.1': + resolution: {integrity: sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-typeof-symbol@7.27.1': + resolution: {integrity: sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-typescript@7.28.6': + resolution: {integrity: sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-escapes@7.27.1': + resolution: {integrity: sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-property-regex@7.28.6': + resolution: {integrity: sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-regex@7.27.1': + resolution: {integrity: sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-sets-regex@7.28.6': + resolution: {integrity: sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/preset-env@7.29.0': + resolution: {integrity: sha512-fNEdfc0yi16lt6IZo2Qxk3knHVdfMYX33czNb4v8yWhemoBhibCpQK/uYHtSKIiO+p/zd3+8fYVXhQdOVV608w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/preset-modules@0.1.6-no-external-plugins': + resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} + peerDependencies: + '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 + + '@babel/preset-react@7.28.5': + resolution: {integrity: sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/preset-typescript@7.28.5': + resolution: {integrity: sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/runtime@7.28.4': resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} engines: {node: '>=6.9.0'} + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + '@biomejs/biome@2.1.2': resolution: {integrity: sha512-yq8ZZuKuBVDgAS76LWCfFKHSYIAgqkxVB3mGVVpOe2vSkUTs7xG46zXZeNPRNVjiJuw0SZ3+J2rXiYx0RUpfGg==} engines: {node: '>=14.21.3'} @@ -2670,6 +3224,84 @@ packages: '@standard-schema/utils@0.3.0': resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} + '@svgr/babel-plugin-add-jsx-attribute@8.0.0': + resolution: {integrity: sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-remove-jsx-attribute@8.0.0': + resolution: {integrity: sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0': + resolution: {integrity: sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0': + resolution: {integrity: sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-svg-dynamic-title@8.0.0': + resolution: {integrity: sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-svg-em-dimensions@8.0.0': + resolution: {integrity: sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-transform-react-native-svg@8.1.0': + resolution: {integrity: sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-transform-svg-component@8.0.0': + resolution: {integrity: sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==} + engines: {node: '>=12'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-preset@8.1.0': + resolution: {integrity: sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/core@8.1.0': + resolution: {integrity: sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==} + engines: {node: '>=14'} + + '@svgr/hast-util-to-babel-ast@8.0.0': + resolution: {integrity: sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==} + engines: {node: '>=14'} + + '@svgr/plugin-jsx@8.1.0': + resolution: {integrity: sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==} + engines: {node: '>=14'} + peerDependencies: + '@svgr/core': '*' + + '@svgr/plugin-svgo@8.1.0': + resolution: {integrity: sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==} + engines: {node: '>=14'} + peerDependencies: + '@svgr/core': '*' + + '@svgr/webpack@8.1.0': + resolution: {integrity: sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==} + engines: {node: '>=14'} + '@swc/core-darwin-arm64@1.15.7': resolution: {integrity: sha512-+hNVUfezUid7LeSHqnhoC6Gh3BROABxjlDNInuZ/fie1RUxaEX4qzDwdTgozJELgHhvYxyPIg1ro8ibnKtgO4g==} engines: {node: '>=10'} @@ -2975,6 +3607,10 @@ packages: react: ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 + '@trysound/sax@0.2.0': + resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} + engines: {node: '>=10.13.0'} + '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} @@ -3431,6 +4067,21 @@ packages: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} + babel-plugin-polyfill-corejs2@0.4.15: + resolution: {integrity: sha512-hR3GwrRwHUfYwGfrisXPIDP3JcYfBrW7wKE7+Au6wDYl7fm/ka1NEII6kORzxNU556JjfidZeBsO10kYvtV1aw==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-corejs3@0.14.0: + resolution: {integrity: sha512-AvDcMxJ34W4Wgy4KBIIePQTAOP1Ie2WFwkQp3dB7FQ/f0lI5+nM96zUnYEOE1P9sEg0es5VCP0HxiWu5fUHZAQ==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-regenerator@0.6.6: + resolution: {integrity: sha512-hYm+XLYRMvupxiQzrvXUj7YyvFFVfv5gI0R71AJzudg1g2AI2vyCPPIFEBjk162/wFzti3inBHo7isWFuEVS/A==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} @@ -3453,6 +4104,9 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} @@ -3463,6 +4117,11 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} @@ -3485,6 +4144,10 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + caniuse-lite@1.0.30001761: resolution: {integrity: sha512-JF9ptu1vP2coz98+5051jZ4PwQgd2ni8A+gYSN7EA7dPKIMf0pDlSUxhdmVOaV3/fYK5uWBkgSXJaRLr4+3A6g==} @@ -3600,6 +4263,12 @@ packages: confbox@0.1.8: resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + core-js-compat@3.48.0: + resolution: {integrity: sha512-OM4cAF3D6VtH/WkLtWvyNC56EZVXsZdU3iqaMG2B4WvYrlqU831pc4UtG5yp0sE9z8Y02wVN7PjW5Zf9Gt0f1Q==} + core-js@3.47.0: resolution: {integrity: sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg==} @@ -3609,6 +4278,15 @@ packages: cose-base@2.2.0: resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==} + cosmiconfig@8.3.6: + resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + crelt@1.0.6: resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} @@ -3621,11 +4299,30 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + css-select@5.2.2: + resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} + + css-tree@2.2.1: + resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + + css-tree@2.3.1: + resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + + css-what@6.2.2: + resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} + engines: {node: '>= 6'} + cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} hasBin: true + csso@5.0.5: + resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + cssstyle@4.6.0: resolution: {integrity: sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==} engines: {node: '>=18'} @@ -3851,6 +4548,10 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} @@ -3892,9 +4593,25 @@ packages: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + dompurify@3.3.1: resolution: {integrity: sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==} + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + + dot-case@3.0.4: + resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + dotenv@17.2.3: resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==} engines: {node: '>=12'} @@ -3999,6 +4716,9 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} + electron-to-chromium@1.5.286: + resolution: {integrity: sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==} + emblor@1.4.8: resolution: {integrity: sha512-Vqtz4Gepa7CIkmplQ+kvJnsSZJ4sAyHvQqqX2iCmgoRo5iRQFxr+5FJkk6QuLVNH5vrbBZEYxg7sMZuDCnQ/PQ==} peerDependencies: @@ -4026,6 +4746,9 @@ packages: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + es-abstract@1.24.1: resolution: {integrity: sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==} engines: {node: '>= 0.4'} @@ -4084,6 +4807,10 @@ packages: engines: {node: '>=18'} hasBin: true + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -4433,6 +5160,10 @@ packages: resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} engines: {node: '>= 0.4'} + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + get-east-asian-width@1.4.0: resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==} engines: {node: '>=18'} @@ -4692,6 +5423,9 @@ packages: resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + is-async-function@2.1.1: resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} engines: {node: '>= 0.4'} @@ -4874,9 +5608,17 @@ packages: canvas: optional: true + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -4890,6 +5632,11 @@ packages: resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} hasBin: true + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + jsondiffpatch@0.6.0: resolution: {integrity: sha512-3QItJOXp2AP1uv7waBkao5nCvhEv+QmJAd38Ybq7wNI74Q+BBmnLn4EDKz6yI9xGAIQoUF87qHt+kc1IVxB4zQ==} engines: {node: ^18.0.0 || >=20.0.0} @@ -5005,6 +5752,9 @@ packages: resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} engines: {node: '>= 12.0.0'} + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + linkify-it@5.0.0: resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} @@ -5021,6 +5771,9 @@ packages: lodash-es@4.17.22: resolution: {integrity: sha512-XEawp1t0gxSi9x01glktRZ5HDy0HXqrM0x5pXQM98EaI0NxO6jVM7omDOxsuEo5UIASAnm2bRp1Jt/e0a2XU8Q==} + lodash.debounce@4.0.8: + resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} @@ -5034,12 +5787,18 @@ packages: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true + lower-case@2.0.2: + resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + lowlight@1.20.0: resolution: {integrity: sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==} lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lucide-react@0.477.0: resolution: {integrity: sha512-yCf7aYxerFZAbd8jHJxjwe1j7jEMPptjnaOqdYeirFnEy85cNR3/L+o0I875CYFYya+eEVzZSbNuRk8BZPDpVw==} peerDependencies: @@ -5124,6 +5883,12 @@ packages: mdast-util-to-string@4.0.0: resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + mdn-data@2.0.28: + resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} + + mdn-data@2.0.30: + resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} + mdurl@2.0.0: resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} @@ -5391,6 +6156,9 @@ packages: sass: optional: true + no-case@3.0.4: + resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + node-abi@3.85.0: resolution: {integrity: sha512-zsFhmbkAzwhTft6nd3VxcG0cvJsT70rL+BIGHWVq5fi6MwGrHwzqKaxXE+Hl2GmnGItnDKPPkO5/LQqjVkIdFg==} engines: {node: '>=10'} @@ -5398,10 +6166,16 @@ packages: node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + npm-to-yarn@3.0.1: resolution: {integrity: sha512-tt6PvKu4WyzPwWUzy/hvPFqn+uwXO0K1ZHka8az3NnrhWJDmSqI8ncWq0fkL0k/lmmi5tAC11FXwXuh0rFbt1A==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + number-flow@0.5.8: resolution: {integrity: sha512-FPr1DumWyGi5Nucoug14bC6xEz70A1TnhgSHhKyfqjgji2SOTz+iLJxKtv37N5JyJbteGYCm6NQ9p1O4KZ7iiA==} @@ -5481,6 +6255,10 @@ packages: parse-entities@4.0.2: resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} @@ -5501,6 +6279,10 @@ packages: path-to-regexp@8.3.0: resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -5916,6 +6698,13 @@ packages: refractor@3.6.0: resolution: {integrity: sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==} + regenerate-unicode-properties@10.2.2: + resolution: {integrity: sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==} + engines: {node: '>=4'} + + regenerate@1.4.2: + resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} + regex-recursion@6.0.2: resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} @@ -5929,6 +6718,17 @@ packages: resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} + regexpu-core@6.4.0: + resolution: {integrity: sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==} + engines: {node: '>=4'} + + regjsgen@0.8.0: + resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} + + regjsparser@0.13.0: + resolution: {integrity: sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==} + hasBin: true + rehype-format@5.0.1: resolution: {integrity: sha512-zvmVru9uB0josBVpr946OR8ui7nJEdzZobwLOOqHb/OOD88W0Vk2SqLwoVOj0fM6IPCCO6TaV9CvQvJMWwukFQ==} @@ -6144,6 +6944,9 @@ packages: simple-get@4.0.1: resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + snake-case@3.0.4: + resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} + sonner@2.0.7: resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} peerDependencies: @@ -6258,6 +7061,14 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + svg-parser@2.0.4: + resolution: {integrity: sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==} + + svgo@3.3.2: + resolution: {integrity: sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==} + engines: {node: '>=14.0.0'} + hasBin: true + swr@2.3.8: resolution: {integrity: sha512-gaCPRVoMq8WGDcWj9p4YWzCMPHzE0WNl6W8ADIx9c3JBEIdMkJGMzW+uzXvxHMltwcYACr9jP+32H8/hgwMR7w==} peerDependencies: @@ -6397,6 +7208,22 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + unicode-canonical-property-names-ecmascript@2.0.1: + resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} + engines: {node: '>=4'} + + unicode-match-property-ecmascript@2.0.0: + resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} + engines: {node: '>=4'} + + unicode-match-property-value-ecmascript@2.2.1: + resolution: {integrity: sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==} + engines: {node: '>=4'} + + unicode-property-aliases-ecmascript@2.2.0: + resolution: {integrity: sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==} + engines: {node: '>=4'} + unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} @@ -6427,6 +7254,12 @@ packages: unrs-resolver@1.11.1: resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -6669,6 +7502,9 @@ packages: peerDependencies: yjs: ^13.0.0 + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yjs@13.6.28: resolution: {integrity: sha512-EgnDOXs8+hBVm6mq3/S89Kiwzh5JRbn7w2wXwbrMRyKy/8dOFsLvuIfC+x19ZdtaDc0tA9rQmdZzbqqNHG44wA==} engines: {node: '>=16.0.0', npm: '>=8.0.0'} @@ -6836,8 +7672,738 @@ snapshots: '@types/react': 19.2.7 react: 19.2.3 + '@babel/code-frame@7.29.0': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.0': {} + + '@babel/core@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.28.6 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.1': + dependencies: + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-annotate-as-pure@7.27.3': + dependencies: + '@babel/types': 7.29.0 + + '@babel/helper-compilation-targets@7.28.6': + dependencies: + '@babel/compat-data': 7.29.0 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.1 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/traverse': 7.29.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-create-regexp-features-plugin@7.28.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + regexpu-core: 6.4.0 + semver: 6.3.1 + + '@babel/helper-define-polyfill-provider@0.6.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + debug: 4.4.3 + lodash.debounce: 4.0.8 + resolve: 1.22.11 + transitivePeerDependencies: + - supports-color + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-member-expression-to-functions@7.28.5': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-imports@7.28.6': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-optimise-call-expression@7.27.1': + dependencies: + '@babel/types': 7.29.0 + + '@babel/helper-plugin-utils@7.28.6': {} + + '@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-wrap-function': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-replace-supers@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helper-wrap-function@7.28.6': + dependencies: + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helpers@7.28.6': + dependencies: + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + + '@babel/parser@7.29.0': + dependencies: + '@babel/types': 7.29.0 + + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + + '@babel/plugin-syntax-import-assertions@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-async-generator-functions@7.29.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.29.0) + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-async-to-generator@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-block-scoping@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-class-properties@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-class-static-block@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-classes@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-globals': 7.28.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-computed-properties@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/template': 7.28.6 + + '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-dotall-regex@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-explicit-resource-management@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-exponentiation-operator@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-for-of@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-function-name@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-json-strings@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-literals@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-logical-assignment-operators@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-commonjs@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-systemjs@7.29.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-named-capturing-groups-regex@7.29.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-new-target@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-nullish-coalescing-operator@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-numeric-separator@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-object-rest-spread@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.29.0) + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-object-super@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-optional-catch-binding@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-optional-chaining@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-parameters@7.27.7(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-private-methods@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-private-property-in-object@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-property-literals@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-react-constant-elements@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-react-display-name@7.28.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-react-jsx-development@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-react-jsx@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-react-pure-annotations@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-regenerator@7.29.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-regexp-modifiers@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-spread@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-unicode-property-regex@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-unicode-sets-regex@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/preset-env@7.29.0(@babel/core@7.29.0)': + dependencies: + '@babel/compat-data': 7.29.0 + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.28.5(@babel/core@7.29.0) + '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.0) + '@babel/plugin-syntax-import-assertions': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.29.0) + '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-async-generator-functions': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-async-to-generator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-block-scoping': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-class-static-block': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-classes': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-computed-properties': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) + '@babel/plugin-transform-dotall-regex': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-explicit-resource-management': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-exponentiation-operator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-json-strings': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-logical-assignment-operators': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-modules-systemjs': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-named-capturing-groups-regex': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-nullish-coalescing-operator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-numeric-separator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-object-rest-spread': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-optional-catch-binding': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.29.0) + '@babel/plugin-transform-private-methods': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-private-property-in-object': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-property-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-regenerator': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-regexp-modifiers': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-reserved-words': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-spread': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-typeof-symbol': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-escapes': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-property-regex': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-sets-regex': 7.28.6(@babel/core@7.29.0) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.29.0) + babel-plugin-polyfill-corejs2: 0.4.15(@babel/core@7.29.0) + babel-plugin-polyfill-corejs3: 0.14.0(@babel/core@7.29.0) + babel-plugin-polyfill-regenerator: 0.6.6(@babel/core@7.29.0) + core-js-compat: 3.48.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/types': 7.29.0 + esutils: 2.0.3 + + '@babel/preset-react@7.28.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-transform-react-display-name': 7.28.0(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-pure-annotations': 7.27.1(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/preset-typescript@7.28.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + '@babel/runtime@7.28.4': {} + '@babel/template@7.28.6': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + + '@babel/traverse@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@biomejs/biome@2.1.2': optionalDependencies: '@biomejs/cli-darwin-arm64': 2.1.2 @@ -7434,9 +9000,9 @@ snapshots: dependencies: tslib: 2.8.1 - '@fumadocs/ui@16.3.1(@types/react@19.2.7)(lucide-react@0.477.0(react@19.2.3))(next@16.1.0(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(tailwindcss@4.1.18)(zod@4.2.1)': + '@fumadocs/ui@16.3.1(@types/react@19.2.7)(lucide-react@0.477.0(react@19.2.3))(next@16.1.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(tailwindcss@4.1.18)(zod@4.2.1)': dependencies: - fumadocs-core: 16.3.1(@types/react@19.2.7)(lucide-react@0.477.0(react@19.2.3))(next@16.1.0(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(zod@4.2.1) + fumadocs-core: 16.3.1(@types/react@19.2.7)(lucide-react@0.477.0(react@19.2.3))(next@16.1.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(zod@4.2.1) lodash.merge: 4.6.2 next-themes: 0.4.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) postcss-selector-parser: 7.1.1 @@ -7445,7 +9011,7 @@ snapshots: tailwind-merge: 3.4.0 optionalDependencies: '@types/react': 19.2.7 - next: 16.1.0(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + next: 16.1.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) tailwindcss: 4.1.18 transitivePeerDependencies: - '@mixedbread/sdk' @@ -8927,6 +10493,99 @@ snapshots: '@standard-schema/utils@0.3.0': {} + '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + + '@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + + '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + + '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + + '@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + + '@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + + '@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + + '@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + + '@svgr/babel-preset@8.1.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@svgr/babel-plugin-add-jsx-attribute': 8.0.0(@babel/core@7.29.0) + '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.29.0) + '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.29.0) + '@svgr/babel-plugin-replace-jsx-attribute-value': 8.0.0(@babel/core@7.29.0) + '@svgr/babel-plugin-svg-dynamic-title': 8.0.0(@babel/core@7.29.0) + '@svgr/babel-plugin-svg-em-dimensions': 8.0.0(@babel/core@7.29.0) + '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.29.0) + '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.29.0) + + '@svgr/core@8.1.0(typescript@5.9.3)': + dependencies: + '@babel/core': 7.29.0 + '@svgr/babel-preset': 8.1.0(@babel/core@7.29.0) + camelcase: 6.3.0 + cosmiconfig: 8.3.6(typescript@5.9.3) + snake-case: 3.0.4 + transitivePeerDependencies: + - supports-color + - typescript + + '@svgr/hast-util-to-babel-ast@8.0.0': + dependencies: + '@babel/types': 7.29.0 + entities: 4.5.0 + + '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.9.3))': + dependencies: + '@babel/core': 7.29.0 + '@svgr/babel-preset': 8.1.0(@babel/core@7.29.0) + '@svgr/core': 8.1.0(typescript@5.9.3) + '@svgr/hast-util-to-babel-ast': 8.0.0 + svg-parser: 2.0.4 + transitivePeerDependencies: + - supports-color + + '@svgr/plugin-svgo@8.1.0(@svgr/core@8.1.0(typescript@5.9.3))(typescript@5.9.3)': + dependencies: + '@svgr/core': 8.1.0(typescript@5.9.3) + cosmiconfig: 8.3.6(typescript@5.9.3) + deepmerge: 4.3.1 + svgo: 3.3.2 + transitivePeerDependencies: + - typescript + + '@svgr/webpack@8.1.0(typescript@5.9.3)': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-constant-elements': 7.27.1(@babel/core@7.29.0) + '@babel/preset-env': 7.29.0(@babel/core@7.29.0) + '@babel/preset-react': 7.28.5(@babel/core@7.29.0) + '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) + '@svgr/core': 8.1.0(typescript@5.9.3) + '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3)) + '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3))(typescript@5.9.3) + transitivePeerDependencies: + - supports-color + - typescript + '@swc/core-darwin-arm64@1.15.7': optional: true @@ -9200,6 +10859,8 @@ snapshots: transitivePeerDependencies: - '@floating-ui/dom' + '@trysound/sax@0.2.0': {} + '@tybys/wasm-util@0.10.1': dependencies: tslib: 2.8.1 @@ -9698,6 +11359,30 @@ snapshots: axobject-query@4.1.0: {} + babel-plugin-polyfill-corejs2@0.4.15(@babel/core@7.29.0): + dependencies: + '@babel/compat-data': 7.29.0 + '@babel/core': 7.29.0 + '@babel/helper-define-polyfill-provider': 0.6.6(@babel/core@7.29.0) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-corejs3@0.14.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-define-polyfill-provider': 0.6.6(@babel/core@7.29.0) + core-js-compat: 3.48.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-regenerator@0.6.6(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-define-polyfill-provider': 0.6.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + bail@2.0.2: {} balanced-match@1.0.2: {} @@ -9725,6 +11410,8 @@ snapshots: readable-stream: 3.6.2 optional: true + boolbase@1.0.0: {} + brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 @@ -9738,6 +11425,14 @@ snapshots: dependencies: fill-range: 7.1.1 + browserslist@4.28.1: + dependencies: + baseline-browser-mapping: 2.9.11 + caniuse-lite: 1.0.30001761 + electron-to-chromium: 1.5.286 + node-releases: 2.0.27 + update-browserslist-db: 1.2.3(browserslist@4.28.1) + buffer-from@1.1.2: {} buffer@5.7.1: @@ -9765,6 +11460,8 @@ snapshots: callsites@3.1.0: {} + camelcase@6.3.0: {} + caniuse-lite@1.0.30001761: {} canvas-confetti@1.9.4: {} @@ -9869,6 +11566,12 @@ snapshots: confbox@0.1.8: {} + convert-source-map@2.0.0: {} + + core-js-compat@3.48.0: + dependencies: + browserslist: 4.28.1 + core-js@3.47.0: {} cose-base@1.0.3: @@ -9879,6 +11582,15 @@ snapshots: dependencies: layout-base: 2.0.1 + cosmiconfig@8.3.6(typescript@5.9.3): + dependencies: + import-fresh: 3.3.1 + js-yaml: 4.1.1 + parse-json: 5.2.0 + path-type: 4.0.0 + optionalDependencies: + typescript: 5.9.3 + crelt@1.0.6: {} cross-env@7.0.3: @@ -9891,8 +11603,32 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + css-select@5.2.2: + dependencies: + boolbase: 1.0.0 + css-what: 6.2.2 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + + css-tree@2.2.1: + dependencies: + mdn-data: 2.0.28 + source-map-js: 1.2.1 + + css-tree@2.3.1: + dependencies: + mdn-data: 2.0.30 + source-map-js: 1.2.1 + + css-what@6.2.2: {} + cssesc@3.0.0: {} + csso@5.0.5: + dependencies: + css-tree: 2.2.1 + cssstyle@4.6.0: dependencies: '@asamuzakjp/css-color': 3.2.0 @@ -10139,6 +11875,8 @@ snapshots: deep-is@0.1.4: {} + deepmerge@4.3.1: {} + define-data-property@1.1.4: dependencies: es-define-property: 1.0.1 @@ -10175,10 +11913,33 @@ snapshots: dependencies: esutils: 2.0.3 + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + domelementtype@2.3.0: {} + + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + dompurify@3.3.1: optionalDependencies: '@types/trusted-types': 2.0.7 + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + + dot-case@3.0.4: + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + dotenv@17.2.3: {} drizzle-kit@0.31.8: @@ -10206,6 +11967,8 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 + electron-to-chromium@1.5.286: {} + emblor@1.4.8(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: '@radix-ui/react-dialog': 1.0.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -10240,6 +12003,10 @@ snapshots: entities@6.0.1: {} + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 + es-abstract@1.24.1: dependencies: array-buffer-byte-length: 1.0.2 @@ -10445,6 +12212,8 @@ snapshots: '@esbuild/win32-ia32': 0.27.2 '@esbuild/win32-x64': 0.27.2 + escalade@3.2.0: {} + escape-string-regexp@4.0.0: {} escape-string-regexp@5.0.0: {} @@ -10777,7 +12546,7 @@ snapshots: fsevents@2.3.3: optional: true - fumadocs-core@16.3.1(@types/react@19.2.7)(lucide-react@0.477.0(react@19.2.3))(next@16.1.0(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(zod@4.2.1): + fumadocs-core@16.3.1(@types/react@19.2.7)(lucide-react@0.477.0(react@19.2.3))(next@16.1.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(zod@4.2.1): dependencies: '@formatjs/intl-localematcher': 0.7.2 '@orama/orama': 3.1.18 @@ -10800,21 +12569,21 @@ snapshots: optionalDependencies: '@types/react': 19.2.7 lucide-react: 0.477.0(react@19.2.3) - next: 16.1.0(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + next: 16.1.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react: 19.2.3 react-dom: 19.2.3(react@19.2.3) zod: 4.2.1 transitivePeerDependencies: - supports-color - fumadocs-mdx@14.2.1(fumadocs-core@16.3.1(@types/react@19.2.7)(lucide-react@0.477.0(react@19.2.3))(next@16.1.0(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(zod@4.2.1))(next@16.1.0(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)(vite@7.3.1(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)): + fumadocs-mdx@14.2.1(fumadocs-core@16.3.1(@types/react@19.2.7)(lucide-react@0.477.0(react@19.2.3))(next@16.1.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(zod@4.2.1))(next@16.1.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)(vite@7.3.1(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)): dependencies: '@mdx-js/mdx': 3.1.1 '@standard-schema/spec': 1.1.0 chokidar: 5.0.0 esbuild: 0.27.2 estree-util-value-to-estree: 3.5.0 - fumadocs-core: 16.3.1(@types/react@19.2.7)(lucide-react@0.477.0(react@19.2.3))(next@16.1.0(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(zod@4.2.1) + fumadocs-core: 16.3.1(@types/react@19.2.7)(lucide-react@0.477.0(react@19.2.3))(next@16.1.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(zod@4.2.1) js-yaml: 4.1.1 mdast-util-to-markdown: 2.1.2 picocolors: 1.1.1 @@ -10828,15 +12597,15 @@ snapshots: vfile: 6.0.3 zod: 4.2.1 optionalDependencies: - next: 16.1.0(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + next: 16.1.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react: 19.2.3 vite: 7.3.1(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0) transitivePeerDependencies: - supports-color - fumadocs-ui@16.3.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(lucide-react@0.477.0(react@19.2.3))(next@16.1.0(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(tailwindcss@4.1.18)(zod@4.2.1): + fumadocs-ui@16.3.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(lucide-react@0.477.0(react@19.2.3))(next@16.1.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(tailwindcss@4.1.18)(zod@4.2.1): dependencies: - '@fumadocs/ui': 16.3.1(@types/react@19.2.7)(lucide-react@0.477.0(react@19.2.3))(next@16.1.0(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(tailwindcss@4.1.18)(zod@4.2.1) + '@fumadocs/ui': 16.3.1(@types/react@19.2.7)(lucide-react@0.477.0(react@19.2.3))(next@16.1.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(tailwindcss@4.1.18)(zod@4.2.1) '@radix-ui/react-accordion': 1.2.12(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -10848,7 +12617,7 @@ snapshots: '@radix-ui/react-slot': 1.2.4(@types/react@19.2.7)(react@19.2.3) '@radix-ui/react-tabs': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) class-variance-authority: 0.7.1 - fumadocs-core: 16.3.1(@types/react@19.2.7)(lucide-react@0.477.0(react@19.2.3))(next@16.1.0(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(zod@4.2.1) + fumadocs-core: 16.3.1(@types/react@19.2.7)(lucide-react@0.477.0(react@19.2.3))(next@16.1.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(zod@4.2.1) next-themes: 0.4.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react: 19.2.3 react-dom: 19.2.3(react@19.2.3) @@ -10883,12 +12652,14 @@ snapshots: functions-have-names@1.2.3: {} - geist@1.5.1(next@16.1.0(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)): + geist@1.5.1(next@16.1.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)): dependencies: - next: 16.1.0(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + next: 16.1.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) generator-function@2.0.1: {} + gensync@1.0.0-beta.2: {} + get-east-asian-width@1.4.0: {} get-intrinsic@1.3.0: @@ -11284,6 +13055,8 @@ snapshots: call-bound: 1.0.4 get-intrinsic: 1.3.0 + is-arrayish@0.2.1: {} + is-async-function@2.1.1: dependencies: async-function: 1.0.0 @@ -11419,16 +13192,18 @@ snapshots: jiti@2.6.1: {} - jotai-tanstack-query@0.11.0(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(jotai@2.16.0(@types/react@19.2.7)(react@19.2.3))(react@19.2.3): + jotai-tanstack-query@0.11.0(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(jotai@2.16.0(@babel/core@7.29.0)(@babel/template@7.28.6)(@types/react@19.2.7)(react@19.2.3))(react@19.2.3): dependencies: '@tanstack/query-core': 5.90.12 - jotai: 2.16.0(@types/react@19.2.7)(react@19.2.3) + jotai: 2.16.0(@babel/core@7.29.0)(@babel/template@7.28.6)(@types/react@19.2.7)(react@19.2.3) optionalDependencies: '@tanstack/react-query': 5.90.12(react@19.2.3) react: 19.2.3 - jotai@2.16.0(@types/react@19.2.7)(react@19.2.3): + jotai@2.16.0(@babel/core@7.29.0)(@babel/template@7.28.6)(@types/react@19.2.7)(react@19.2.3): optionalDependencies: + '@babel/core': 7.29.0 + '@babel/template': 7.28.6 '@types/react': 19.2.7 react: 19.2.3 @@ -11466,8 +13241,12 @@ snapshots: - supports-color - utf-8-validate + jsesc@3.1.0: {} + json-buffer@3.0.1: {} + json-parse-even-better-errors@2.3.1: {} + json-schema-traverse@0.4.1: {} json-schema@0.4.0: {} @@ -11478,6 +13257,8 @@ snapshots: dependencies: minimist: 1.2.8 + json5@2.2.3: {} + jsondiffpatch@0.6.0: dependencies: '@types/diff-match-patch': 1.0.36 @@ -11577,6 +13358,8 @@ snapshots: lightningcss-win32-arm64-msvc: 1.30.2 lightningcss-win32-x64-msvc: 1.30.2 + lines-and-columns@1.2.4: {} + linkify-it@5.0.0: dependencies: uc.micro: 2.1.0 @@ -11591,6 +13374,8 @@ snapshots: lodash-es@4.17.22: {} + lodash.debounce@4.0.8: {} + lodash.merge@4.6.2: {} long@5.3.2: {} @@ -11601,6 +13386,10 @@ snapshots: dependencies: js-tokens: 4.0.0 + lower-case@2.0.2: + dependencies: + tslib: 2.8.1 + lowlight@1.20.0: dependencies: fault: 1.0.4 @@ -11608,6 +13397,10 @@ snapshots: lru-cache@10.4.3: {} + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + lucide-react@0.477.0(react@19.2.3): dependencies: react: 19.2.3 @@ -11812,6 +13605,10 @@ snapshots: dependencies: '@types/mdast': 4.0.4 + mdn-data@2.0.28: {} + + mdn-data@2.0.30: {} + mdurl@2.0.0: {} merge2@1.4.1: {} @@ -12210,13 +14007,13 @@ snapshots: next-intl-swc-plugin-extractor@4.6.1: {} - next-intl@4.6.1(next@16.1.0(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)(typescript@5.9.3): + next-intl@4.6.1(next@16.1.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)(typescript@5.9.3): dependencies: '@formatjs/intl-localematcher': 0.5.10 '@parcel/watcher': 2.5.1 '@swc/core': 1.15.7 negotiator: 1.0.0 - next: 16.1.0(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + next: 16.1.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) next-intl-swc-plugin-extractor: 4.6.1 po-parser: 2.0.0 react: 19.2.3 @@ -12231,7 +14028,7 @@ snapshots: react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - next@16.1.0(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + next@16.1.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: '@next/env': 16.1.0 '@swc/helpers': 0.5.15 @@ -12240,7 +14037,7 @@ snapshots: postcss: 8.4.31 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - styled-jsx: 5.1.6(react@19.2.3) + styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.2.3) optionalDependencies: '@next/swc-darwin-arm64': 16.1.0 '@next/swc-darwin-x64': 16.1.0 @@ -12256,6 +14053,11 @@ snapshots: - '@babel/core' - babel-plugin-macros + no-case@3.0.4: + dependencies: + lower-case: 2.0.2 + tslib: 2.8.1 + node-abi@3.85.0: dependencies: semver: 7.7.3 @@ -12263,8 +14065,14 @@ snapshots: node-addon-api@7.1.1: {} + node-releases@2.0.27: {} + npm-to-yarn@3.0.1: {} + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + number-flow@0.5.8: dependencies: esm-env: 1.2.2 @@ -12376,6 +14184,13 @@ snapshots: is-decimal: 2.0.1 is-hexadecimal: 2.0.1 + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.29.0 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + parse5@7.3.0: dependencies: entities: 6.0.1 @@ -12390,6 +14205,8 @@ snapshots: path-to-regexp@8.3.0: {} + path-type@4.0.0: {} + pathe@2.0.3: {} pg-cloudflare@1.2.7: @@ -12886,6 +14703,12 @@ snapshots: parse-entities: 2.0.0 prismjs: 1.27.0 + regenerate-unicode-properties@10.2.2: + dependencies: + regenerate: 1.4.2 + + regenerate@1.4.2: {} + regex-recursion@6.0.2: dependencies: regex-utilities: 2.3.0 @@ -12905,6 +14728,21 @@ snapshots: gopd: 1.2.0 set-function-name: 2.0.2 + regexpu-core@6.4.0: + dependencies: + regenerate: 1.4.2 + regenerate-unicode-properties: 10.2.2 + regjsgen: 0.8.0 + regjsparser: 0.13.0 + unicode-match-property-ecmascript: 2.0.0 + unicode-match-property-value-ecmascript: 2.2.1 + + regjsgen@0.8.0: {} + + regjsparser@0.13.0: + dependencies: + jsesc: 3.1.0 + rehype-format@5.0.1: dependencies: '@types/hast': 3.0.4 @@ -13272,6 +15110,11 @@ snapshots: simple-concat: 1.0.1 optional: true + snake-case@3.0.4: + dependencies: + dot-case: 3.0.4 + tslib: 2.8.1 + sonner@2.0.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: react: 19.2.3 @@ -13407,10 +15250,12 @@ snapshots: dependencies: inline-style-parser: 0.2.7 - styled-jsx@5.1.6(react@19.2.3): + styled-jsx@5.1.6(@babel/core@7.29.0)(react@19.2.3): dependencies: client-only: 0.0.1 react: 19.2.3 + optionalDependencies: + '@babel/core': 7.29.0 stylis@4.3.6: {} @@ -13420,6 +15265,18 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} + svg-parser@2.0.4: {} + + svgo@3.3.2: + dependencies: + '@trysound/sax': 0.2.0 + commander: 7.2.0 + css-select: 5.2.2 + css-tree: 2.3.1 + css-what: 6.2.2 + csso: 5.0.5 + picocolors: 1.1.1 + swr@2.3.8(react@19.2.3): dependencies: dequal: 2.0.3 @@ -13571,6 +15428,17 @@ snapshots: undici-types@6.21.0: {} + unicode-canonical-property-names-ecmascript@2.0.1: {} + + unicode-match-property-ecmascript@2.0.0: + dependencies: + unicode-canonical-property-names-ecmascript: 2.0.1 + unicode-property-aliases-ecmascript: 2.2.0 + + unicode-match-property-value-ecmascript@2.2.1: {} + + unicode-property-aliases-ecmascript@2.2.0: {} + unified@11.0.5: dependencies: '@types/unist': 3.0.3 @@ -13642,6 +15510,12 @@ snapshots: '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 + update-browserslist-db@1.2.3(browserslist@4.28.1): + dependencies: + browserslist: 4.28.1 + escalade: 3.2.0 + picocolors: 1.1.1 + uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -13848,6 +15722,8 @@ snapshots: lib0: 0.2.115 yjs: 13.6.28 + yallist@3.1.1: {} + yjs@13.6.28: dependencies: lib0: 0.2.115 diff --git a/surfsense_web/svgr.d.ts b/surfsense_web/svgr.d.ts new file mode 100644 index 000000000..ada7f47c5 --- /dev/null +++ b/surfsense_web/svgr.d.ts @@ -0,0 +1,5 @@ +declare module "*.svg" { + import type { FC, SVGProps } from "react"; + const content: FC>; + export default content; +}