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 (
-
-
- Add Image Model
-
- );
- }
-
- return (
-
-
-
- {isLoading ? (
-
- ) : currentConfig ? (
- <>
- {isCurrentAutoMode ? (
-
- ) : (
-
- )}
-
- {currentConfig.name}
-
- {isCurrentAutoMode ? (
-
- Auto
-
- ) : (
-
- Image
-
- )}
- >
- ) : (
- <>
-
- Image Model
- >
- )}
-
-
-
-
-
-
- {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 && (
-
{
- e.stopPropagation();
- setOpen(false);
- onEdit(config, false);
- }}
- >
-
-
- )}
-
-
- );
- })}
-
- >
- )}
-
- {/* Add New */}
- {onAddNew && (
-
-
{
- setOpen(false);
- onAddNew();
- }}
- >
-
- Add Image Model
-
-
- )}
-
-
-
-
- );
-}
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 && (
-
handleEditConfig(e, config, true)}
- >
-
-
- )}
-
-
- );
- })}
-
- )}
-
- {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
-
- )}
-
-
-
-
handleEditConfig(e, config, false)}
- >
-
-
-
-
- );
- })}
-
- )}
-
- {/* Add New Config Button */}
-
-
{
- setOpen(false);
- onAddNew();
- }}
+
+
+
-
- Add New Configuration
-
-
-
-
+
+ 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 && (
+
handleEditLLMConfig(e, config, true)}
+ >
+
+
+ )}
+
+
+ );
+ })}
+
+ )}
+
+ {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
+
+ )}
+
+
+
+
handleEditLLMConfig(e, config, false)}
+ >
+
+
+
+
+ );
+ })}
+
+ )}
+
+ {/* Add New LLM Config */}
+
+
{
+ setOpen(false);
+ onAddNewLLM();
+ }}
+ >
+
+ Add New Configuration
+
+
+
+
+
+
+ {/* ─── 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 && (
+
{
+ e.stopPropagation();
+ setOpen(false);
+ onEditImage(config, true);
+ }}
+ >
+
+
+ )}
+
+
+ );
+ })}
+
+ )}
+
+ {/* 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 && (
+
{
+ e.stopPropagation();
+ setOpen(false);
+ onEditImage(config, false);
+ }}
+ >
+
+
+ )}
+
+
+ );
+ })}
+
+ >
+ )}
+
+ {/* Add New Image Config */}
+ {onAddNewImage && (
+
+
{
+ setOpen(false);
+ onAddNewImage();
+ }}
+ >
+
+ Add Image Model
+
+
+ )}
+
+
+
+
);
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 && (
+
+
+
+ onDelete(snapshot)}
+ disabled={isDeleting}
+ className="h-7 w-7 text-muted-foreground hover:text-destructive"
+ >
+
+
+
+ Delete
+
+
+ )}
+
- (e.target as HTMLInputElement).select()}
- />
-
-
-
onCopy(snapshot)}
- className="h-8 px-2"
- title="Copy link"
- >
-
-
- {canDelete && (
-
onDelete(snapshot)}
- disabled={isDeleting}
- className="h-8 px-2 text-destructive hover:text-destructive hover:bg-destructive/10"
- title="Delete link"
+
+ {/* Message count badge */}
+
+
-
-
- )}
-
-
+
+ {snapshot.message_count} messages
+
+
+
+ {/* Public URL – selectable fallback for manual copy */}
+
+
+ {snapshot.public_url}
+
+
+
+
+
+ {copied ? (
+
+ ) : (
+
+ )}
+
+
+ {copied ? "Copied!" : "Copy link"}
+
+
+
+
+ {/* Footer: Date + Creator */}
+
+
{formattedDate}
+ {member && (
+ <>
+
·
+
+
+
+
+ {member.avatarUrl ? (
+
+ ) : (
+
+
+ {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 && (
+
+ Add Image Model
+
+ )}
{/* 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
-
-
-
-
-
-
-
-
-
-
-
- Unassigned
-
- {globalConfigs.length > 0 && (
- <>
-
- Global
-
- {globalConfigs.map((c) => {
- const isAuto = "is_auto_mode" in c && c.is_auto_mode;
- return (
-
-
- {isAuto ? (
-
-
- AUTO
-
- ) : (
-
- {c.provider}
-
- )}
- {c.name}
-
-
- );
- })}
- >
- )}
- {(userConfigs?.length ?? 0) > 0 && (
- <>
-
- Your Models
-
- {userConfigs?.map((c) => (
-
-
-
- {c.provider}
-
- {c.name}
- ({c.model_name})
-
-
- ))}
- >
- )}
-
-
- {hasPrefChanges && (
-
-
- {isSavingPref ? "Saving..." : "Save"}
-
- {
- setSelectedPrefId(preferences.image_generation_config_id ?? "");
- setHasPrefChanges(false);
- }}
- className="text-xs h-8"
- >
- Reset
-
-
- )}
-
-
-
- )}
-
- {/* 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
-
-
- Add Image Model
-
-
-
{(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."}
-
-
- Add First Image Model
-
+ {canCreate && (
+
+
+ Add First Image Model
+
+ )}
) : (
-
+
- {userConfigs?.map((config) => (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {config.name}
-
-
- {config.provider}
-
-
-
- {config.model_name}
-
- {config.description && (
-
- {config.description}
-
- )}
-
-
- {new Date(config.created_at).toLocaleDateString()}
-
-
-
-
-
-
-
- openEditDialog(config)}
- className="h-7 w-7 p-0 text-muted-foreground hover:text-foreground"
- >
-
-
-
- Edit
-
-
-
-
-
- setConfigToDelete(config)}
- className="h-7 w-7 p-0 text-muted-foreground hover:text-destructive"
- >
-
-
-
- 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 && (
+
+
+
+ openEditDialog(config)}
+ className="h-7 w-7 text-muted-foreground hover:text-foreground"
+ >
+
+
+
+ Edit
+
+
+ )}
+ {canDelete && (
+
+
+
+ setConfigToDelete(config)}
+ className="h-7 w-7 text-muted-foreground hover:text-destructive"
+ >
+
+
+
+ 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 ? (
+
+ ) : (
+
+
+ {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 */}
-
-
-
+ {/* Header actions */}
+
+ refreshConfigs()}
+ disabled={isLoading}
+ className="flex items-center gap-2 text-xs md:text-sm h-8 md:h-9"
+ >
+
+ Refresh
+
+ {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 */}
+
+
+ Configuration
+
+
handleRoleAssignment(role.prefKey, value)}
+ >
+
+
+
+
+
+ Unassigned
+
+
+ {/* Global Configurations */}
+ {roleGlobalConfigs.length > 0 && (
+
+
+ Global Configurations
+
+ {roleGlobalConfigs.map((config) => {
+ const isAuto = "is_auto_mode" in config && config.is_auto_mode;
+ return (
+
+
+ {isAuto ? (
+
+
+ AUTO
+
+ ) : (
+ getProviderIcon(config.provider, {
+ className: "size-3 md:size-3.5 shrink-0",
+ })
+ )}
+
+ {config.name}
+
+ {!isAuto && (
+
+ ({config.model_name})
+
+ )}
+ {isAuto && (
+
+ Recommended
+
+ )}
+
+
+ );
+ })}
+
+ )}
+
+ {/* Custom Configurations */}
+ {roleUserConfigs.length > 0 && (
+
+
+ Your Configurations
+
+ {roleUserConfigs.map((config) => (
+
+
+ {getProviderIcon(config.provider, {
+ className: "size-3 md:size-3.5 shrink-0",
+ })}
+
+ {config.name}
+
+
+ ({config.model_name})
+
+
+
+ ))}
+
+ )}
+
+
+
+
+ {/* Assigned Config Summary */}
+ {assignedConfig && (
+
+ {isAutoMode ? (
+
+
+
+
+ Auto Mode
+
+
+ Routes across all available providers
+
- {currentAssignment && (
-
- )}
-
-
-
-
-
- Assign LLM Configuration:
-
-
handleRoleAssignment(`${key}_llm_id`, value)}
- >
-
-
-
-
-
- Unassigned
-
-
- {/* Global Configurations */}
- {globalConfigs.length > 0 && (
- <>
-
- Global Configurations
-
- {globalConfigs.map((config) => {
- const isAutoMode =
- "is_auto_mode" in config && config.is_auto_mode;
- return (
-
-
- {isAutoMode ? (
-
-
- AUTO
-
- ) : (
-
- {config.provider}
-
- )}
- {config.name}
- {!isAutoMode && (
-
- ({config.model_name})
-
- )}
- {isAutoMode ? (
-
- Recommended
-
- ) : (
-
- 🌐 Global
-
- )}
-
-
- );
- })}
- >
- )}
-
- {/* Custom Configurations */}
- {newLLMConfigs.length > 0 && (
- <>
-
- Your Configurations
-
- {newLLMConfigs
- .filter(
- (config) => config.id && config.id.toString().trim() !== ""
- )
- .map((config) => (
-
-
-
- {config.provider}
-
- {config.name}
-
- ({config.model_name})
-
-
-
- ))}
- >
- )}
-
-
-
-
- {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 && (
-
-
-
- {isSaving ? "Saving" : "Save Changes"}
-
+ {/* Save / Reset Bar */}
+
+ {hasChanges && (
+
+ You have unsaved changes
+
-
+
Reset
+
+
+ {isSaving ? "Saving…" : "Save 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 */}
+
+ refreshConfigs()}
+ disabled={isLoading}
+ className="flex items-center gap-2 text-xs md:text-sm h-8 md:h-9"
+ >
+
+ Refresh
+
+ {canCreate && (
refreshConfigs()}
- disabled={isLoading}
className="flex items-center gap-2 text-xs md:text-sm h-8 md:h-9"
>
-
- Refresh
+ Add Configuration
-
+ )}
- {/* 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
-
-
- Add Configuration
-
-
-
+
{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."}
-
-
- Create First Configuration
-
+ {canCreate && (
+
+
+ Create First Configuration
+
+ )}
) : (
-
+
{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 && (
openEditDialog(config)}
- className="h-7 w-7 md:h-8 md:w-8 p-0 text-muted-foreground hover:text-foreground"
+ className="h-7 w-7 text-muted-foreground hover:text-foreground"
>
-
+
Edit
+ )}
+ {canDelete && (
setConfigToDelete(config)}
- className="h-7 w-7 md:h-8 md:w-8 p-0 text-muted-foreground hover:text-destructive"
+ className="h-7 w-7 text-muted-foreground hover:text-destructive"
>
-
+
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 ? (
+
+ ) : (
+
+
+ {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;
+}