From 40fa0f365ccbc52b82099973bfb5ab28ce0d959a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2026 17:08:46 +0900 Subject: [PATCH 01/40] chore(deps): bump the github-actions-dependencies group across 1 directory with 2 updates (#34261) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/api-tests.yml | 8 ++++---- .github/workflows/autofix.yml | 2 +- .github/workflows/db-migration-test.yml | 4 ++-- .github/workflows/pyrefly-diff.yml | 2 +- .github/workflows/style.yml | 2 +- .github/workflows/vdb-tests.yml | 2 +- .github/workflows/web-e2e.yml | 2 +- .github/workflows/web-tests.yml | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/api-tests.yml b/.github/workflows/api-tests.yml index 7bce056970..cd967b76cf 100644 --- a/.github/workflows/api-tests.yml +++ b/.github/workflows/api-tests.yml @@ -35,7 +35,7 @@ jobs: persist-credentials: false - name: Setup UV and Python - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 + uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: enable-cache: true python-version: ${{ matrix.python-version }} @@ -84,7 +84,7 @@ jobs: persist-credentials: false - name: Setup UV and Python - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 + uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: enable-cache: true python-version: ${{ matrix.python-version }} @@ -156,7 +156,7 @@ jobs: persist-credentials: false - name: Setup UV and Python - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 + uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: enable-cache: true python-version: "3.12" @@ -203,7 +203,7 @@ jobs: - name: Report coverage if: ${{ env.CODECOV_TOKEN != '' }} - uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5.5.3 + uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0 with: files: ./coverage.xml disable_search: true diff --git a/.github/workflows/autofix.yml b/.github/workflows/autofix.yml index d8a53c9594..0f89d32fdb 100644 --- a/.github/workflows/autofix.yml +++ b/.github/workflows/autofix.yml @@ -52,7 +52,7 @@ jobs: python-version: "3.11" - if: github.event_name != 'merge_group' - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 + uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 - name: Generate Docker Compose if: github.event_name != 'merge_group' && steps.docker-compose-changes.outputs.any_changed == 'true' diff --git a/.github/workflows/db-migration-test.yml b/.github/workflows/db-migration-test.yml index ffb9734e48..5991abe3ba 100644 --- a/.github/workflows/db-migration-test.yml +++ b/.github/workflows/db-migration-test.yml @@ -19,7 +19,7 @@ jobs: persist-credentials: false - name: Setup UV and Python - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 + uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: enable-cache: true python-version: "3.12" @@ -69,7 +69,7 @@ jobs: persist-credentials: false - name: Setup UV and Python - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 + uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: enable-cache: true python-version: "3.12" diff --git a/.github/workflows/pyrefly-diff.yml b/.github/workflows/pyrefly-diff.yml index a00f469bbe..0b2a7b8e9e 100644 --- a/.github/workflows/pyrefly-diff.yml +++ b/.github/workflows/pyrefly-diff.yml @@ -22,7 +22,7 @@ jobs: fetch-depth: 0 - name: Setup Python & UV - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 + uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: enable-cache: true diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml index 7b269ccf4e..a7432ae167 100644 --- a/.github/workflows/style.yml +++ b/.github/workflows/style.yml @@ -33,7 +33,7 @@ jobs: - name: Setup UV and Python if: steps.changed-files.outputs.any_changed == 'true' - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 + uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: enable-cache: false python-version: "3.12" diff --git a/.github/workflows/vdb-tests.yml b/.github/workflows/vdb-tests.yml index 7c4cd0ba8c..026ff0fe57 100644 --- a/.github/workflows/vdb-tests.yml +++ b/.github/workflows/vdb-tests.yml @@ -30,7 +30,7 @@ jobs: remove_tool_cache: true - name: Setup UV and Python - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 + uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: enable-cache: true python-version: ${{ matrix.python-version }} diff --git a/.github/workflows/web-e2e.yml b/.github/workflows/web-e2e.yml index 8035d1ef8e..ec8e1ce4e3 100644 --- a/.github/workflows/web-e2e.yml +++ b/.github/workflows/web-e2e.yml @@ -32,7 +32,7 @@ jobs: run: vp install --frozen-lockfile - name: Setup UV and Python - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 + uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: enable-cache: true python-version: "3.12" diff --git a/.github/workflows/web-tests.yml b/.github/workflows/web-tests.yml index 8110a16355..9ce1156d87 100644 --- a/.github/workflows/web-tests.yml +++ b/.github/workflows/web-tests.yml @@ -83,7 +83,7 @@ jobs: - name: Report coverage if: ${{ env.CODECOV_TOKEN != '' }} - uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5.5.3 + uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0 with: directory: web/coverage flags: web From 456684dfc38cb2b8e48fa59110783123eded064c Mon Sep 17 00:00:00 2001 From: Renzo <170978465+RenzoMXD@users.noreply.github.com> Date: Mon, 30 Mar 2026 10:09:49 +0200 Subject: [PATCH 02/40] refactor: core/rag docstore, datasource, embedding, rerank, retrieval (#34203) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Asuka Minato --- .../rag/datasource/keyword/jieba/jieba.py | 4 +- api/core/rag/datasource/retrieval_service.py | 9 +-- .../tidb_on_qdrant/tidb_on_qdrant_vector.py | 5 +- api/core/rag/datasource/vdb/vector_factory.py | 2 +- api/core/rag/docstore/dataset_docstore.py | 22 +++---- api/core/rag/embedding/cached_embedding.py | 29 ++++----- api/core/rag/extractor/notion_extractor.py | 9 ++- .../index_processor/index_processor_base.py | 5 +- .../processor/paragraph_index_processor.py | 17 +++--- .../processor/parent_child_index_processor.py | 27 +++++---- api/core/rag/rerank/rerank_model.py | 6 +- api/core/rag/retrieval/dataset_retrieval.py | 4 +- .../datasource/keyword/jieba/test_jieba.py | 24 ++++---- .../datasource/test_datasource_retrieval.py | 8 +-- .../rag/datasource/vdb/test_vector_factory.py | 8 +-- .../rag/docstore/test_dataset_docstore.py | 14 ++--- .../rag/embedding/test_cached_embedding.py | 27 +++------ .../rag/embedding/test_embedding_service.py | 60 ++++++++----------- .../rag/extractor/test_notion_extractor.py | 19 +++--- .../test_paragraph_index_processor.py | 18 +++--- .../test_parent_child_index_processor.py | 17 ++---- .../rag/indexing/test_index_processor_base.py | 20 +++---- .../core/rag/rerank/test_reranker.py | 17 ++---- .../rag/retrieval/test_dataset_retrieval.py | 13 ++-- 24 files changed, 170 insertions(+), 214 deletions(-) diff --git a/api/core/rag/datasource/keyword/jieba/jieba.py b/api/core/rag/datasource/keyword/jieba/jieba.py index b07dc108be..b8d5db7a43 100644 --- a/api/core/rag/datasource/keyword/jieba/jieba.py +++ b/api/core/rag/datasource/keyword/jieba/jieba.py @@ -97,13 +97,13 @@ class Jieba(BaseKeyword): documents = [] - segment_query_stmt = db.session.query(DocumentSegment).where( + segment_query_stmt = select(DocumentSegment).where( DocumentSegment.dataset_id == self.dataset.id, DocumentSegment.index_node_id.in_(sorted_chunk_indices) ) if document_ids_filter: segment_query_stmt = segment_query_stmt.where(DocumentSegment.document_id.in_(document_ids_filter)) - segments = db.session.execute(segment_query_stmt).scalars().all() + segments = db.session.scalars(segment_query_stmt).all() segment_map = {segment.index_node_id: segment for segment in segments} for chunk_index in sorted_chunk_indices: segment = segment_map.get(chunk_index) diff --git a/api/core/rag/datasource/retrieval_service.py b/api/core/rag/datasource/retrieval_service.py index cc6ec12c75..203a8588d6 100644 --- a/api/core/rag/datasource/retrieval_service.py +++ b/api/core/rag/datasource/retrieval_service.py @@ -432,10 +432,11 @@ class RetrievalService: # Batch query dataset documents dataset_documents = { doc.id: doc - for doc in db.session.query(DatasetDocument) - .where(DatasetDocument.id.in_(document_ids)) - .options(load_only(DatasetDocument.id, DatasetDocument.doc_form, DatasetDocument.dataset_id)) - .all() + for doc in db.session.scalars( + select(DatasetDocument) + .where(DatasetDocument.id.in_(document_ids)) + .options(load_only(DatasetDocument.id, DatasetDocument.doc_form, DatasetDocument.dataset_id)) + ).all() } valid_dataset_documents = {} diff --git a/api/core/rag/datasource/vdb/tidb_on_qdrant/tidb_on_qdrant_vector.py b/api/core/rag/datasource/vdb/tidb_on_qdrant/tidb_on_qdrant_vector.py index 3c1d5e015f..69c81d521c 100644 --- a/api/core/rag/datasource/vdb/tidb_on_qdrant/tidb_on_qdrant_vector.py +++ b/api/core/rag/datasource/vdb/tidb_on_qdrant/tidb_on_qdrant_vector.py @@ -426,11 +426,10 @@ class TidbOnQdrantVectorFactory(AbstractVectorFactory): TIDB_ON_QDRANT_API_KEY = f"{tidb_auth_binding.account}:{tidb_auth_binding.password}" else: - idle_tidb_auth_binding = ( - db.session.query(TidbAuthBinding) + idle_tidb_auth_binding = db.session.scalar( + select(TidbAuthBinding) .where(TidbAuthBinding.active == False, TidbAuthBinding.status == "ACTIVE") .limit(1) - .one_or_none() ) if idle_tidb_auth_binding: idle_tidb_auth_binding.active = True diff --git a/api/core/rag/datasource/vdb/vector_factory.py b/api/core/rag/datasource/vdb/vector_factory.py index 5a8d3a2f3f..26531eab88 100644 --- a/api/core/rag/datasource/vdb/vector_factory.py +++ b/api/core/rag/datasource/vdb/vector_factory.py @@ -277,7 +277,7 @@ class Vector: return self._vector_processor.search_by_vector(query_vector, **kwargs) def search_by_file(self, file_id: str, **kwargs: Any) -> list[Document]: - upload_file: UploadFile | None = db.session.query(UploadFile).where(UploadFile.id == file_id).first() + upload_file: UploadFile | None = db.session.get(UploadFile, file_id) if not upload_file: return [] diff --git a/api/core/rag/docstore/dataset_docstore.py b/api/core/rag/docstore/dataset_docstore.py index e5b794f80d..40f45953af 100644 --- a/api/core/rag/docstore/dataset_docstore.py +++ b/api/core/rag/docstore/dataset_docstore.py @@ -4,7 +4,7 @@ from collections.abc import Sequence from typing import Any from graphon.model_runtime.entities.model_entities import ModelType -from sqlalchemy import func, select +from sqlalchemy import delete, func, select from core.model_manager import ModelManager from core.rag.index_processor.constant.index_type import IndexTechniqueType @@ -63,10 +63,8 @@ class DatasetDocumentStore: return output def add_documents(self, docs: Sequence[Document], allow_update: bool = True, save_child: bool = False): - max_position = ( - db.session.query(func.max(DocumentSegment.position)) - .where(DocumentSegment.document_id == self._document_id) - .scalar() + max_position = db.session.scalar( + select(func.max(DocumentSegment.position)).where(DocumentSegment.document_id == self._document_id) ) if max_position is None: @@ -155,12 +153,14 @@ class DatasetDocumentStore: ) if save_child and doc.children: # delete the existing child chunks - db.session.query(ChildChunk).where( - ChildChunk.tenant_id == self._dataset.tenant_id, - ChildChunk.dataset_id == self._dataset.id, - ChildChunk.document_id == self._document_id, - ChildChunk.segment_id == segment_document.id, - ).delete() + db.session.execute( + delete(ChildChunk).where( + ChildChunk.tenant_id == self._dataset.tenant_id, + ChildChunk.dataset_id == self._dataset.id, + ChildChunk.document_id == self._document_id, + ChildChunk.segment_id == segment_document.id, + ) + ) # add new child chunks for position, child in enumerate(doc.children, start=1): child_segment = ChildChunk( diff --git a/api/core/rag/embedding/cached_embedding.py b/api/core/rag/embedding/cached_embedding.py index 3bdad00712..8d1c0da392 100644 --- a/api/core/rag/embedding/cached_embedding.py +++ b/api/core/rag/embedding/cached_embedding.py @@ -6,6 +6,7 @@ from typing import Any, cast import numpy as np from graphon.model_runtime.entities.model_entities import ModelPropertyKey from graphon.model_runtime.model_providers.__base.text_embedding_model import TextEmbeddingModel +from sqlalchemy import select from sqlalchemy.exc import IntegrityError from configs import dify_config @@ -31,14 +32,14 @@ class CacheEmbedding(Embeddings): embedding_queue_indices = [] for i, text in enumerate(texts): hash = helper.generate_text_hash(text) - embedding = ( - db.session.query(Embedding) - .filter_by( - model_name=self._model_instance.model_name, - hash=hash, - provider_name=self._model_instance.provider, + embedding = db.session.scalar( + select(Embedding) + .where( + Embedding.model_name == self._model_instance.model_name, + Embedding.hash == hash, + Embedding.provider_name == self._model_instance.provider, ) - .first() + .limit(1) ) if embedding: text_embeddings[i] = embedding.get_embedding() @@ -112,14 +113,14 @@ class CacheEmbedding(Embeddings): embedding_queue_indices = [] for i, multimodel_document in enumerate(multimodel_documents): file_id = multimodel_document["file_id"] - embedding = ( - db.session.query(Embedding) - .filter_by( - model_name=self._model_instance.model_name, - hash=file_id, - provider_name=self._model_instance.provider, + embedding = db.session.scalar( + select(Embedding) + .where( + Embedding.model_name == self._model_instance.model_name, + Embedding.hash == file_id, + Embedding.provider_name == self._model_instance.provider, ) - .first() + .limit(1) ) if embedding: multimodel_embeddings[i] = embedding.get_embedding() diff --git a/api/core/rag/extractor/notion_extractor.py b/api/core/rag/extractor/notion_extractor.py index 372af8fd94..aa36160711 100644 --- a/api/core/rag/extractor/notion_extractor.py +++ b/api/core/rag/extractor/notion_extractor.py @@ -4,6 +4,7 @@ import operator from typing import Any, cast import httpx +from sqlalchemy import update from configs import dify_config from core.rag.extractor.extractor_base import BaseExtractor @@ -346,9 +347,11 @@ class NotionExtractor(BaseExtractor): if data_source_info: data_source_info["last_edited_time"] = last_edited_time - db.session.query(DocumentModel).filter_by(id=document_model.id).update( - {DocumentModel.data_source_info: json.dumps(data_source_info)} - ) # type: ignore + db.session.execute( + update(DocumentModel) + .where(DocumentModel.id == document_model.id) + .values(data_source_info=json.dumps(data_source_info)) + ) db.session.commit() def get_notion_last_edited_time(self) -> str: diff --git a/api/core/rag/index_processor/index_processor_base.py b/api/core/rag/index_processor/index_processor_base.py index a435dfc46a..7d504fdb35 100644 --- a/api/core/rag/index_processor/index_processor_base.py +++ b/api/core/rag/index_processor/index_processor_base.py @@ -11,6 +11,7 @@ from typing import TYPE_CHECKING, Any, NotRequired, Optional from urllib.parse import unquote, urlparse import httpx +from sqlalchemy import select from typing_extensions import TypedDict from configs import dify_config @@ -200,7 +201,7 @@ class BaseIndexProcessor(ABC): # Get unique IDs for database query unique_upload_file_ids = list(set(upload_file_id_list)) - upload_files = db.session.query(UploadFile).where(UploadFile.id.in_(unique_upload_file_ids)).all() + upload_files = db.session.scalars(select(UploadFile).where(UploadFile.id.in_(unique_upload_file_ids))).all() # Create a mapping from ID to UploadFile for quick lookup upload_file_map = {upload_file.id: upload_file for upload_file in upload_files} @@ -312,7 +313,7 @@ class BaseIndexProcessor(ABC): """ from services.file_service import FileService - tool_file = db.session.query(ToolFile).where(ToolFile.id == tool_file_id).first() + tool_file = db.session.get(ToolFile, tool_file_id) if not tool_file: return None blob = storage.load_once(tool_file.file_key) diff --git a/api/core/rag/index_processor/processor/paragraph_index_processor.py b/api/core/rag/index_processor/processor/paragraph_index_processor.py index 5c10ffbf2d..22ab492cbf 100644 --- a/api/core/rag/index_processor/processor/paragraph_index_processor.py +++ b/api/core/rag/index_processor/processor/paragraph_index_processor.py @@ -18,6 +18,7 @@ from graphon.model_runtime.entities.message_entities import ( UserPromptMessage, ) from graphon.model_runtime.entities.model_entities import ModelFeature, ModelType +from sqlalchemy import select from core.app.file_access import DatabaseFileAccessController from core.app.llm import deduct_llm_quota @@ -145,14 +146,12 @@ class ParagraphIndexProcessor(BaseIndexProcessor): if delete_summaries: if node_ids: # Find segments by index_node_id - segments = ( - db.session.query(DocumentSegment) - .filter( + segments = db.session.scalars( + select(DocumentSegment).where( DocumentSegment.dataset_id == dataset.id, DocumentSegment.index_node_id.in_(node_ids), ) - .all() - ) + ).all() segment_ids = [segment.id for segment in segments] if segment_ids: SummaryIndexService.delete_summaries_for_segments(dataset, segment_ids) @@ -537,11 +536,9 @@ class ParagraphIndexProcessor(BaseIndexProcessor): # Get unique IDs for database query unique_upload_file_ids = list(set(upload_file_id_list)) - upload_files = ( - db.session.query(UploadFile) - .where(UploadFile.id.in_(unique_upload_file_ids), UploadFile.tenant_id == tenant_id) - .all() - ) + upload_files = db.session.scalars( + select(UploadFile).where(UploadFile.id.in_(unique_upload_file_ids), UploadFile.tenant_id == tenant_id) + ).all() # Create File objects from UploadFile records file_objects = [] diff --git a/api/core/rag/index_processor/processor/parent_child_index_processor.py b/api/core/rag/index_processor/processor/parent_child_index_processor.py index 70504e6e50..1c5e02e9c8 100644 --- a/api/core/rag/index_processor/processor/parent_child_index_processor.py +++ b/api/core/rag/index_processor/processor/parent_child_index_processor.py @@ -6,6 +6,8 @@ import uuid from collections.abc import Mapping from typing import Any +from sqlalchemy import delete, select + from configs import dify_config from core.db.session_factory import session_factory from core.entities.knowledge_entities import PreviewDetail @@ -177,17 +179,16 @@ class ParentChildIndexProcessor(BaseIndexProcessor): child_node_ids = precomputed_child_node_ids else: # Fallback to original query (may fail if segments are already deleted) - child_node_ids = ( - db.session.query(ChildChunk.index_node_id) + rows = db.session.execute( + select(ChildChunk.index_node_id) .join(DocumentSegment, ChildChunk.segment_id == DocumentSegment.id) .where( DocumentSegment.dataset_id == dataset.id, DocumentSegment.index_node_id.in_(node_ids), ChildChunk.dataset_id == dataset.id, ) - .all() - ) - child_node_ids = [child_node_id[0] for child_node_id in child_node_ids if child_node_id[0]] + ).all() + child_node_ids = [row[0] for row in rows if row[0]] # Delete from vector index if child_node_ids: @@ -195,18 +196,22 @@ class ParentChildIndexProcessor(BaseIndexProcessor): # Delete from database if delete_child_chunks and child_node_ids: - db.session.query(ChildChunk).where( - ChildChunk.dataset_id == dataset.id, ChildChunk.index_node_id.in_(child_node_ids) - ).delete(synchronize_session=False) + db.session.execute( + delete(ChildChunk).where( + ChildChunk.dataset_id == dataset.id, ChildChunk.index_node_id.in_(child_node_ids) + ) + ) db.session.commit() else: vector.delete() if delete_child_chunks: # Use existing compound index: (tenant_id, dataset_id, ...) - db.session.query(ChildChunk).where( - ChildChunk.tenant_id == dataset.tenant_id, ChildChunk.dataset_id == dataset.id - ).delete(synchronize_session=False) + db.session.execute( + delete(ChildChunk).where( + ChildChunk.tenant_id == dataset.tenant_id, ChildChunk.dataset_id == dataset.id + ) + ) db.session.commit() def retrieve( diff --git a/api/core/rag/rerank/rerank_model.py b/api/core/rag/rerank/rerank_model.py index 211a9f5c5c..8283be19f9 100644 --- a/api/core/rag/rerank/rerank_model.py +++ b/api/core/rag/rerank/rerank_model.py @@ -134,9 +134,7 @@ class RerankModelRunner(BaseRerankRunner): ): if document.metadata.get("doc_type") == DocType.IMAGE: # Query file info within db.session context to ensure thread-safe access - upload_file = ( - db.session.query(UploadFile).where(UploadFile.id == document.metadata["doc_id"]).first() - ) + upload_file = db.session.get(UploadFile, document.metadata["doc_id"]) if upload_file: blob = storage.load_once(upload_file.key) document_file_base64 = base64.b64encode(blob).decode() @@ -169,7 +167,7 @@ class RerankModelRunner(BaseRerankRunner): return rerank_result, unique_documents elif query_type == QueryType.IMAGE_QUERY: # Query file info within db.session context to ensure thread-safe access - upload_file = db.session.query(UploadFile).where(UploadFile.id == query).first() + upload_file = db.session.get(UploadFile, query) if upload_file: blob = storage.load_once(upload_file.key) file_query = base64.b64encode(blob).decode() diff --git a/api/core/rag/retrieval/dataset_retrieval.py b/api/core/rag/retrieval/dataset_retrieval.py index 1abea6639e..593e1f1420 100644 --- a/api/core/rag/retrieval/dataset_retrieval.py +++ b/api/core/rag/retrieval/dataset_retrieval.py @@ -1340,7 +1340,7 @@ class DatasetRetrieval: metadata_filtering_conditions: MetadataFilteringCondition | None, inputs: dict, ) -> tuple[dict[str, list[str]] | None, MetadataCondition | None]: - document_query = db.session.query(DatasetDocument).where( + document_query = select(DatasetDocument).where( DatasetDocument.dataset_id.in_(dataset_ids), DatasetDocument.indexing_status == "completed", DatasetDocument.enabled == True, @@ -1411,7 +1411,7 @@ class DatasetRetrieval: document_query = document_query.where(and_(*filters)) else: document_query = document_query.where(or_(*filters)) - documents = document_query.all() + documents = db.session.scalars(document_query).all() # group by dataset_id metadata_filter_document_ids = defaultdict(list) if documents else None # type: ignore for document in documents: diff --git a/api/tests/unit_tests/core/rag/datasource/keyword/jieba/test_jieba.py b/api/tests/unit_tests/core/rag/datasource/keyword/jieba/test_jieba.py index 795a325a6b..bbdd476914 100644 --- a/api/tests/unit_tests/core/rag/datasource/keyword/jieba/test_jieba.py +++ b/api/tests/unit_tests/core/rag/datasource/keyword/jieba/test_jieba.py @@ -201,27 +201,23 @@ def test_search_returns_documents_in_rank_order_and_applies_filter(monkeypatch, document_id = _Field("document_id") keyword = Jieba(_dataset(_dataset_keyword_table())) - query_stmt = _FakeQuery() - patched_runtime.session.query.return_value = query_stmt - patched_runtime.session.execute.return_value = _FakeExecuteResult( - [ - SimpleNamespace( - index_node_id="node-2", - content="segment-content", - index_node_hash="hash-2", - document_id="doc-2", - dataset_id="dataset-1", - ) - ] - ) + patched_runtime.session.scalars.return_value.all.return_value = [ + SimpleNamespace( + index_node_id="node-2", + content="segment-content", + index_node_hash="hash-2", + document_id="doc-2", + dataset_id="dataset-1", + ) + ] monkeypatch.setattr(jieba_module, "DocumentSegment", _FakeDocumentSegment) + monkeypatch.setattr(jieba_module, "select", lambda *_: _FakeSelect()) monkeypatch.setattr(keyword, "_get_dataset_keyword_table", MagicMock(return_value={"k": {"node-1", "node-2"}})) monkeypatch.setattr(keyword, "_retrieve_ids_by_query", MagicMock(return_value=["node-1", "node-2"])) documents = keyword.search("query", top_k=2, document_ids_filter=["doc-2"]) - assert len(query_stmt.where_calls) == 2 assert len(documents) == 1 assert documents[0].page_content == "segment-content" assert documents[0].metadata["doc_id"] == "node-2" diff --git a/api/tests/unit_tests/core/rag/datasource/test_datasource_retrieval.py b/api/tests/unit_tests/core/rag/datasource/test_datasource_retrieval.py index 63de4b8af2..5dbd62580a 100644 --- a/api/tests/unit_tests/core/rag/datasource/test_datasource_retrieval.py +++ b/api/tests/unit_tests/core/rag/datasource/test_datasource_retrieval.py @@ -714,13 +714,13 @@ class TestRetrievalServiceInternals: dataset_id="dataset-id", ) - dataset_query = Mock() - dataset_query.where.return_value.options.return_value.all.return_value = [ + scalars_result = Mock() + scalars_result.all.return_value = [ dataset_doc_parent, dataset_doc_text, dataset_doc_parent_summary, ] - monkeypatch.setattr(retrieval_service_module.db.session, "query", Mock(return_value=dataset_query)) + monkeypatch.setattr(retrieval_service_module.db.session, "scalars", Mock(return_value=scalars_result)) monkeypatch.setattr(retrieval_service_module, "RetrievalChildChunk", _SimpleRetrievalChildChunk) monkeypatch.setattr(retrieval_service_module, "RetrievalSegments", _SimpleRetrievalSegment) @@ -882,7 +882,7 @@ class TestRetrievalServiceInternals: def test_format_retrieval_documents_rolls_back_and_raises_when_db_fails(self, monkeypatch): rollback = Mock() monkeypatch.setattr(retrieval_service_module.db.session, "rollback", rollback) - monkeypatch.setattr(retrieval_service_module.db.session, "query", Mock(side_effect=RuntimeError("db error"))) + monkeypatch.setattr(retrieval_service_module.db.session, "scalars", Mock(side_effect=RuntimeError("db error"))) documents = [Document(page_content="content", metadata={"document_id": "doc-1"}, provider="dify")] diff --git a/api/tests/unit_tests/core/rag/datasource/vdb/test_vector_factory.py b/api/tests/unit_tests/core/rag/datasource/vdb/test_vector_factory.py index 54ad6d330b..4e9ceddda9 100644 --- a/api/tests/unit_tests/core/rag/datasource/vdb/test_vector_factory.py +++ b/api/tests/unit_tests/core/rag/datasource/vdb/test_vector_factory.py @@ -340,15 +340,13 @@ def test_search_by_file_handles_missing_and_existing_upload(vector_factory_modul vector._embeddings = MagicMock() vector._vector_processor = MagicMock() + mock_session = SimpleNamespace(get=lambda _model, _id: None) monkeypatch.setattr(vector_factory_module, "UploadFile", SimpleNamespace(id=_Field())) - monkeypatch.setattr( - vector_factory_module, "db", SimpleNamespace(session=SimpleNamespace(query=lambda _model: upload_query)) - ) + monkeypatch.setattr(vector_factory_module, "db", SimpleNamespace(session=mock_session)) - upload_query.first.return_value = None assert vector.search_by_file("file-1") == [] - upload_query.first.return_value = SimpleNamespace(key="blob-key") + mock_session.get = lambda _model, _id: SimpleNamespace(key="blob-key") monkeypatch.setattr(vector_factory_module.storage, "load_once", MagicMock(return_value=b"file-bytes")) vector._embeddings.embed_multimodal_query.return_value = [0.3, 0.4] vector._vector_processor.search_by_vector.return_value = ["hit"] diff --git a/api/tests/unit_tests/core/rag/docstore/test_dataset_docstore.py b/api/tests/unit_tests/core/rag/docstore/test_dataset_docstore.py index 3ba0628fe2..a7b7c1595b 100644 --- a/api/tests/unit_tests/core/rag/docstore/test_dataset_docstore.py +++ b/api/tests/unit_tests/core/rag/docstore/test_dataset_docstore.py @@ -167,7 +167,7 @@ class TestDatasetDocumentStoreAddDocuments: ): mock_session = MagicMock() mock_db.session = mock_session - mock_db.session.query.return_value.where.return_value.scalar.return_value = None + mock_db.session.scalar.return_value = None mock_manager = MagicMock() mock_manager.get_model_instance.return_value = mock_model_instance @@ -211,7 +211,7 @@ class TestDatasetDocumentStoreAddDocuments: with patch("core.rag.docstore.dataset_docstore.db") as mock_db: mock_session = MagicMock() mock_db.session = mock_session - mock_db.session.query.return_value.where.return_value.scalar.return_value = 5 + mock_db.session.scalar.return_value = 5 with patch.object(DatasetDocumentStore, "get_document_segment", return_value=mock_existing_segment): with patch.object(DatasetDocumentStore, "add_multimodel_documents_binding"): @@ -276,7 +276,7 @@ class TestDatasetDocumentStoreAddDocuments: with patch("core.rag.docstore.dataset_docstore.db") as mock_db: mock_session = MagicMock() mock_db.session = mock_session - mock_db.session.query.return_value.where.return_value.scalar.return_value = None + mock_db.session.scalar.return_value = None with patch.object(DatasetDocumentStore, "get_document_segment", return_value=None): with patch.object(DatasetDocumentStore, "add_multimodel_documents_binding"): @@ -353,7 +353,7 @@ class TestDatasetDocumentStoreAddDocuments: with patch("core.rag.docstore.dataset_docstore.db") as mock_db: mock_session = MagicMock() mock_db.session = mock_session - mock_db.session.query.return_value.where.return_value.scalar.return_value = None + mock_db.session.scalar.return_value = None with patch.object(DatasetDocumentStore, "get_document_segment", return_value=None): with patch.object(DatasetDocumentStore, "add_multimodel_documents_binding"): @@ -755,7 +755,7 @@ class TestDatasetDocumentStoreAddDocumentsUpdateChild: with patch("core.rag.docstore.dataset_docstore.db") as mock_db: mock_session = MagicMock() mock_db.session = mock_session - mock_db.session.query.return_value.where.return_value.scalar.return_value = 5 + mock_db.session.scalar.return_value = 5 with patch.object(DatasetDocumentStore, "get_document_segment", return_value=mock_existing_segment): with patch.object(DatasetDocumentStore, "add_multimodel_documents_binding"): @@ -767,7 +767,7 @@ class TestDatasetDocumentStoreAddDocumentsUpdateChild: store.add_documents([mock_doc], save_child=True) - mock_db.session.query.return_value.where.return_value.delete.assert_called() + mock_db.session.execute.assert_called() mock_db.session.commit.assert_called() @@ -798,7 +798,7 @@ class TestDatasetDocumentStoreAddDocumentsUpdateAnswer: with patch("core.rag.docstore.dataset_docstore.db") as mock_db: mock_session = MagicMock() mock_db.session = mock_session - mock_db.session.query.return_value.where.return_value.scalar.return_value = 5 + mock_db.session.scalar.return_value = 5 with patch.object(DatasetDocumentStore, "get_document_segment", return_value=mock_existing_segment): with patch.object(DatasetDocumentStore, "add_multimodel_documents_binding"): diff --git a/api/tests/unit_tests/core/rag/embedding/test_cached_embedding.py b/api/tests/unit_tests/core/rag/embedding/test_cached_embedding.py index 6fd44be4d4..3563186186 100644 --- a/api/tests/unit_tests/core/rag/embedding/test_cached_embedding.py +++ b/api/tests/unit_tests/core/rag/embedding/test_cached_embedding.py @@ -69,7 +69,7 @@ class TestCacheEmbeddingMultimodalDocuments: documents = [{"file_id": "file123", "content": "test content"}] with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None mock_model_instance.invoke_multimodal_embedding.return_value = sample_multimodal_result result = cache_embedding.embed_multimodal_documents(documents) @@ -114,7 +114,7 @@ class TestCacheEmbeddingMultimodalDocuments: ) with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None mock_model_instance.invoke_multimodal_embedding.return_value = embedding_result result = cache_embedding.embed_multimodal_documents(documents) @@ -134,7 +134,7 @@ class TestCacheEmbeddingMultimodalDocuments: mock_cached_embedding.get_embedding.return_value = normalized_cached with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = mock_cached_embedding + mock_session.scalar.return_value = mock_cached_embedding result = cache_embedding.embed_multimodal_documents(documents) @@ -180,18 +180,7 @@ class TestCacheEmbeddingMultimodalDocuments: ) with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - call_count = [0] - - def mock_filter_by(**kwargs): - call_count[0] += 1 - mock_query = Mock() - if call_count[0] == 1: - mock_query.first.return_value = mock_cached_embedding - else: - mock_query.first.return_value = None - return mock_query - - mock_session.query.return_value.filter_by = mock_filter_by + mock_session.scalar.side_effect = [mock_cached_embedding, None, None] mock_model_instance.invoke_multimodal_embedding.return_value = embedding_result result = cache_embedding.embed_multimodal_documents(documents) @@ -224,7 +213,7 @@ class TestCacheEmbeddingMultimodalDocuments: ) with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None mock_model_instance.invoke_multimodal_embedding.return_value = embedding_result with patch("core.rag.embedding.cached_embedding.logger") as mock_logger: @@ -265,7 +254,7 @@ class TestCacheEmbeddingMultimodalDocuments: ) with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None batch_results = [create_batch_result(10), create_batch_result(10), create_batch_result(5)] mock_model_instance.invoke_multimodal_embedding.side_effect = batch_results @@ -281,7 +270,7 @@ class TestCacheEmbeddingMultimodalDocuments: documents = [{"file_id": "file123"}] with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None mock_model_instance.invoke_multimodal_embedding.side_effect = Exception("API Error") with pytest.raises(Exception) as exc_info: @@ -298,7 +287,7 @@ class TestCacheEmbeddingMultimodalDocuments: documents = [{"file_id": "file123"}] with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None mock_model_instance.invoke_multimodal_embedding.return_value = sample_multimodal_result mock_session.commit.side_effect = IntegrityError("Duplicate key", None, None) diff --git a/api/tests/unit_tests/core/rag/embedding/test_embedding_service.py b/api/tests/unit_tests/core/rag/embedding/test_embedding_service.py index d7ba944e58..408cf14a51 100644 --- a/api/tests/unit_tests/core/rag/embedding/test_embedding_service.py +++ b/api/tests/unit_tests/core/rag/embedding/test_embedding_service.py @@ -139,7 +139,7 @@ class TestCacheEmbeddingDocuments: # Mock database query to return no cached embedding (cache miss) with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None # Mock model invocation mock_model_instance.invoke_text_embedding.return_value = sample_embedding_result @@ -203,7 +203,7 @@ class TestCacheEmbeddingDocuments: ) with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None mock_model_instance.invoke_text_embedding.return_value = embedding_result # Act @@ -240,7 +240,7 @@ class TestCacheEmbeddingDocuments: with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: # Mock database to return cached embedding (cache hit) - mock_session.query.return_value.filter_by.return_value.first.return_value = mock_cached_embedding + mock_session.scalar.return_value = mock_cached_embedding # Act result = cache_embedding.embed_documents(texts) @@ -313,19 +313,7 @@ class TestCacheEmbeddingDocuments: mock_hash.side_effect = generate_hash # Mock database to return cached embedding only for first text (hash_1) - call_count = [0] - - def mock_filter_by(**kwargs): - call_count[0] += 1 - mock_query = Mock() - # First call (hash_1) returns cached, others return None - if call_count[0] == 1: - mock_query.first.return_value = mock_cached_embedding - else: - mock_query.first.return_value = None - return mock_query - - mock_session.query.return_value.filter_by = mock_filter_by + mock_session.scalar.side_effect = [mock_cached_embedding, None, None] mock_model_instance.invoke_text_embedding.return_value = embedding_result # Act @@ -392,7 +380,7 @@ class TestCacheEmbeddingDocuments: ) with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None # Mock model to return appropriate batch results batch_results = [ @@ -455,7 +443,7 @@ class TestCacheEmbeddingDocuments: ) with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None mock_model_instance.invoke_text_embedding.return_value = embedding_result with patch("core.rag.embedding.cached_embedding.logger") as mock_logger: @@ -489,7 +477,7 @@ class TestCacheEmbeddingDocuments: texts = ["Test text"] with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None # Mock model to raise connection error mock_model_instance.invoke_text_embedding.side_effect = InvokeConnectionError("Failed to connect to API") @@ -515,7 +503,7 @@ class TestCacheEmbeddingDocuments: texts = ["Test text"] with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None # Mock model to raise rate limit error mock_model_instance.invoke_text_embedding.side_effect = InvokeRateLimitError("Rate limit exceeded") @@ -539,7 +527,7 @@ class TestCacheEmbeddingDocuments: texts = ["Test text"] with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None # Mock model to raise authorization error mock_model_instance.invoke_text_embedding.side_effect = InvokeAuthorizationError("Invalid API key") @@ -564,7 +552,7 @@ class TestCacheEmbeddingDocuments: texts = ["Test text"] with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None mock_model_instance.invoke_text_embedding.return_value = sample_embedding_result # Mock database commit to raise IntegrityError @@ -884,7 +872,7 @@ class TestEmbeddingModelSwitching: ) with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None model_instance_ada.invoke_text_embedding.return_value = result_ada model_instance_3_small.invoke_text_embedding.return_value = result_3_small @@ -1047,7 +1035,7 @@ class TestEmbeddingDimensionValidation: ) with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None mock_model_instance.invoke_text_embedding.return_value = embedding_result # Act @@ -1100,7 +1088,7 @@ class TestEmbeddingDimensionValidation: ) with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None mock_model_instance.invoke_text_embedding.return_value = embedding_result # Act @@ -1186,7 +1174,7 @@ class TestEmbeddingDimensionValidation: ) with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None model_instance_ada.invoke_text_embedding.return_value = result_ada model_instance_cohere.invoke_text_embedding.return_value = result_cohere @@ -1284,7 +1272,7 @@ class TestEmbeddingEdgeCases: ) with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None mock_model_instance.invoke_text_embedding.return_value = embedding_result # Act @@ -1327,7 +1315,7 @@ class TestEmbeddingEdgeCases: ) with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None mock_model_instance.invoke_text_embedding.return_value = embedding_result # Act @@ -1375,7 +1363,7 @@ class TestEmbeddingEdgeCases: ) with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None mock_model_instance.invoke_text_embedding.return_value = embedding_result # Act @@ -1427,7 +1415,7 @@ class TestEmbeddingEdgeCases: ) with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None mock_model_instance.invoke_text_embedding.return_value = embedding_result # Act @@ -1483,7 +1471,7 @@ class TestEmbeddingEdgeCases: ) with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None mock_model_instance.invoke_text_embedding.return_value = embedding_result # Act @@ -1551,7 +1539,7 @@ class TestEmbeddingEdgeCases: ) with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None mock_model_instance.invoke_text_embedding.return_value = embedding_result # Act @@ -1649,7 +1637,7 @@ class TestEmbeddingEdgeCases: ) with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None mock_model_instance.invoke_text_embedding.return_value = embedding_result # Act @@ -1728,7 +1716,7 @@ class TestEmbeddingCachePerformance: with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: # First call: cache miss - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None usage = EmbeddingUsage( tokens=5, @@ -1756,7 +1744,7 @@ class TestEmbeddingCachePerformance: assert len(result1) == 1 # Arrange - Second call: cache hit - mock_session.query.return_value.filter_by.return_value.first.return_value = mock_cached_embedding + mock_session.scalar.return_value = mock_cached_embedding # Act - Second call (cache hit) result2 = cache_embedding.embed_documents([text]) @@ -1816,7 +1804,7 @@ class TestEmbeddingCachePerformance: ) with patch("core.rag.embedding.cached_embedding.db.session") as mock_session: - mock_session.query.return_value.filter_by.return_value.first.return_value = None + mock_session.scalar.return_value = None # Mock model to return appropriate batch results batch_results = [ diff --git a/api/tests/unit_tests/core/rag/extractor/test_notion_extractor.py b/api/tests/unit_tests/core/rag/extractor/test_notion_extractor.py index 6daee11f8f..808e41867e 100644 --- a/api/tests/unit_tests/core/rag/extractor/test_notion_extractor.py +++ b/api/tests/unit_tests/core/rag/extractor/test_notion_extractor.py @@ -405,35 +405,36 @@ class TestNotionMetadataAndCredentialMethods: class FakeDocumentModel: data_source_info = "data_source_info" + id = "id" - update_calls = [] + execute_calls = [] - class FakeQuery: - def filter_by(self, **kwargs): + class FakeUpdateStmt: + def where(self, *args): return self - def update(self, payload): - update_calls.append(payload) + def values(self, **kwargs): + return self class FakeSession: committed = False - def query(self, model): - assert model is FakeDocumentModel - return FakeQuery() + def execute(self, stmt): + execute_calls.append(stmt) def commit(self): self.committed = True fake_db = SimpleNamespace(session=FakeSession()) monkeypatch.setattr(notion_extractor, "DocumentModel", FakeDocumentModel) + monkeypatch.setattr(notion_extractor, "update", lambda model: FakeUpdateStmt()) monkeypatch.setattr(notion_extractor, "db", fake_db) monkeypatch.setattr(extractor, "get_notion_last_edited_time", lambda: "2026-01-01T00:00:00.000Z") doc_model = SimpleNamespace(id="doc-1", data_source_info_dict={"source": "notion"}) extractor.update_last_edited_time(doc_model) - assert update_calls + assert execute_calls assert fake_db.session.committed is True def test_get_notion_last_edited_time_uses_page_and_database_urls(self, mocker: MockerFixture): diff --git a/api/tests/unit_tests/core/rag/indexing/processor/test_paragraph_index_processor.py b/api/tests/unit_tests/core/rag/indexing/processor/test_paragraph_index_processor.py index cc2873dd3f..d4b987c832 100644 --- a/api/tests/unit_tests/core/rag/indexing/processor/test_paragraph_index_processor.py +++ b/api/tests/unit_tests/core/rag/indexing/processor/test_paragraph_index_processor.py @@ -188,10 +188,10 @@ class TestParagraphIndexProcessor: mock_keyword_cls.return_value.add_texts.assert_called_once_with(docs) def test_clean_deletes_summaries_and_vector(self, processor: ParagraphIndexProcessor, dataset: Mock) -> None: - segment_query = Mock() - segment_query.filter.return_value.all.return_value = [SimpleNamespace(id="seg-1")] + scalars_result = Mock() + scalars_result.all.return_value = [SimpleNamespace(id="seg-1")] session = Mock() - session.query.return_value = segment_query + session.scalars.return_value = scalars_result with ( patch("core.rag.index_processor.processor.paragraph_index_processor.db.session", session), @@ -531,10 +531,10 @@ class TestParagraphIndexProcessor: size=1, key="key", ) - query = Mock() - query.where.return_value.all.return_value = [image_upload, non_image_upload] + scalars_result = Mock() + scalars_result.all.return_value = [image_upload, non_image_upload] session = Mock() - session.query.return_value = query + session.scalars.return_value = scalars_result with ( patch("core.rag.index_processor.processor.paragraph_index_processor.db.session", session), @@ -565,10 +565,10 @@ class TestParagraphIndexProcessor: size=1, key="key", ) - query = Mock() - query.where.return_value.all.return_value = [image_upload] + scalars_result = Mock() + scalars_result.all.return_value = [image_upload] session = Mock() - session.query.return_value = query + session.scalars.return_value = scalars_result with ( patch("core.rag.index_processor.processor.paragraph_index_processor.db.session", session), diff --git a/api/tests/unit_tests/core/rag/indexing/processor/test_parent_child_index_processor.py b/api/tests/unit_tests/core/rag/indexing/processor/test_parent_child_index_processor.py index b1ed735ee7..d363a0804d 100644 --- a/api/tests/unit_tests/core/rag/indexing/processor/test_parent_child_index_processor.py +++ b/api/tests/unit_tests/core/rag/indexing/processor/test_parent_child_index_processor.py @@ -208,11 +208,7 @@ class TestParentChildIndexProcessor: vector.create_multimodal.assert_called_once_with(multimodal_docs) def test_clean_with_precomputed_child_ids(self, processor: ParentChildIndexProcessor, dataset: Mock) -> None: - delete_query = Mock() - where_query = Mock() - where_query.delete.return_value = 2 session = Mock() - session.query.return_value.where.return_value = where_query with ( patch("core.rag.index_processor.processor.parent_child_index_processor.Vector") as mock_vector_cls, @@ -227,16 +223,16 @@ class TestParentChildIndexProcessor: ) vector.delete_by_ids.assert_called_once_with(["child-1", "child-2"]) - where_query.delete.assert_called_once_with(synchronize_session=False) + session.execute.assert_called() session.commit.assert_called_once() def test_clean_queries_child_ids_when_not_precomputed( self, processor: ParentChildIndexProcessor, dataset: Mock ) -> None: - child_query = Mock() - child_query.join.return_value.where.return_value.all.return_value = [("child-1",), (None,), ("child-2",)] + execute_result = Mock() + execute_result.all.return_value = [("child-1",), (None,), ("child-2",)] session = Mock() - session.query.return_value = child_query + session.execute.return_value = execute_result with ( patch("core.rag.index_processor.processor.parent_child_index_processor.Vector") as mock_vector_cls, @@ -248,10 +244,7 @@ class TestParentChildIndexProcessor: vector.delete_by_ids.assert_called_once_with(["child-1", "child-2"]) def test_clean_dataset_wide_cleanup(self, processor: ParentChildIndexProcessor, dataset: Mock) -> None: - where_query = Mock() - where_query.delete.return_value = 3 session = Mock() - session.query.return_value.where.return_value = where_query with ( patch("core.rag.index_processor.processor.parent_child_index_processor.Vector") as mock_vector_cls, @@ -261,7 +254,7 @@ class TestParentChildIndexProcessor: processor.clean(dataset, None, delete_child_chunks=True) vector.delete.assert_called_once() - where_query.delete.assert_called_once_with(synchronize_session=False) + session.execute.assert_called() session.commit.assert_called_once() def test_clean_deletes_summaries_when_requested(self, processor: ParentChildIndexProcessor, dataset: Mock) -> None: diff --git a/api/tests/unit_tests/core/rag/indexing/test_index_processor_base.py b/api/tests/unit_tests/core/rag/indexing/test_index_processor_base.py index b31bb6eea7..12c5238f5e 100644 --- a/api/tests/unit_tests/core/rag/indexing/test_index_processor_base.py +++ b/api/tests/unit_tests/core/rag/indexing/test_index_processor_base.py @@ -133,10 +133,10 @@ class TestBaseIndexProcessor: upload_b = SimpleNamespace(id="bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", name="b.png") upload_tool = SimpleNamespace(id="tool-upload-id", name="tool.png") upload_remote = SimpleNamespace(id="remote-upload-id", name="remote.png") - db_query = Mock() - db_query.where.return_value.all.return_value = [upload_a, upload_b, upload_tool, upload_remote] + scalars_result = Mock() + scalars_result.all.return_value = [upload_a, upload_b, upload_tool, upload_remote] db_session = Mock() - db_session.query.return_value = db_query + db_session.scalars.return_value = scalars_result with ( patch.object(processor, "_extract_markdown_images", return_value=images), @@ -170,10 +170,10 @@ class TestBaseIndexProcessor: def test_get_content_files_ignores_missing_upload_records(self, processor: _ForwardingBaseIndexProcessor) -> None: document = Document(page_content="ignored", metadata={"document_id": "doc-1", "dataset_id": "ds-1"}) images = ["/files/aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa/image-preview"] - db_query = Mock() - db_query.where.return_value.all.return_value = [] + scalars_result = Mock() + scalars_result.all.return_value = [] db_session = Mock() - db_session.query.return_value = db_query + db_session.scalars.return_value = scalars_result with ( patch.object(processor, "_extract_markdown_images", return_value=images), @@ -259,20 +259,16 @@ class TestBaseIndexProcessor: assert processor._download_image("https://example.com/image.png", current_user=Mock()) is None def test_download_tool_file_returns_none_when_not_found(self, processor: _ForwardingBaseIndexProcessor) -> None: - db_query = Mock() - db_query.where.return_value.first.return_value = None db_session = Mock() - db_session.query.return_value = db_query + db_session.get.return_value = None with patch("core.rag.index_processor.index_processor_base.db.session", db_session): assert processor._download_tool_file("tool-id", current_user=Mock()) is None def test_download_tool_file_uploads_file_when_found(self, processor: _ForwardingBaseIndexProcessor) -> None: tool_file = SimpleNamespace(file_key="k1", name="tool.png", mimetype="image/png") - db_query = Mock() - db_query.where.return_value.first.return_value = tool_file db_session = Mock() - db_session.query.return_value = db_query + db_session.get.return_value = tool_file mock_db = Mock() mock_db.session = db_session mock_db.engine = Mock() diff --git a/api/tests/unit_tests/core/rag/rerank/test_reranker.py b/api/tests/unit_tests/core/rag/rerank/test_reranker.py index 2ec7f0498e..c279b00d3b 100644 --- a/api/tests/unit_tests/core/rag/rerank/test_reranker.py +++ b/api/tests/unit_tests/core/rag/rerank/test_reranker.py @@ -473,12 +473,10 @@ class TestRerankModelRunnerMultimodal: metadata={}, provider="external", ) - query = Mock() - query.where.return_value.first.return_value = SimpleNamespace(key="image-key") rerank_result = RerankResult(model="rerank-model", docs=[]) with ( - patch("core.rag.rerank.rerank_model.db.session.query", return_value=query), + patch("core.rag.rerank.rerank_model.db.session.get", return_value=SimpleNamespace(key="image-key")), patch("core.rag.rerank.rerank_model.storage.load_once", return_value=b"image-bytes") as mock_load_once, patch.object( rerank_runner, @@ -504,12 +502,10 @@ class TestRerankModelRunnerMultimodal: metadata={"doc_id": "img-missing", "doc_type": DocType.IMAGE}, provider="dify", ) - query = Mock() - query.where.return_value.first.return_value = None rerank_result = RerankResult(model="rerank-model", docs=[]) with ( - patch("core.rag.rerank.rerank_model.db.session.query", return_value=query), + patch("core.rag.rerank.rerank_model.db.session.get", return_value=None), patch.object( rerank_runner, "fetch_text_rerank", @@ -533,8 +529,6 @@ class TestRerankModelRunnerMultimodal: metadata={"doc_id": "txt-1", "doc_type": DocType.TEXT}, provider="dify", ) - query_chain = Mock() - query_chain.where.return_value.first.return_value = SimpleNamespace(key="query-image-key") rerank_result = RerankResult( model="rerank-model", docs=[RerankDocument(index=0, text="text-content", score=0.77)], @@ -542,7 +536,7 @@ class TestRerankModelRunnerMultimodal: mock_model_instance.invoke_multimodal_rerank.return_value = rerank_result session = MagicMock() - session.query.return_value = query_chain + session.get.return_value = SimpleNamespace(key="query-image-key") with ( patch("core.rag.rerank.rerank_model.db.session", session), patch("core.rag.rerank.rerank_model.storage.load_once", return_value=b"query-image-bytes"), @@ -563,10 +557,7 @@ class TestRerankModelRunnerMultimodal: assert "user" not in invoke_kwargs def test_fetch_multimodal_rerank_raises_when_query_image_not_found(self, rerank_runner): - query_chain = Mock() - query_chain.where.return_value.first.return_value = None - - with patch("core.rag.rerank.rerank_model.db.session.query", return_value=query_chain): + with patch("core.rag.rerank.rerank_model.db.session.get", return_value=None): with pytest.raises(ValueError, match="Upload file not found for query"): rerank_runner.fetch_multimodal_rerank( query="missing-upload-id", diff --git a/api/tests/unit_tests/core/rag/retrieval/test_dataset_retrieval.py b/api/tests/unit_tests/core/rag/retrieval/test_dataset_retrieval.py index c11426163e..fee7b168ad 100644 --- a/api/tests/unit_tests/core/rag/retrieval/test_dataset_retrieval.py +++ b/api/tests/unit_tests/core/rag/retrieval/test_dataset_retrieval.py @@ -3971,11 +3971,10 @@ class TestDatasetRetrievalAdditionalHelpers: ) def test_get_metadata_filter_condition(self, retrieval: DatasetRetrieval) -> None: - db_query = Mock() - db_query.where.return_value = db_query - db_query.all.return_value = [SimpleNamespace(dataset_id="d1", id="doc-1")] + scalars_result = Mock() + scalars_result.all.return_value = [SimpleNamespace(dataset_id="d1", id="doc-1")] - with patch("core.rag.retrieval.dataset_retrieval.db.session.query", return_value=db_query): + with patch("core.rag.retrieval.dataset_retrieval.db.session.scalars", return_value=scalars_result): mapping, condition = retrieval.get_metadata_filter_condition( dataset_ids=["d1"], query="python", @@ -3991,7 +3990,7 @@ class TestDatasetRetrievalAdditionalHelpers: automatic_filters = [{"condition": "contains", "metadata_name": "author", "value": "Alice"}] with ( - patch("core.rag.retrieval.dataset_retrieval.db.session.query", return_value=db_query), + patch("core.rag.retrieval.dataset_retrieval.db.session.scalars", return_value=scalars_result), patch.object(retrieval, "_automatic_metadata_filter_func", return_value=automatic_filters), ): mapping, condition = retrieval.get_metadata_filter_condition( @@ -4012,7 +4011,7 @@ class TestDatasetRetrievalAdditionalHelpers: logical_operator="and", conditions=[AppCondition(name="author", comparison_operator="contains", value="{{name}}")], ) - with patch("core.rag.retrieval.dataset_retrieval.db.session.query", return_value=db_query): + with patch("core.rag.retrieval.dataset_retrieval.db.session.scalars", return_value=scalars_result): mapping, condition = retrieval.get_metadata_filter_condition( dataset_ids=["d1"], query="python", @@ -4027,7 +4026,7 @@ class TestDatasetRetrievalAdditionalHelpers: assert condition is not None assert condition.conditions[0].value == "Alice" - with patch("core.rag.retrieval.dataset_retrieval.db.session.query", return_value=db_query): + with patch("core.rag.retrieval.dataset_retrieval.db.session.scalars", return_value=scalars_result): with pytest.raises(ValueError, match="Invalid metadata filtering mode"): retrieval.get_metadata_filter_condition( dataset_ids=["d1"], From 944db46d4fc622c9cbbc6e2fb0ceb34c69911391 Mon Sep 17 00:00:00 2001 From: Dream <42954461+eureka928@users.noreply.github.com> Date: Mon, 30 Mar 2026 04:22:29 -0400 Subject: [PATCH 03/40] refactor(api): replace json.loads with Pydantic validation in services layer (#33704) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Asuka Minato --- .../datasets/rag_pipeline/datasource_auth.py | 7 ++-- .../console/workspace/tool_providers.py | 3 +- .../console/workspace/trigger_providers.py | 6 +-- api/services/account_service.py | 16 ++++++-- api/services/message_service.py | 10 +++-- api/services/model_load_balancing_service.py | 11 +++--- api/services/plugin/plugin_migration.py | 37 ++++++++++++------- .../restore_archived_workflow_run.py | 22 +++++++++-- api/services/tools/tools_transform_service.py | 10 +++-- .../trigger_subscription_builder_service.py | 18 ++++++--- api/services/workflow_service.py | 2 +- .../services/plugin/test_oauth_service.py | 17 +++++++++ .../test_restore_archived_workflow_run.py | 3 +- 13 files changed, 114 insertions(+), 48 deletions(-) diff --git a/api/controllers/console/datasets/rag_pipeline/datasource_auth.py b/api/controllers/console/datasets/rag_pipeline/datasource_auth.py index 1976a6bc8a..bdf83b991e 100644 --- a/api/controllers/console/datasets/rag_pipeline/datasource_auth.py +++ b/api/controllers/console/datasets/rag_pipeline/datasource_auth.py @@ -120,7 +120,8 @@ class DatasourceOAuthCallback(Resource): if context is None: raise Forbidden("Invalid context_id") - user_id, tenant_id = context.get("user_id"), context.get("tenant_id") + user_id: str = context["user_id"] + tenant_id: str = context["tenant_id"] datasource_provider_id = DatasourceProviderID(provider_id) plugin_id = datasource_provider_id.plugin_id datasource_provider_service = DatasourceProviderService() @@ -141,7 +142,7 @@ class DatasourceOAuthCallback(Resource): system_credentials=oauth_client_params, request=request, ) - credential_id = context.get("credential_id") + credential_id: str | None = context.get("credential_id") if credential_id: datasource_provider_service.reauthorize_datasource_oauth_provider( tenant_id=tenant_id, @@ -150,7 +151,7 @@ class DatasourceOAuthCallback(Resource): name=oauth_response.metadata.get("name") or None, expire_at=oauth_response.expires_at, credentials=dict(oauth_response.credentials), - credential_id=context.get("credential_id"), + credential_id=credential_id, ) else: datasource_provider_service.add_datasource_oauth_provider( diff --git a/api/controllers/console/workspace/tool_providers.py b/api/controllers/console/workspace/tool_providers.py index 02eb0adc94..80216915cd 100644 --- a/api/controllers/console/workspace/tool_providers.py +++ b/api/controllers/console/workspace/tool_providers.py @@ -832,7 +832,8 @@ class ToolOAuthCallback(Resource): tool_provider = ToolProviderID(provider) plugin_id = tool_provider.plugin_id provider_name = tool_provider.provider_name - user_id, tenant_id = context.get("user_id"), context.get("tenant_id") + user_id: str = context["user_id"] + tenant_id: str = context["tenant_id"] oauth_handler = OAuthHandler() oauth_client_params = BuiltinToolManageService.get_oauth_client(tenant_id, provider) diff --git a/api/controllers/console/workspace/trigger_providers.py b/api/controllers/console/workspace/trigger_providers.py index 265b6ecd9a..76d64cb97c 100644 --- a/api/controllers/console/workspace/trigger_providers.py +++ b/api/controllers/console/workspace/trigger_providers.py @@ -499,9 +499,9 @@ class TriggerOAuthCallbackApi(Resource): provider_id = TriggerProviderID(provider) plugin_id = provider_id.plugin_id provider_name = provider_id.provider_name - user_id = context.get("user_id") - tenant_id = context.get("tenant_id") - subscription_builder_id = context.get("subscription_builder_id") + user_id: str = context["user_id"] + tenant_id: str = context["tenant_id"] + subscription_builder_id: str = context["subscription_builder_id"] # Get OAuth client configuration oauth_client_params = TriggerProviderService.get_oauth_client( diff --git a/api/services/account_service.py b/api/services/account_service.py index bd520f54cf..cc8ef08857 100644 --- a/api/services/account_service.py +++ b/api/services/account_service.py @@ -7,9 +7,19 @@ from datetime import UTC, datetime, timedelta from hashlib import sha256 from typing import Any, cast -from pydantic import BaseModel +from pydantic import BaseModel, TypeAdapter from sqlalchemy import func, select from sqlalchemy.orm import Session +from typing_extensions import TypedDict + + +class InvitationData(TypedDict): + account_id: str + email: str + workspace_id: str + + +_invitation_adapter: TypeAdapter[InvitationData] = TypeAdapter(InvitationData) from werkzeug.exceptions import Unauthorized from configs import dify_config @@ -1571,7 +1581,7 @@ class RegisterService: @classmethod def get_invitation_by_token( cls, token: str, workspace_id: str | None = None, email: str | None = None - ) -> dict[str, str] | None: + ) -> InvitationData | None: if workspace_id is not None and email is not None: email_hash = sha256(email.encode()).hexdigest() cache_key = f"member_invite_token:{workspace_id}, {email_hash}:{token}" @@ -1590,7 +1600,7 @@ class RegisterService: if not data: return None - invitation: dict = json.loads(data) + invitation = _invitation_adapter.validate_json(data) return invitation @classmethod diff --git a/api/services/message_service.py b/api/services/message_service.py index e5389ef659..a04f9cbe01 100644 --- a/api/services/message_service.py +++ b/api/services/message_service.py @@ -1,8 +1,8 @@ -import json from collections.abc import Sequence from typing import Union from graphon.model_runtime.entities.model_entities import ModelType +from pydantic import TypeAdapter from sqlalchemy.orm import sessionmaker from core.app.apps.advanced_chat.app_config_manager import AdvancedChatAppConfigManager @@ -17,7 +17,7 @@ from extensions.ext_database import db from libs.infinite_scroll_pagination import InfiniteScrollPagination from models import Account from models.enums import FeedbackFromSource, FeedbackRating -from models.model import App, AppMode, AppModelConfig, EndUser, Message, MessageFeedback +from models.model import App, AppMode, AppModelConfig, AppModelConfigDict, EndUser, Message, MessageFeedback from repositories.execution_extra_content_repository import ExecutionExtraContentRepository from repositories.sqlalchemy_execution_extra_content_repository import ( SQLAlchemyExecutionExtraContentRepository, @@ -31,6 +31,8 @@ from services.errors.message import ( ) from services.workflow_service import WorkflowService +_app_model_config_adapter: TypeAdapter[AppModelConfigDict] = TypeAdapter(AppModelConfigDict) + def _create_execution_extra_content_repository() -> ExecutionExtraContentRepository: session_maker = sessionmaker(bind=db.engine, expire_on_commit=False) @@ -286,7 +288,9 @@ class MessageService: .first() ) else: - conversation_override_model_configs = json.loads(conversation.override_model_configs) + conversation_override_model_configs = _app_model_config_adapter.validate_json( + conversation.override_model_configs + ) app_model_config = AppModelConfig( app_id=app_model.id, ) diff --git a/api/services/model_load_balancing_service.py b/api/services/model_load_balancing_service.py index 91cca5cb6d..25de411e43 100644 --- a/api/services/model_load_balancing_service.py +++ b/api/services/model_load_balancing_service.py @@ -1,7 +1,6 @@ import json import logging -from json import JSONDecodeError -from typing import Union +from typing import Any, Union from graphon.model_runtime.entities.model_entities import ModelType from graphon.model_runtime.entities.provider_entities import ( @@ -168,10 +167,10 @@ class ModelLoadBalancingService: try: if load_balancing_config.encrypted_config: - credentials: dict[str, object] = json.loads(load_balancing_config.encrypted_config) + credentials: dict[str, Any] = json.loads(load_balancing_config.encrypted_config) else: credentials = {} - except JSONDecodeError: + except (json.JSONDecodeError, ValueError): credentials = {} # Get provider credential secret variables @@ -256,7 +255,7 @@ class ModelLoadBalancingService: credentials = json.loads(load_balancing_model_config.encrypted_config) else: credentials = {} - except JSONDecodeError: + except (json.JSONDecodeError, ValueError): credentials = {} # Get credential form schemas from model credential schema or provider credential schema @@ -575,7 +574,7 @@ class ModelLoadBalancingService: original_credentials = json.loads(load_balancing_model_config.encrypted_config) else: original_credentials = {} - except JSONDecodeError: + except (json.JSONDecodeError, ValueError): original_credentials = {} # encrypt credentials diff --git a/api/services/plugin/plugin_migration.py b/api/services/plugin/plugin_migration.py index df5fa3e233..1562d4e696 100644 --- a/api/services/plugin/plugin_migration.py +++ b/api/services/plugin/plugin_migration.py @@ -12,7 +12,9 @@ import click import sqlalchemy as sa import tqdm from flask import Flask, current_app +from pydantic import TypeAdapter from sqlalchemy.orm import Session +from typing_extensions import TypedDict from core.agent.entities import AgentToolEntity from core.helper import marketplace @@ -33,6 +35,14 @@ logger = logging.getLogger(__name__) excluded_providers = ["time", "audio", "code", "webscraper"] +class _TenantPluginRecord(TypedDict): + tenant_id: str + plugins: list[str] + + +_tenant_plugin_adapter: TypeAdapter[_TenantPluginRecord] = TypeAdapter(_TenantPluginRecord) + + class PluginMigration: @classmethod def extract_plugins(cls, filepath: str, workers: int): @@ -308,9 +318,8 @@ class PluginMigration: logger.info("Extracting unique plugins from %s", extracted_plugins) with open(extracted_plugins) as f: for line in f: - data = json.loads(line) - new_plugin_ids = data.get("plugins", []) - for plugin_id in new_plugin_ids: + data = _tenant_plugin_adapter.validate_json(line) + for plugin_id in data["plugins"]: if plugin_id not in plugin_ids: plugin_ids.append(plugin_id) @@ -381,21 +390,23 @@ class PluginMigration: Read line by line, and install plugins for each tenant. """ for line in f: - data = json.loads(line) - tenant_id = data.get("tenant_id") - plugin_ids = data.get("plugins", []) - current_not_installed = { - "tenant_id": tenant_id, - "plugin_not_exist": [], - } + data = _tenant_plugin_adapter.validate_json(line) + tenant_id = data["tenant_id"] + plugin_ids = data["plugins"] + plugin_not_exist: list[str] = [] # get plugin unique identifier for plugin_id in plugin_ids: unique_identifier = plugins.get(plugin_id) if unique_identifier: - current_not_installed["plugin_not_exist"].append(plugin_id) + plugin_not_exist.append(plugin_id) - if current_not_installed["plugin_not_exist"]: - not_installed.append(current_not_installed) + if plugin_not_exist: + not_installed.append( + { + "tenant_id": tenant_id, + "plugin_not_exist": plugin_not_exist, + } + ) thread_pool.submit(install, tenant_id, plugin_ids) diff --git a/api/services/retention/workflow_run/restore_archived_workflow_run.py b/api/services/retention/workflow_run/restore_archived_workflow_run.py index 64dad7ba52..c8362738ee 100644 --- a/api/services/retention/workflow_run/restore_archived_workflow_run.py +++ b/api/services/retention/workflow_run/restore_archived_workflow_run.py @@ -6,7 +6,6 @@ back to the database. """ import io -import json import logging import time import zipfile @@ -17,8 +16,23 @@ from datetime import datetime from typing import Any, cast import click +from pydantic import TypeAdapter from sqlalchemy.dialects.postgresql import insert as pg_insert from sqlalchemy.engine import CursorResult +from typing_extensions import TypedDict + + +class _TableInfo(TypedDict, total=False): + row_count: int + + +class ArchiveManifest(TypedDict, total=False): + tables: dict[str, _TableInfo] + schema_version: str + + +_manifest_adapter: TypeAdapter[ArchiveManifest] = TypeAdapter(ArchiveManifest) + from sqlalchemy.orm import DeclarativeBase, Session, sessionmaker from extensions.ext_database import db @@ -239,12 +253,12 @@ class WorkflowRunRestore: return self.workflow_run_repo @staticmethod - def _load_manifest_from_zip(archive: zipfile.ZipFile) -> dict[str, Any]: + def _load_manifest_from_zip(archive: zipfile.ZipFile) -> ArchiveManifest: try: data = archive.read("manifest.json") except KeyError as e: raise ValueError("manifest.json missing from archive bundle") from e - return json.loads(data.decode("utf-8")) + return _manifest_adapter.validate_json(data) def _restore_table_records( self, @@ -332,7 +346,7 @@ class WorkflowRunRestore: return result - def _get_schema_version(self, manifest: dict[str, Any]) -> str: + def _get_schema_version(self, manifest: ArchiveManifest) -> str: schema_version = manifest.get("schema_version") if not schema_version: logger.warning("Manifest missing schema_version; defaulting to 1.0") diff --git a/api/services/tools/tools_transform_service.py b/api/services/tools/tools_transform_service.py index b276146066..7cd61e3162 100644 --- a/api/services/tools/tools_transform_service.py +++ b/api/services/tools/tools_transform_service.py @@ -3,7 +3,7 @@ import logging from collections.abc import Mapping from typing import Any, Union -from pydantic import ValidationError +from pydantic import TypeAdapter, ValidationError from yarl import URL from configs import dify_config @@ -31,6 +31,8 @@ from services.plugin.plugin_service import PluginService logger = logging.getLogger(__name__) +_mcp_tools_adapter: TypeAdapter[list[MCPTool]] = TypeAdapter(list[MCPTool]) + class ToolTransformService: _MCP_SCHEMA_TYPE_RESOLUTION_MAX_DEPTH = 10 @@ -53,7 +55,7 @@ class ToolTransformService: if isinstance(icon, str): return json.loads(icon) return icon - except Exception: + except (json.JSONDecodeError, ValueError): return {"background": "#252525", "content": "\ud83d\ude01"} elif provider_type == ToolProviderType.MCP: return icon @@ -247,8 +249,8 @@ class ToolTransformService: response = provider_entity.to_api_response(user_name=user_name, include_sensitive=include_sensitive) try: - mcp_tools = [MCPTool(**tool) for tool in json.loads(db_provider.tools)] - except (ValidationError, json.JSONDecodeError): + mcp_tools = _mcp_tools_adapter.validate_json(db_provider.tools) + except (ValidationError, ValueError): mcp_tools = [] # Add additional fields specific to the transform response["id"] = db_provider.server_identifier if not for_list else db_provider.id diff --git a/api/services/trigger/trigger_subscription_builder_service.py b/api/services/trigger/trigger_subscription_builder_service.py index 37f852da3e..889717df72 100644 --- a/api/services/trigger/trigger_subscription_builder_service.py +++ b/api/services/trigger/trigger_subscription_builder_service.py @@ -1,4 +1,3 @@ -import json import logging import uuid from collections.abc import Mapping @@ -7,6 +6,7 @@ from datetime import datetime from typing import Any from flask import Request, Response +from pydantic import TypeAdapter from core.plugin.entities.plugin_daemon import CredentialType from core.plugin.entities.request import TriggerDispatchResponse @@ -29,6 +29,8 @@ from services.trigger.trigger_provider_service import TriggerProviderService logger = logging.getLogger(__name__) +_request_logs_adapter: TypeAdapter[list[RequestLog]] = TypeAdapter(list[RequestLog]) + class TriggerSubscriptionBuilderService: """Service for managing trigger providers and credentials""" @@ -398,7 +400,7 @@ class TriggerSubscriptionBuilderService: cache_key = cls.encode_cache_key(endpoint_id) subscription_cache = redis_client.get(cache_key) if subscription_cache: - return SubscriptionBuilder.model_validate(json.loads(subscription_cache)) + return SubscriptionBuilder.model_validate_json(subscription_cache) return None @@ -423,12 +425,16 @@ class TriggerSubscriptionBuilderService: ) key = f"trigger:subscription:builder:logs:{endpoint_id}" - logs = json.loads(redis_client.get(key) or "[]") - logs.append(log.model_dump(mode="json")) + logs = _request_logs_adapter.validate_json(redis_client.get(key) or b"[]") + logs.append(log) # Keep last N logs logs = logs[-cls.__VALIDATION_REQUEST_CACHE_COUNT__ :] - redis_client.setex(key, cls.__VALIDATION_REQUEST_CACHE_EXPIRE_SECONDS__, json.dumps(logs, default=str)) + redis_client.setex( + key, + cls.__VALIDATION_REQUEST_CACHE_EXPIRE_SECONDS__, + _request_logs_adapter.dump_json(logs), + ) @classmethod def list_logs(cls, endpoint_id: str) -> list[RequestLog]: @@ -437,7 +443,7 @@ class TriggerSubscriptionBuilderService: logs_json = redis_client.get(key) if not logs_json: return [] - return [RequestLog.model_validate(log) for log in json.loads(logs_json)] + return _request_logs_adapter.validate_json(logs_json) @classmethod def process_builder_validation_endpoint(cls, endpoint_id: str, request: Request) -> Response | None: diff --git a/api/services/workflow_service.py b/api/services/workflow_service.py index b555676704..3b3ee6dd92 100644 --- a/api/services/workflow_service.py +++ b/api/services/workflow_service.py @@ -1118,7 +1118,7 @@ class WorkflowService: continue try: payload = json.loads(recipient.recipient_payload) - except Exception: + except (json.JSONDecodeError, ValueError): logger.exception("Failed to parse human input recipient payload for delivery test.") continue email = payload.get("email") diff --git a/api/tests/unit_tests/services/plugin/test_oauth_service.py b/api/tests/unit_tests/services/plugin/test_oauth_service.py index 6511385000..eee65b3a18 100644 --- a/api/tests/unit_tests/services/plugin/test_oauth_service.py +++ b/api/tests/unit_tests/services/plugin/test_oauth_service.py @@ -93,3 +93,20 @@ class TestUseProxyContext: assert result == stored expected_key = "oauth_proxy_context:valid-id" redis_client.delete.assert_called_once_with(expected_key) + + def test_returns_context_with_credential_id(self): + from extensions.ext_redis import redis_client + + stored = { + "user_id": "u1", + "tenant_id": "t1", + "plugin_id": "p1", + "provider": "github", + "credential_id": "cred-42", + } + redis_client.get.return_value = json.dumps(stored).encode() + + result = OAuthProxyService.use_proxy_context("ctx-with-cred") + + assert result["credential_id"] == "cred-42" + assert result["tenant_id"] == "t1" diff --git a/api/tests/unit_tests/services/retention/workflow_run/test_restore_archived_workflow_run.py b/api/tests/unit_tests/services/retention/workflow_run/test_restore_archived_workflow_run.py index 4bfdba87a0..628e4e594d 100644 --- a/api/tests/unit_tests/services/retention/workflow_run/test_restore_archived_workflow_run.py +++ b/api/tests/unit_tests/services/retention/workflow_run/test_restore_archived_workflow_run.py @@ -13,6 +13,7 @@ from datetime import datetime from unittest.mock import Mock, create_autospec, patch import pytest +from pydantic import ValidationError from sqlalchemy import Column, Integer, MetaData, String, Table from libs.archive_storage import ArchiveStorageNotConfiguredError @@ -292,7 +293,7 @@ class TestLoadManifestFromZip: zip_buffer.seek(0) with zipfile.ZipFile(zip_buffer, "r") as archive: - with pytest.raises(json.JSONDecodeError): + with pytest.raises(ValidationError): WorkflowRunRestore._load_manifest_from_zip(archive) From 1aaba80211d85cc801f1d4dc2043df9034555359 Mon Sep 17 00:00:00 2001 From: jigangz <115519042+jigangz@users.noreply.github.com> Date: Mon, 30 Mar 2026 03:09:50 -0700 Subject: [PATCH 04/40] fix: enrich Service API segment responses with summary content (#34221) Co-authored-by: jigangz Co-authored-by: FFXN <31929997+FFXN@users.noreply.github.com> --- .../service_api/dataset/segment.py | 33 ++++++++-- .../dataset/test_dataset_segment.py | 65 ++++++++++++++++++- 2 files changed, 92 insertions(+), 6 deletions(-) diff --git a/api/controllers/service_api/dataset/segment.py b/api/controllers/service_api/dataset/segment.py index b4cc9874b6..5b16da81e0 100644 --- a/api/controllers/service_api/dataset/segment.py +++ b/api/controllers/service_api/dataset/segment.py @@ -29,6 +29,31 @@ from services.entities.knowledge_entities.knowledge_entities import SegmentUpdat from services.errors.chunk import ChildChunkDeleteIndexError, ChildChunkIndexingError from services.errors.chunk import ChildChunkDeleteIndexError as ChildChunkDeleteIndexServiceError from services.errors.chunk import ChildChunkIndexingError as ChildChunkIndexingServiceError +from services.summary_index_service import SummaryIndexService + + +def _marshal_segment_with_summary(segment, dataset_id: str) -> dict: + """Marshal a single segment and enrich it with summary content.""" + segment_dict = dict(marshal(segment, segment_fields)) # type: ignore[arg-type] + summary = SummaryIndexService.get_segment_summary(segment_id=segment.id, dataset_id=dataset_id) + segment_dict["summary"] = summary.summary_content if summary else None + return segment_dict + + +def _marshal_segments_with_summary(segments, dataset_id: str) -> list[dict]: + """Marshal multiple segments and enrich them with summary content (batch query).""" + segment_ids = [segment.id for segment in segments] + summaries: dict = {} + if segment_ids: + summary_records = SummaryIndexService.get_segments_summaries(segment_ids=segment_ids, dataset_id=dataset_id) + summaries = {chunk_id: record.summary_content for chunk_id, record in summary_records.items()} + + result = [] + for segment in segments: + segment_dict = dict(marshal(segment, segment_fields)) # type: ignore[arg-type] + segment_dict["summary"] = summaries.get(segment.id) + result.append(segment_dict) + return result class SegmentCreatePayload(BaseModel): @@ -132,7 +157,7 @@ class SegmentApi(DatasetApiResource): for args_item in payload.segments: SegmentService.segment_create_args_validate(args_item, document) segments = SegmentService.multi_create_segment(payload.segments, document, dataset) - return {"data": marshal(segments, segment_fields), "doc_form": document.doc_form}, 200 + return {"data": _marshal_segments_with_summary(segments, dataset_id), "doc_form": document.doc_form}, 200 else: return {"error": "Segments is required"}, 400 @@ -196,7 +221,7 @@ class SegmentApi(DatasetApiResource): ) response = { - "data": marshal(segments, segment_fields), + "data": _marshal_segments_with_summary(segments, dataset_id), "doc_form": document.doc_form, "total": total, "has_more": len(segments) == limit, @@ -296,7 +321,7 @@ class DatasetSegmentApi(DatasetApiResource): payload = SegmentUpdatePayload.model_validate(service_api_ns.payload or {}) updated_segment = SegmentService.update_segment(payload.segment, segment, document, dataset) - return {"data": marshal(updated_segment, segment_fields), "doc_form": document.doc_form}, 200 + return {"data": _marshal_segment_with_summary(updated_segment, dataset_id), "doc_form": document.doc_form}, 200 @service_api_ns.doc("get_segment") @service_api_ns.doc(description="Get a specific segment by ID") @@ -326,7 +351,7 @@ class DatasetSegmentApi(DatasetApiResource): if not segment: raise NotFound("Segment not found.") - return {"data": marshal(segment, segment_fields), "doc_form": document.doc_form}, 200 + return {"data": _marshal_segment_with_summary(segment, dataset_id), "doc_form": document.doc_form}, 200 @service_api_ns.route( diff --git a/api/tests/unit_tests/controllers/service_api/dataset/test_dataset_segment.py b/api/tests/unit_tests/controllers/service_api/dataset/test_dataset_segment.py index 7f5d6b0839..e9c3e6d376 100644 --- a/api/tests/unit_tests/controllers/service_api/dataset/test_dataset_segment.py +++ b/api/tests/unit_tests/controllers/service_api/dataset/test_dataset_segment.py @@ -768,6 +768,7 @@ class TestSegmentApiGet: ``current_account_with_tenant()`` and ``marshal``. """ + @patch("controllers.service_api.dataset.segment.SummaryIndexService") @patch("controllers.service_api.dataset.segment.marshal") @patch("controllers.service_api.dataset.segment.SegmentService") @patch("controllers.service_api.dataset.segment.DocumentService") @@ -780,6 +781,7 @@ class TestSegmentApiGet: mock_doc_svc, mock_seg_svc, mock_marshal, + mock_summary_svc, app, mock_tenant, mock_dataset, @@ -791,7 +793,8 @@ class TestSegmentApiGet: mock_db.session.scalar.return_value = mock_dataset mock_doc_svc.get_document.return_value = Mock(doc_form=IndexStructureType.PARAGRAPH_INDEX) mock_seg_svc.get_segments.return_value = ([mock_segment], 1) - mock_marshal.return_value = [{"id": mock_segment.id}] + mock_marshal.return_value = {"id": mock_segment.id} + mock_summary_svc.get_segments_summaries.return_value = {} # Act with app.test_request_context( @@ -872,6 +875,7 @@ class TestSegmentApiPost: mock_rate_limit.enabled = False mock_feature_svc.get_knowledge_rate_limit.return_value = mock_rate_limit + @patch("controllers.service_api.dataset.segment.SummaryIndexService") @patch("controllers.service_api.dataset.segment.marshal") @patch("controllers.service_api.dataset.segment.SegmentService") @patch("controllers.service_api.dataset.segment.DocumentService") @@ -888,6 +892,7 @@ class TestSegmentApiPost: mock_doc_svc, mock_seg_svc, mock_marshal, + mock_summary_svc, app, mock_tenant, mock_dataset, @@ -909,7 +914,8 @@ class TestSegmentApiPost: mock_seg_svc.segment_create_args_validate.return_value = None mock_seg_svc.multi_create_segment.return_value = [mock_segment] - mock_marshal.return_value = [{"id": mock_segment.id}] + mock_marshal.return_value = {"id": mock_segment.id} + mock_summary_svc.get_segments_summaries.return_value = {} segments_data = [{"content": "Test segment content", "answer": "Test answer"}] @@ -1206,6 +1212,7 @@ class TestDatasetSegmentApiUpdate: mock_rate_limit.enabled = False mock_feature_svc.get_knowledge_rate_limit.return_value = mock_rate_limit + @patch("controllers.service_api.dataset.segment.SummaryIndexService") @patch("controllers.service_api.dataset.segment.marshal") @patch("controllers.service_api.dataset.segment.SegmentService") @patch("controllers.service_api.dataset.segment.DocumentService") @@ -1224,6 +1231,7 @@ class TestDatasetSegmentApiUpdate: mock_doc_svc, mock_seg_svc, mock_marshal, + mock_summary_svc, app, mock_tenant, mock_dataset, @@ -1240,6 +1248,7 @@ class TestDatasetSegmentApiUpdate: updated = Mock() mock_seg_svc.update_segment.return_value = updated mock_marshal.return_value = {"id": mock_segment.id} + mock_summary_svc.get_segment_summary.return_value = None with app.test_request_context( f"/datasets/{mock_dataset.id}/documents/doc-id/segments/{mock_segment.id}", @@ -1349,6 +1358,7 @@ class TestDatasetSegmentApiGetSingle: ``current_account_with_tenant()`` and ``marshal``. """ + @patch("controllers.service_api.dataset.segment.SummaryIndexService") @patch("controllers.service_api.dataset.segment.marshal") @patch("controllers.service_api.dataset.segment.SegmentService") @patch("controllers.service_api.dataset.segment.DocumentService") @@ -1363,6 +1373,7 @@ class TestDatasetSegmentApiGetSingle: mock_doc_svc, mock_seg_svc, mock_marshal, + mock_summary_svc, app, mock_tenant, mock_dataset, @@ -1376,6 +1387,7 @@ class TestDatasetSegmentApiGetSingle: mock_doc_svc.get_document.return_value = mock_doc mock_seg_svc.get_segment_by_id.return_value = mock_segment mock_marshal.return_value = {"id": mock_segment.id} + mock_summary_svc.get_segment_summary.return_value = None with app.test_request_context( f"/datasets/{mock_dataset.id}/documents/doc-id/segments/{mock_segment.id}", @@ -1393,6 +1405,55 @@ class TestDatasetSegmentApiGetSingle: assert "data" in response assert response["doc_form"] == IndexStructureType.PARAGRAPH_INDEX + @patch("controllers.service_api.dataset.segment.SummaryIndexService") + @patch("controllers.service_api.dataset.segment.marshal") + @patch("controllers.service_api.dataset.segment.SegmentService") + @patch("controllers.service_api.dataset.segment.DocumentService") + @patch("controllers.service_api.dataset.segment.DatasetService") + @patch("controllers.service_api.dataset.segment.current_account_with_tenant") + @patch("controllers.service_api.dataset.segment.db") + def test_get_single_segment_includes_summary( + self, + mock_db, + mock_account_fn, + mock_dataset_svc, + mock_doc_svc, + mock_seg_svc, + mock_marshal, + mock_summary_svc, + app, + mock_tenant, + mock_dataset, + mock_segment, + ): + """Test that single segment response includes summary content from SummaryIndexService.""" + mock_account_fn.return_value = (Mock(), mock_tenant.id) + mock_db.session.scalar.return_value = mock_dataset + mock_dataset_svc.check_dataset_model_setting.return_value = None + mock_doc = Mock(doc_form=IndexStructureType.PARAGRAPH_INDEX) + mock_doc_svc.get_document.return_value = mock_doc + mock_seg_svc.get_segment_by_id.return_value = mock_segment + mock_marshal.return_value = {"id": mock_segment.id, "summary": None} + + mock_summary_record = Mock() + mock_summary_record.summary_content = "This is the segment summary" + mock_summary_svc.get_segment_summary.return_value = mock_summary_record + + with app.test_request_context( + f"/datasets/{mock_dataset.id}/documents/doc-id/segments/{mock_segment.id}", + method="GET", + ): + api = DatasetSegmentApi() + response, status = api.get( + tenant_id=mock_tenant.id, + dataset_id=mock_dataset.id, + document_id="doc-id", + segment_id=mock_segment.id, + ) + + assert status == 200 + assert response["data"]["summary"] == "This is the segment summary" + @patch("controllers.service_api.dataset.segment.current_account_with_tenant") @patch("controllers.service_api.dataset.segment.db") def test_get_single_segment_dataset_not_found( From 52a4bea88f45a30bc8c5a9fa3c031cb00a57be5a Mon Sep 17 00:00:00 2001 From: Stephen Zhou Date: Mon, 30 Mar 2026 18:34:50 +0800 Subject: [PATCH 05/40] refactor: introduce pnpm workspace (#34241) Co-authored-by: yyh Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- .github/actions/setup-web/action.yml | 1 - .github/workflows/autofix.yml | 4 + .github/workflows/build-push.yml | 30 +- .github/workflows/docker-build.yml | 30 +- .github/workflows/main-ci.yml | 8 + .github/workflows/style.yml | 8 +- .github/workflows/tool-test-sdks.yaml | 3 + .github/workflows/web-e2e.yml | 4 - .github/workflows/web-tests.yml | 31 - .gitignore | 3 +- web/.nvmrc => .nvmrc | 0 Makefile | 6 +- api/README.md | 2 + dev/setup | 3 +- dev/start-web | 4 +- e2e/AGENTS.md | 23 +- e2e/package.json | 22 +- e2e/pnpm-lock.yaml | 2632 --------- package.json | 11 + web/pnpm-lock.yaml => pnpm-lock.yaml | 4861 +++++++++++------ pnpm-workspace.yaml | 257 + sdks/nodejs-client/README.md | 4 + sdks/nodejs-client/package.json | 27 +- sdks/nodejs-client/pnpm-lock.yaml | 2255 -------- sdks/nodejs-client/pnpm-workspace.yaml | 2 - sdks/nodejs-client/scripts/publish.sh | 83 +- web/taze.config.js => taze.config.js | 1 + web/.dockerignore | 32 - web/Dockerfile | 24 +- web/Dockerfile.dockerignore | 34 + web/README.md | 34 +- .../config/config-audio.spec.tsx | 3 +- .../config/config-document.spec.tsx | 3 +- .../app/configuration/config/index.spec.tsx | 9 +- .../hooks/__tests__/use-dsl-drag-drop.spec.ts | 5 +- .../base/carousel/__tests__/index.spec.tsx | 38 +- .../upgrade-btn/__tests__/index.spec.tsx | 9 +- web/eslint.config.mjs | 1 + web/next.config.ts | 1 - web/package.json | 435 +- web/scripts/copy-and-start.mjs | 56 +- web/vitest.setup.ts | 3 + 42 files changed, 4060 insertions(+), 6942 deletions(-) rename web/.nvmrc => .nvmrc (100%) delete mode 100644 e2e/pnpm-lock.yaml create mode 100644 package.json rename web/pnpm-lock.yaml => pnpm-lock.yaml (77%) create mode 100644 pnpm-workspace.yaml delete mode 100644 sdks/nodejs-client/pnpm-lock.yaml delete mode 100644 sdks/nodejs-client/pnpm-workspace.yaml rename web/taze.config.js => taze.config.js (95%) delete mode 100644 web/.dockerignore create mode 100644 web/Dockerfile.dockerignore diff --git a/.github/actions/setup-web/action.yml b/.github/actions/setup-web/action.yml index 24af948732..673155bcf7 100644 --- a/.github/actions/setup-web/action.yml +++ b/.github/actions/setup-web/action.yml @@ -6,7 +6,6 @@ runs: - name: Setup Vite+ uses: voidzero-dev/setup-vp@20553a7a7429c429a74894104a2835d7fed28a72 # v1.3.0 with: - working-directory: web node-version-file: .nvmrc cache: true run-install: true diff --git a/.github/workflows/autofix.yml b/.github/workflows/autofix.yml index 0f89d32fdb..9648c34274 100644 --- a/.github/workflows/autofix.yml +++ b/.github/workflows/autofix.yml @@ -39,6 +39,10 @@ jobs: with: files: | web/** + package.json + pnpm-lock.yaml + pnpm-workspace.yaml + .nvmrc - name: Check api inputs if: github.event_name != 'merge_group' id: api-changes diff --git a/.github/workflows/build-push.yml b/.github/workflows/build-push.yml index 1ae8d44482..a23edc70e5 100644 --- a/.github/workflows/build-push.yml +++ b/.github/workflows/build-push.yml @@ -24,27 +24,39 @@ env: jobs: build: - runs-on: ${{ matrix.platform == 'linux/arm64' && 'arm64_runner' || 'ubuntu-latest' }} + runs-on: ${{ matrix.runs_on }} if: github.repository == 'langgenius/dify' strategy: matrix: include: - service_name: "build-api-amd64" image_name_env: "DIFY_API_IMAGE_NAME" - context: "api" + artifact_context: "api" + build_context: "{{defaultContext}}:api" + file: "Dockerfile" platform: linux/amd64 + runs_on: ubuntu-latest - service_name: "build-api-arm64" image_name_env: "DIFY_API_IMAGE_NAME" - context: "api" + artifact_context: "api" + build_context: "{{defaultContext}}:api" + file: "Dockerfile" platform: linux/arm64 + runs_on: ubuntu-24.04-arm - service_name: "build-web-amd64" image_name_env: "DIFY_WEB_IMAGE_NAME" - context: "web" + artifact_context: "web" + build_context: "{{defaultContext}}" + file: "web/Dockerfile" platform: linux/amd64 + runs_on: ubuntu-latest - service_name: "build-web-arm64" image_name_env: "DIFY_WEB_IMAGE_NAME" - context: "web" + artifact_context: "web" + build_context: "{{defaultContext}}" + file: "web/Dockerfile" platform: linux/arm64 + runs_on: ubuntu-24.04-arm steps: - name: Prepare @@ -58,9 +70,6 @@ jobs: username: ${{ env.DOCKERHUB_USER }} password: ${{ env.DOCKERHUB_TOKEN }} - - name: Set up QEMU - uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0 - - name: Set up Docker Buildx uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 @@ -74,7 +83,8 @@ jobs: id: build uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 with: - context: "{{defaultContext}}:${{ matrix.context }}" + context: ${{ matrix.build_context }} + file: ${{ matrix.file }} platforms: ${{ matrix.platform }} build-args: COMMIT_SHA=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }} labels: ${{ steps.meta.outputs.labels }} @@ -93,7 +103,7 @@ jobs: - name: Upload digest uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: - name: digests-${{ matrix.context }}-${{ env.PLATFORM_PAIR }} + name: digests-${{ matrix.artifact_context }}-${{ env.PLATFORM_PAIR }} path: /tmp/digests/* if-no-files-found: error retention-days: 1 diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 340b380dc9..cbeb1a3bb1 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -6,7 +6,12 @@ on: - "main" paths: - api/Dockerfile + - web/docker/** - web/Dockerfile + - package.json + - pnpm-lock.yaml + - pnpm-workspace.yaml + - .nvmrc concurrency: group: docker-build-${{ github.head_ref || github.run_id }} @@ -14,26 +19,31 @@ concurrency: jobs: build-docker: - runs-on: ubuntu-latest + runs-on: ${{ matrix.runs_on }} strategy: matrix: include: - service_name: "api-amd64" platform: linux/amd64 - context: "api" + runs_on: ubuntu-latest + context: "{{defaultContext}}:api" + file: "Dockerfile" - service_name: "api-arm64" platform: linux/arm64 - context: "api" + runs_on: ubuntu-24.04-arm + context: "{{defaultContext}}:api" + file: "Dockerfile" - service_name: "web-amd64" platform: linux/amd64 - context: "web" + runs_on: ubuntu-latest + context: "{{defaultContext}}" + file: "web/Dockerfile" - service_name: "web-arm64" platform: linux/arm64 - context: "web" + runs_on: ubuntu-24.04-arm + context: "{{defaultContext}}" + file: "web/Dockerfile" steps: - - name: Set up QEMU - uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0 - - name: Set up Docker Buildx uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 @@ -41,8 +51,8 @@ jobs: uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 with: push: false - context: "{{defaultContext}}:${{ matrix.context }}" - file: "${{ matrix.file }}" + context: ${{ matrix.context }} + file: ${{ matrix.file }} platforms: ${{ matrix.platform }} cache-from: type=gha cache-to: type=gha,mode=max diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index 2d96dae4da..104368d192 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -65,6 +65,10 @@ jobs: - 'docker/volumes/sandbox/conf/**' web: - 'web/**' + - 'package.json' + - 'pnpm-lock.yaml' + - 'pnpm-workspace.yaml' + - '.nvmrc' - '.github/workflows/web-tests.yml' - '.github/actions/setup-web/**' e2e: @@ -73,6 +77,10 @@ jobs: - 'api/uv.lock' - 'e2e/**' - 'web/**' + - 'package.json' + - 'pnpm-lock.yaml' + - 'pnpm-workspace.yaml' + - '.nvmrc' - 'docker/docker-compose.middleware.yaml' - 'docker/middleware.env.example' - '.github/workflows/web-e2e.yml' diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml index a7432ae167..9bc4ceaa93 100644 --- a/.github/workflows/style.yml +++ b/.github/workflows/style.yml @@ -77,6 +77,10 @@ jobs: with: files: | web/** + package.json + pnpm-lock.yaml + pnpm-workspace.yaml + .nvmrc .github/workflows/style.yml .github/actions/setup-web/** @@ -90,9 +94,9 @@ jobs: uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: web/.eslintcache - key: ${{ runner.os }}-web-eslint-${{ hashFiles('web/package.json', 'web/pnpm-lock.yaml', 'web/eslint.config.mjs', 'web/eslint.constants.mjs', 'web/plugins/eslint/**') }}-${{ github.sha }} + key: ${{ runner.os }}-web-eslint-${{ hashFiles('web/package.json', 'pnpm-lock.yaml', 'web/eslint.config.mjs', 'web/eslint.constants.mjs', 'web/plugins/eslint/**') }}-${{ github.sha }} restore-keys: | - ${{ runner.os }}-web-eslint-${{ hashFiles('web/package.json', 'web/pnpm-lock.yaml', 'web/eslint.config.mjs', 'web/eslint.constants.mjs', 'web/plugins/eslint/**') }}- + ${{ runner.os }}-web-eslint-${{ hashFiles('web/package.json', 'pnpm-lock.yaml', 'web/eslint.config.mjs', 'web/eslint.constants.mjs', 'web/plugins/eslint/**') }}- - name: Web style check if: steps.changed-files.outputs.any_changed == 'true' diff --git a/.github/workflows/tool-test-sdks.yaml b/.github/workflows/tool-test-sdks.yaml index 3fc351c0c2..536a52b560 100644 --- a/.github/workflows/tool-test-sdks.yaml +++ b/.github/workflows/tool-test-sdks.yaml @@ -6,6 +6,9 @@ on: - main paths: - sdks/** + - package.json + - pnpm-lock.yaml + - pnpm-workspace.yaml concurrency: group: sdk-tests-${{ github.head_ref || github.run_id }} diff --git a/.github/workflows/web-e2e.yml b/.github/workflows/web-e2e.yml index ec8e1ce4e3..eb752619be 100644 --- a/.github/workflows/web-e2e.yml +++ b/.github/workflows/web-e2e.yml @@ -27,10 +27,6 @@ jobs: - name: Setup web dependencies uses: ./.github/actions/setup-web - - name: Install E2E package dependencies - working-directory: ./e2e - run: vp install --frozen-lockfile - - name: Setup UV and Python uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: diff --git a/.github/workflows/web-tests.yml b/.github/workflows/web-tests.yml index 9ce1156d87..3c36335e79 100644 --- a/.github/workflows/web-tests.yml +++ b/.github/workflows/web-tests.yml @@ -89,34 +89,3 @@ jobs: flags: web env: CODECOV_TOKEN: ${{ env.CODECOV_TOKEN }} - - web-build: - name: Web Build - runs-on: ubuntu-latest - defaults: - run: - working-directory: ./web - - steps: - - name: Checkout code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - persist-credentials: false - - - name: Check changed files - id: changed-files - uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 - with: - files: | - web/** - .github/workflows/web-tests.yml - .github/actions/setup-web/** - - - name: Setup web environment - if: steps.changed-files.outputs.any_changed == 'true' - uses: ./.github/actions/setup-web - - - name: Web build check - if: steps.changed-files.outputs.any_changed == 'true' - working-directory: ./web - run: vp run build diff --git a/.gitignore b/.gitignore index aaca9f2b0a..d7698fe3fd 100644 --- a/.gitignore +++ b/.gitignore @@ -212,6 +212,7 @@ api/.vscode # pnpm /.pnpm-store +/node_modules # plugin migrate plugins.jsonl @@ -239,4 +240,4 @@ scripts/stress-test/reports/ *.local.md # Code Agent Folder -.qoder/* \ No newline at end of file +.qoder/* diff --git a/web/.nvmrc b/.nvmrc similarity index 100% rename from web/.nvmrc rename to .nvmrc diff --git a/Makefile b/Makefile index c377b7c671..d8c9df5208 100644 --- a/Makefile +++ b/Makefile @@ -24,8 +24,8 @@ prepare-docker: # Step 2: Prepare web environment prepare-web: @echo "🌐 Setting up web environment..." - @cp -n web/.env.example web/.env 2>/dev/null || echo "Web .env already exists" - @cd web && pnpm install + @cp -n web/.env.example web/.env.local 2>/dev/null || echo "Web .env.local already exists" + @pnpm install @echo "✅ Web environment prepared (not started)" # Step 3: Prepare API environment @@ -93,7 +93,7 @@ test: # Build Docker images build-web: @echo "Building web Docker image: $(WEB_IMAGE):$(VERSION)..." - docker build -t $(WEB_IMAGE):$(VERSION) ./web + docker build -f web/Dockerfile -t $(WEB_IMAGE):$(VERSION) . @echo "Web Docker image built successfully: $(WEB_IMAGE):$(VERSION)" build-api: diff --git a/api/README.md b/api/README.md index b647367046..00562f3f78 100644 --- a/api/README.md +++ b/api/README.md @@ -40,6 +40,8 @@ The scripts resolve paths relative to their location, so you can run them from a ./dev/start-web ``` + `./dev/setup` and `./dev/start-web` install JavaScript dependencies through the repository root workspace, so you do not need a separate `cd web && pnpm install` step. + 1. Set up your application by visiting `http://localhost:3000`. 1. Start the worker service (async and scheduler tasks, runs from `api`). diff --git a/dev/setup b/dev/setup index 399c8f28a5..4236ff7fa7 100755 --- a/dev/setup +++ b/dev/setup @@ -24,5 +24,4 @@ cp "$MIDDLEWARE_ENV_EXAMPLE" "$MIDDLEWARE_ENV" cd "$ROOT/api" uv sync --group dev -cd "$ROOT/web" -pnpm install +pnpm --dir "$ROOT" install diff --git a/dev/start-web b/dev/start-web index f853f4a895..baf008274b 100755 --- a/dev/start-web +++ b/dev/start-web @@ -3,6 +3,6 @@ set -x SCRIPT_DIR="$(dirname "$(realpath "$0")")" -cd "$SCRIPT_DIR/../web" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" -pnpm install && pnpm dev:inspect +pnpm --dir "$ROOT_DIR" install && pnpm --dir "$ROOT_DIR/web" dev:inspect diff --git a/e2e/AGENTS.md b/e2e/AGENTS.md index 245c9863d4..ae642768f5 100644 --- a/e2e/AGENTS.md +++ b/e2e/AGENTS.md @@ -19,15 +19,18 @@ It tests: - `uv` - Docker +Run the following commands from the repository root. + Install Playwright browsers once: ```bash -cd e2e pnpm install -pnpm e2e:install -pnpm check +pnpm -C e2e e2e:install +pnpm -C e2e check ``` +`pnpm install` is resolved through the repository workspace and uses the shared root lockfile plus `pnpm-workspace.yaml`. + Use `pnpm check` as the default local verification step after editing E2E TypeScript, Cucumber support code, or feature glue. It runs formatting, linting, and type checks for this package. Common commands: @@ -35,20 +38,20 @@ Common commands: ```bash # authenticated-only regression (default excludes @fresh) # expects backend API, frontend artifact, and middleware stack to already be running -pnpm e2e +pnpm -C e2e e2e # full reset + fresh install + authenticated scenarios # starts required middleware/dependencies for you -pnpm e2e:full +pnpm -C e2e e2e:full # run a tagged subset -pnpm e2e -- --tags @smoke +pnpm -C e2e e2e -- --tags @smoke # headed browser -pnpm e2e:headed -- --tags @smoke +pnpm -C e2e e2e:headed -- --tags @smoke # slow down browser actions for local debugging -E2E_SLOW_MO=500 pnpm e2e:headed -- --tags @smoke +E2E_SLOW_MO=500 pnpm -C e2e e2e:headed -- --tags @smoke ``` Frontend artifact behavior: @@ -101,7 +104,7 @@ Because of that, the `@fresh` install scenario only runs in the `pnpm e2e:full*` Reset all persisted E2E state: ```bash -pnpm e2e:reset +pnpm -C e2e e2e:reset ``` This removes: @@ -117,7 +120,7 @@ This removes: Start the full middleware stack: ```bash -pnpm e2e:middleware:up +pnpm -C e2e e2e:middleware:up ``` Stop the full middleware stack: diff --git a/e2e/package.json b/e2e/package.json index 9b8a1f873f..0ee2afff7f 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -14,21 +14,11 @@ "e2e:reset": "tsx ./scripts/setup.ts reset" }, "devDependencies": { - "@cucumber/cucumber": "12.7.0", - "@playwright/test": "1.51.1", - "@types/node": "25.5.0", - "tsx": "4.21.0", - "typescript": "5.9.3", - "vite-plus": "latest" - }, - "engines": { - "node": "^22.22.1" - }, - "packageManager": "pnpm@10.32.1", - "pnpm": { - "overrides": { - "vite": "npm:@voidzero-dev/vite-plus-core@latest", - "vitest": "npm:@voidzero-dev/vite-plus-test@latest" - } + "@cucumber/cucumber": "catalog:", + "@playwright/test": "catalog:", + "@types/node": "catalog:", + "tsx": "catalog:", + "typescript": "catalog:", + "vite-plus": "catalog:" } } diff --git a/e2e/pnpm-lock.yaml b/e2e/pnpm-lock.yaml deleted file mode 100644 index b63458ad4a..0000000000 --- a/e2e/pnpm-lock.yaml +++ /dev/null @@ -1,2632 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -overrides: - vite: npm:@voidzero-dev/vite-plus-core@latest - vitest: npm:@voidzero-dev/vite-plus-test@latest - -importers: - - .: - devDependencies: - '@cucumber/cucumber': - specifier: 12.7.0 - version: 12.7.0 - '@playwright/test': - specifier: 1.51.1 - version: 1.51.1 - '@types/node': - specifier: 25.5.0 - version: 25.5.0 - tsx: - specifier: 4.21.0 - version: 4.21.0 - typescript: - specifier: 5.9.3 - version: 5.9.3 - vite-plus: - specifier: latest - version: 0.1.14(@types/node@25.5.0)(esbuild@0.27.4)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.3(@types/node@25.5.0)(esbuild@0.27.4)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) - -packages: - - '@babel/code-frame@7.29.0': - resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-identifier@7.28.5': - resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} - engines: {node: '>=6.9.0'} - - '@colors/colors@1.5.0': - resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} - engines: {node: '>=0.1.90'} - - '@cucumber/ci-environment@13.0.0': - resolution: {integrity: sha512-cs+3NzfNkGbcmHPddjEv4TKFiBpZRQ6WJEEufB9mw+ExS22V/4R/zpDSEG+fsJ/iSNCd6A2sATdY8PFOyY3YnA==} - - '@cucumber/cucumber-expressions@19.0.0': - resolution: {integrity: sha512-4FKoOQh2Uf6F6/Ln+1OxuK8LkTg6PyAqekhf2Ix8zqV2M54sH+m7XNJNLhOFOAW/t9nxzRbw2CcvXbCLjcvHZg==} - - '@cucumber/cucumber@12.7.0': - resolution: {integrity: sha512-7A/9CJpJDxv1SQ7hAZU0zPn2yRxx6XMR+LO4T94Enm3cYNWsEEj+RGX38NLX4INT+H6w5raX3Csb/qs4vUBsOA==} - engines: {node: 20 || 22 || >=24} - hasBin: true - - '@cucumber/gherkin-streams@6.0.0': - resolution: {integrity: sha512-HLSHMmdDH0vCr7vsVEURcDA4WwnRLdjkhqr6a4HQ3i4RFK1wiDGPjBGVdGJLyuXuRdJpJbFc6QxHvT8pU4t6jw==} - hasBin: true - peerDependencies: - '@cucumber/gherkin': '>=22.0.0' - '@cucumber/message-streams': '>=4.0.0' - '@cucumber/messages': '>=17.1.1' - - '@cucumber/gherkin-utils@11.0.0': - resolution: {integrity: sha512-LJ+s4+TepHTgdKWDR4zbPyT7rQjmYIcukTwNbwNwgqr6i8Gjcmzf6NmtbYDA19m1ZFg6kWbFsmHnj37ZuX+kZA==} - hasBin: true - - '@cucumber/gherkin@38.0.0': - resolution: {integrity: sha512-duEXK+KDfQUzu3vsSzXjkxQ2tirF5PRsc1Xrts6THKHJO6mjw4RjM8RV+vliuDasmhhrmdLcOcM7d9nurNTJKw==} - - '@cucumber/html-formatter@23.0.0': - resolution: {integrity: sha512-WwcRzdM8Ixy4e53j+Frm3fKM5rNuIyWUfy4HajEN+Xk/YcjA6yW0ACGTFDReB++VDZz/iUtwYdTlPRY36NbqJg==} - peerDependencies: - '@cucumber/messages': '>=18' - - '@cucumber/junit-xml-formatter@0.9.0': - resolution: {integrity: sha512-WF+A7pBaXpKMD1i7K59Nk5519zj4extxY4+4nSgv5XLsGXHDf1gJnb84BkLUzevNtp2o2QzMG0vWLwSm8V5blw==} - peerDependencies: - '@cucumber/messages': '*' - - '@cucumber/message-streams@4.0.1': - resolution: {integrity: sha512-Kxap9uP5jD8tHUZVjTWgzxemi/0uOsbGjd4LBOSxcJoOCRbESFwemUzilJuzNTB8pcTQUh8D5oudUyxfkJOKmA==} - peerDependencies: - '@cucumber/messages': '>=17.1.1' - - '@cucumber/messages@32.0.1': - resolution: {integrity: sha512-1OSoW+GQvFUNAl6tdP2CTBexTXMNJF0094goVUcvugtQeXtJ0K8sCP0xbq7GGoiezs/eJAAOD03+zAPT64orHQ==} - - '@cucumber/pretty-formatter@1.0.1': - resolution: {integrity: sha512-A1lU4VVP0aUWdOTmpdzvXOyEYuPtBDI0xYwYJnmoMDplzxMdhcHk86lyyvYDoMoPzzq6OkOE3isuosvUU4X7IQ==} - peerDependencies: - '@cucumber/cucumber': '>=7.0.0' - '@cucumber/messages': '*' - - '@cucumber/query@14.7.0': - resolution: {integrity: sha512-fiqZ4gMEgYjmbuWproF/YeCdD5y+gD2BqgBIGbpihOsx6UlNsyzoDSfO+Tny0q65DxfK+pHo2UkPyEl7dO7wmQ==} - peerDependencies: - '@cucumber/messages': '*' - - '@cucumber/tag-expressions@9.1.0': - resolution: {integrity: sha512-bvHjcRFZ+J1TqIa9eFNO1wGHqwx4V9ZKV3hYgkuK/VahHx73uiP4rKV3JVrvWSMrwrFvJG6C8aEwnCWSvbyFdQ==} - - '@emnapi/core@1.9.1': - resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==} - - '@emnapi/runtime@1.9.1': - resolution: {integrity: sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==} - - '@emnapi/wasi-threads@1.2.0': - resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} - - '@esbuild/aix-ppc64@0.27.4': - resolution: {integrity: sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.27.4': - resolution: {integrity: sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.27.4': - resolution: {integrity: sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.27.4': - resolution: {integrity: sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.27.4': - resolution: {integrity: sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.27.4': - resolution: {integrity: sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.27.4': - resolution: {integrity: sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.27.4': - resolution: {integrity: sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.27.4': - resolution: {integrity: sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.27.4': - resolution: {integrity: sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.27.4': - resolution: {integrity: sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.27.4': - resolution: {integrity: sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.27.4': - resolution: {integrity: sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.27.4': - resolution: {integrity: sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.27.4': - resolution: {integrity: sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.27.4': - resolution: {integrity: sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.27.4': - resolution: {integrity: sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-arm64@0.27.4': - resolution: {integrity: sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.27.4': - resolution: {integrity: sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.27.4': - resolution: {integrity: sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.27.4': - resolution: {integrity: sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openharmony-arm64@0.27.4': - resolution: {integrity: sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - - '@esbuild/sunos-x64@0.27.4': - resolution: {integrity: sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.27.4': - resolution: {integrity: sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.27.4': - resolution: {integrity: sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.27.4': - resolution: {integrity: sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - - '@napi-rs/wasm-runtime@1.1.1': - resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} - - '@oxc-project/runtime@0.121.0': - resolution: {integrity: sha512-p0bQukD8OEHxzY4T9OlANBbEFGnOnjo1CYi50HES7OD36UO2yPh6T+uOJKLtlg06eclxroipRCpQGMpeH8EJ/g==} - engines: {node: ^20.19.0 || >=22.12.0} - - '@oxc-project/types@0.122.0': - resolution: {integrity: sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==} - - '@oxfmt/binding-android-arm-eabi@0.42.0': - resolution: {integrity: sha512-dsqPTYsozeokRjlrt/b4E7Pj0z3eS3Eg74TWQuuKbjY4VttBmA88rB7d50Xrd+TZ986qdXCNeZRPEzZHAe+jow==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [android] - - '@oxfmt/binding-android-arm64@0.42.0': - resolution: {integrity: sha512-t+aAjHxcr5eOBphFHdg1ouQU9qmZZoRxnX7UOJSaTwSoKsb6TYezNKO0YbWytGXCECObRqNcUxPoPr0KaraAIg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] - - '@oxfmt/binding-darwin-arm64@0.42.0': - resolution: {integrity: sha512-ulpSEYMKg61C5bRMZinFHrKJYRoKGVbvMEXA5zM1puX3O9T6Q4XXDbft20yrDijpYWeuG59z3Nabt+npeTsM1A==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - - '@oxfmt/binding-darwin-x64@0.42.0': - resolution: {integrity: sha512-ttxLKhQYPdFiM8I/Ri37cvqChE4Xa562nNOsZFcv1CKTVLeEozXjKuYClNvxkXmNlcF55nzM80P+CQkdFBu+uQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - - '@oxfmt/binding-freebsd-x64@0.42.0': - resolution: {integrity: sha512-Og7QS3yI3tdIKYZ58SXik0rADxIk2jmd+/YvuHRyKULWpG4V2fR5V4hvKm624Mc0cQET35waPXiCQWvjQEjwYQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] - - '@oxfmt/binding-linux-arm-gnueabihf@0.42.0': - resolution: {integrity: sha512-jwLOw/3CW4H6Vxcry4/buQHk7zm9Ne2YsidzTL1kpiMe4qqrRCwev3dkyWe2YkFmP+iZCQ7zku4KwjcLRoh8ew==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@oxfmt/binding-linux-arm-musleabihf@0.42.0': - resolution: {integrity: sha512-XwXu2vkMtiq2h7tfvN+WA/9/5/1IoGAVCFPiiQUvcAuG3efR97KNcRGM8BetmbYouFotQ2bDal3yyjUx6IPsTg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@oxfmt/binding-linux-arm64-gnu@0.42.0': - resolution: {integrity: sha512-ea7s/XUJoT7ENAtUQDudFe3nkSM3e3Qpz4nJFRdzO2wbgXEcjnchKLEsV3+t4ev3r8nWxIYr9NRjPWtnyIFJVA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@oxfmt/binding-linux-arm64-musl@0.42.0': - resolution: {integrity: sha512-+JA0YMlSdDqmacygGi2REp57c3fN+tzARD8nwsukx9pkCHK+6DkbAA9ojS4lNKsiBjIW8WWa0pBrBWhdZEqfuw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@oxfmt/binding-linux-ppc64-gnu@0.42.0': - resolution: {integrity: sha512-VfnET0j4Y5mdfCzh5gBt0NK28lgn5DKx+8WgSMLYYeSooHhohdbzwAStLki9pNuGy51y4I7IoW8bqwAaCMiJQg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@oxfmt/binding-linux-riscv64-gnu@0.42.0': - resolution: {integrity: sha512-gVlCbmBkB0fxBWbhBj9rcxezPydsQHf4MFKeHoTSPicOQ+8oGeTQgQ8EeesSybWeiFPVRx3bgdt4IJnH6nOjAA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@oxfmt/binding-linux-riscv64-musl@0.42.0': - resolution: {integrity: sha512-zN5OfstL0avgt/IgvRu0zjQzVh/EPkcLzs33E9LMAzpqlLWiPWeMDZyMGFlSRGOdDjuNmlZBCgj0pFnK5u32TQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [riscv64] - os: [linux] - libc: [musl] - - '@oxfmt/binding-linux-s390x-gnu@0.42.0': - resolution: {integrity: sha512-9X6+H2L0qMc2sCAgO9HS03bkGLMKvOFjmEdchaFlany3vNZOjnVui//D8k/xZAtQv2vaCs1reD5KAgPoIU4msA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@oxfmt/binding-linux-x64-gnu@0.42.0': - resolution: {integrity: sha512-BajxJ6KQvMMdpXGPWhBGyjb2Jvx4uec0w+wi6TJZ6Tv7+MzPwe0pO8g5h1U0jyFgoaF7mDl6yKPW3ykWcbUJRw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@oxfmt/binding-linux-x64-musl@0.42.0': - resolution: {integrity: sha512-0wV284I6vc5f0AqAhgAbHU2935B4bVpncPoe5n/WzVZY/KnHgqxC8iSFGeSyLWEgstFboIcWkOPck7tqbdHkzA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [musl] - - '@oxfmt/binding-openharmony-arm64@0.42.0': - resolution: {integrity: sha512-p4BG6HpGnhfgHk1rzZfyR6zcWkE7iLrWxyehHfXUy4Qa5j3e0roglFOdP/Nj5cJJ58MA3isQ5dlfkW2nNEpolw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - - '@oxfmt/binding-win32-arm64-msvc@0.42.0': - resolution: {integrity: sha512-mn//WV60A+IetORDxYieYGAoQso4KnVRRjORDewMcod4irlRe0OSC7YPhhwaexYNPQz/GCFk+v9iUcZ2W22yxQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - - '@oxfmt/binding-win32-ia32-msvc@0.42.0': - resolution: {integrity: sha512-3gWltUrvuz4LPJXWivoAxZ28Of2O4N7OGuM5/X3ubPXCEV8hmgECLZzjz7UYvSDUS3grfdccQwmjynm+51EFpw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ia32] - os: [win32] - - '@oxfmt/binding-win32-x64-msvc@0.42.0': - resolution: {integrity: sha512-Wg4TMAfQRL9J9AZevJ/ZNy3uyyDztDYQtGr4P8UyyzIhLhFrdSmz1J/9JT+rv0fiCDLaFOBQnj3f3K3+a5PzDQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - - '@oxlint-tsgolint/darwin-arm64@0.17.3': - resolution: {integrity: sha512-5aDl4mxXWs+Bj02pNrX6YY6v9KMZjLIytXoqolLEo0dfBNVeZUonZgJAa/w0aUmijwIRrBhxEzb42oLuUtfkGw==} - cpu: [arm64] - os: [darwin] - - '@oxlint-tsgolint/darwin-x64@0.17.3': - resolution: {integrity: sha512-gPBy4DS5ueCgXzko20XsNZzDe/Cxde056B+QuPLGvz05CGEAtmRfpImwnyY2lAXXjPL+SmnC/OYexu8zI12yHQ==} - cpu: [x64] - os: [darwin] - - '@oxlint-tsgolint/linux-arm64@0.17.3': - resolution: {integrity: sha512-+pkunvCfB6pB0G9qHVVXUao3nqzXQPo4O3DReIi+5nGa+bOU3J3Srgy+Zb8VyOL+WDsSMJ+U7+r09cKHWhz3hg==} - cpu: [arm64] - os: [linux] - - '@oxlint-tsgolint/linux-x64@0.17.3': - resolution: {integrity: sha512-/kW5oXtBThu4FjmgIBthdmMjWLzT3M1TEDQhxDu7hQU5xDeTd60CDXb2SSwKCbue9xu7MbiFoJu83LN0Z/d38g==} - cpu: [x64] - os: [linux] - - '@oxlint-tsgolint/win32-arm64@0.17.3': - resolution: {integrity: sha512-NMELRvbz4Ed4dxg8WiqZxtu3k4OJEp2B9KInZW+BMfqEqbwZdEJY83tbqz2hD1EjKO2akrqBQ0GpRUJEkd8kKw==} - cpu: [arm64] - os: [win32] - - '@oxlint-tsgolint/win32-x64@0.17.3': - resolution: {integrity: sha512-+pJ7r8J3SLPws5uoidVplZc8R/lpKyKPE6LoPGv9BME00Y1VjT6jWGx/dtUN8PWvcu3iTC6k+8u3ojFSJNmWTg==} - cpu: [x64] - os: [win32] - - '@oxlint/binding-android-arm-eabi@1.57.0': - resolution: {integrity: sha512-C7EiyfAJG4B70496eV543nKiq5cH0o/xIh/ufbjQz3SIvHhlDDsyn+mRFh+aW8KskTyUpyH2LGWL8p2oN6bl1A==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [android] - - '@oxlint/binding-android-arm64@1.57.0': - resolution: {integrity: sha512-9i80AresjZ/FZf5xK8tKFbhQnijD4s1eOZw6/FHUwD59HEZbVLRc2C88ADYJfLZrF5XofWDiRX/Ja9KefCLy7w==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] - - '@oxlint/binding-darwin-arm64@1.57.0': - resolution: {integrity: sha512-0eUfhRz5L2yKa9I8k3qpyl37XK3oBS5BvrgdVIx599WZK63P8sMbg+0s4IuxmIiZuBK68Ek+Z+gcKgeYf0otsg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - - '@oxlint/binding-darwin-x64@1.57.0': - resolution: {integrity: sha512-UvrSuzBaYOue+QMAcuDITe0k/Vhj6KZGjfnI6x+NkxBTke/VoM7ZisaxgNY0LWuBkTnd1OmeQfEQdQ48fRjkQg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - - '@oxlint/binding-freebsd-x64@1.57.0': - resolution: {integrity: sha512-wtQq0dCoiw4bUwlsNVDJJ3pxJA218fOezpgtLKrbQqUtQJcM9yP8z+I9fu14aHg0uyAxIY+99toL6uBa2r7nxA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] - - '@oxlint/binding-linux-arm-gnueabihf@1.57.0': - resolution: {integrity: sha512-qxFWl2BBBFcT4djKa+OtMdnLgoHEJXpqjyGwz8OhW35ImoCwR5qtAGqApNYce5260FQqoAHW8S8eZTjiX67Tsg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@oxlint/binding-linux-arm-musleabihf@1.57.0': - resolution: {integrity: sha512-SQoIsBU7J0bDW15/f0/RvxHfY3Y0+eB/caKBQtNFbuerTiA6JCYx9P1MrrFTwY2dTm/lMgTSgskvCEYk2AtG/Q==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@oxlint/binding-linux-arm64-gnu@1.57.0': - resolution: {integrity: sha512-jqxYd1W6WMeozsCmqe9Rzbu3SRrGTyGDAipRlRggetyYbUksJqJKvUNTQtZR/KFoJPb+grnSm5SHhdWrywv3RQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@oxlint/binding-linux-arm64-musl@1.57.0': - resolution: {integrity: sha512-i66WyEPVEvq9bxRUCJ/MP5EBfnTDN3nhwEdFZFTO5MmLLvzngfWEG3NSdXQzTT3vk5B9i6C2XSIYBh+aG6uqyg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@oxlint/binding-linux-ppc64-gnu@1.57.0': - resolution: {integrity: sha512-oMZDCwz4NobclZU3pH+V1/upVlJZiZvne4jQP+zhJwt+lmio4XXr4qG47CehvrW1Lx2YZiIHuxM2D4YpkG3KVA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@oxlint/binding-linux-riscv64-gnu@1.57.0': - resolution: {integrity: sha512-uoBnjJ3MMEBbfnWC1jSFr7/nSCkcQYa72NYoNtLl1imshDnWSolYCjzb8LVCwYCCfLJXD+0gBLD7fyC14c0+0g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@oxlint/binding-linux-riscv64-musl@1.57.0': - resolution: {integrity: sha512-BdrwD7haPZ8a9KrZhKJRSj6jwCor+Z8tHFZ3PT89Y3Jq5v3LfMfEePeAmD0LOTWpiTmzSzdmyw9ijneapiVHKQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [riscv64] - os: [linux] - libc: [musl] - - '@oxlint/binding-linux-s390x-gnu@1.57.0': - resolution: {integrity: sha512-BNs+7ZNsRstVg2tpNxAXfMX/Iv5oZh204dVyb8Z37+/gCh+yZqNTlg6YwCLIMPSk5wLWIGOaQjT0GUOahKYImw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@oxlint/binding-linux-x64-gnu@1.57.0': - resolution: {integrity: sha512-AghS18w+XcENcAX0+BQGLiqjpqpaxKJa4cWWP0OWNLacs27vHBxu7TYkv9LUSGe5w8lOJHeMxcYfZNOAPqw2bg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@oxlint/binding-linux-x64-musl@1.57.0': - resolution: {integrity: sha512-E/FV3GB8phu/Rpkhz5T96hAiJlGzn91qX5yj5gU754P5cmVGXY1Jw/VSjDSlZBCY3VHjsVLdzgdkJaomEmcNOg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [musl] - - '@oxlint/binding-openharmony-arm64@1.57.0': - resolution: {integrity: sha512-xvZ2yZt0nUVfU14iuGv3V25jpr9pov5N0Wr28RXnHFxHCRxNDMtYPHV61gGLhN9IlXM96gI4pyYpLSJC5ClLCQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - - '@oxlint/binding-win32-arm64-msvc@1.57.0': - resolution: {integrity: sha512-Z4D8Pd0AyHBKeazhdIXeUUy5sIS3Mo0veOlzlDECg6PhRRKgEsBJCCV1n+keUZtQ04OP+i7+itS3kOykUyNhDg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - - '@oxlint/binding-win32-ia32-msvc@1.57.0': - resolution: {integrity: sha512-StOZ9nFMVKvevicbQfql6Pouu9pgbeQnu60Fvhz2S6yfMaii+wnueLnqQ5I1JPgNF0Syew4voBlAaHD13wH6tw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ia32] - os: [win32] - - '@oxlint/binding-win32-x64-msvc@1.57.0': - resolution: {integrity: sha512-6PuxhYgth8TuW0+ABPOIkGdBYw+qYGxgIdXPHSVpiCDm+hqTTWCmC739St1Xni0DJBt8HnSHTG67i1y6gr8qrA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - - '@playwright/test@1.51.1': - resolution: {integrity: sha512-nM+kEaTSAoVlXmMPH10017vn3FSiFqr/bh4fKg9vmAdMfd9SDqRZNvPSiAHADc/itWak+qPvMPZQOPwCBW7k7Q==} - engines: {node: '>=18'} - hasBin: true - - '@polka/url@1.0.0-next.29': - resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} - - '@rolldown/binding-android-arm64@1.0.0-rc.12': - resolution: {integrity: sha512-pv1y2Fv0JybcykuiiD3qBOBdz6RteYojRFY1d+b95WVuzx211CRh+ytI/+9iVyWQ6koTh5dawe4S/yRfOFjgaA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] - - '@rolldown/binding-darwin-arm64@1.0.0-rc.12': - resolution: {integrity: sha512-cFYr6zTG/3PXXF3pUO+umXxt1wkRK/0AYT8lDwuqvRC+LuKYWSAQAQZjCWDQpAH172ZV6ieYrNnFzVVcnSflAg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - - '@rolldown/binding-darwin-x64@1.0.0-rc.12': - resolution: {integrity: sha512-ZCsYknnHzeXYps0lGBz8JrF37GpE9bFVefrlmDrAQhOEi4IOIlcoU1+FwHEtyXGx2VkYAvhu7dyBf75EJQffBw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - - '@rolldown/binding-freebsd-x64@1.0.0-rc.12': - resolution: {integrity: sha512-dMLeprcVsyJsKolRXyoTH3NL6qtsT0Y2xeuEA8WQJquWFXkEC4bcu1rLZZSnZRMtAqwtrF/Ib9Ddtpa/Gkge9Q==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] - - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.12': - resolution: {integrity: sha512-YqWjAgGC/9M1lz3GR1r1rP79nMgo3mQiiA+Hfo+pvKFK1fAJ1bCi0ZQVh8noOqNacuY1qIcfyVfP6HoyBRZ85Q==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.12': - resolution: {integrity: sha512-/I5AS4cIroLpslsmzXfwbe5OmWvSsrFuEw3mwvbQ1kDxJ822hFHIx+vsN/TAzNVyepI/j/GSzrtCIwQPeKCLIg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.12': - resolution: {integrity: sha512-V6/wZztnBqlx5hJQqNWwFdxIKN0m38p8Jas+VoSfgH54HSj9tKTt1dZvG6JRHcjh6D7TvrJPWFGaY9UBVOaWPw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.12': - resolution: {integrity: sha512-AP3E9BpcUYliZCxa3w5Kwj9OtEVDYK6sVoUzy4vTOJsjPOgdaJZKFmN4oOlX0Wp0RPV2ETfmIra9x1xuayFB7g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.12': - resolution: {integrity: sha512-nWwpvUSPkoFmZo0kQazZYOrT7J5DGOJ/+QHHzjvNlooDZED8oH82Yg67HvehPPLAg5fUff7TfWFHQS8IV1n3og==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.12': - resolution: {integrity: sha512-RNrafz5bcwRy+O9e6P8Z/OCAJW/A+qtBczIqVYwTs14pf4iV1/+eKEjdOUta93q2TsT/FI0XYDP3TCky38LMAg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-x64-musl@1.0.0-rc.12': - resolution: {integrity: sha512-Jpw/0iwoKWx3LJ2rc1yjFrj+T7iHZn2JDg1Yny1ma0luviFS4mhAIcd1LFNxK3EYu3DHWCps0ydXQ5i/rrJ2ig==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [musl] - - '@rolldown/binding-openharmony-arm64@1.0.0-rc.12': - resolution: {integrity: sha512-vRugONE4yMfVn0+7lUKdKvN4D5YusEiPilaoO2sgUWpCvrncvWgPMzK00ZFFJuiPgLwgFNP5eSiUlv2tfc+lpA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - - '@rolldown/binding-wasm32-wasi@1.0.0-rc.12': - resolution: {integrity: sha512-ykGiLr/6kkiHc0XnBfmFJuCjr5ZYKKofkx+chJWDjitX+KsJuAmrzWhwyOMSHzPhzOHOy7u9HlFoa5MoAOJ/Zg==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.12': - resolution: {integrity: sha512-5eOND4duWkwx1AzCxadcOrNeighiLwMInEADT0YM7xeEOOFcovWZCq8dadXgcRHSf3Ulh1kFo/qvzoFiCLOL1Q==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.12': - resolution: {integrity: sha512-PyqoipaswDLAZtot351MLhrlrh6lcZPo2LSYE+VDxbVk24LVKAGOuE4hb8xZQmrPAuEtTZW8E6D2zc5EUZX4Lw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - - '@rolldown/pluginutils@1.0.0-rc.12': - resolution: {integrity: sha512-HHMwmarRKvoFsJorqYlFeFRzXZqCt2ETQlEDOb9aqssrnVBB1/+xgTGtuTrIk5vzLNX1MjMtTf7W9z3tsSbrxw==} - - '@standard-schema/spec@1.1.0': - resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - - '@teppeis/multimaps@3.0.0': - resolution: {integrity: sha512-ID7fosbc50TbT0MK0EG12O+gAP3W3Aa/Pz4DaTtQtEvlc9Odaqi0de+xuZ7Li2GtK4HzEX7IuRWS/JmZLksR3Q==} - engines: {node: '>=14'} - - '@tybys/wasm-util@0.10.1': - resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} - - '@types/chai@5.2.3': - resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} - - '@types/deep-eql@4.0.2': - resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} - - '@types/node@25.5.0': - resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==} - - '@types/normalize-package-data@2.4.4': - resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} - - '@voidzero-dev/vite-plus-core@0.1.14': - resolution: {integrity: sha512-CCWzdkfW0fo0cQNlIsYp5fOuH2IwKuPZEb2UY2Z8gXcp5pG74A82H2Pthj0heAuvYTAnfT7kEC6zM+RbiBgQbg==} - engines: {node: ^20.19.0 || >=22.12.0} - peerDependencies: - '@arethetypeswrong/core': ^0.18.1 - '@tsdown/css': 0.21.4 - '@tsdown/exe': 0.21.4 - '@types/node': ^20.19.0 || >=22.12.0 - '@vitejs/devtools': ^0.1.0 - esbuild: ^0.27.0 - jiti: '>=1.21.0' - less: ^4.0.0 - publint: ^0.3.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - typescript: ^5.0.0 - unplugin-unused: ^0.5.0 - yaml: ^2.4.2 - peerDependenciesMeta: - '@arethetypeswrong/core': - optional: true - '@tsdown/css': - optional: true - '@tsdown/exe': - optional: true - '@types/node': - optional: true - '@vitejs/devtools': - optional: true - esbuild: - optional: true - jiti: - optional: true - less: - optional: true - publint: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - typescript: - optional: true - unplugin-unused: - optional: true - yaml: - optional: true - - '@voidzero-dev/vite-plus-darwin-arm64@0.1.14': - resolution: {integrity: sha512-q2ESUSbapwsxVRe/KevKATahNRraoX5nti3HT9S3266OHT5sMroBY14jaxTv74ekjQc9E6EPhyLGQWuWQuuBRw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - - '@voidzero-dev/vite-plus-darwin-x64@0.1.14': - resolution: {integrity: sha512-UpcDZc9G99E/4HDRoobvYHxMvFOG5uv3RwEcq0HF70u4DsnEMl1z8RaJLeWV7a09LGwj9Q+YWC3Z4INWnTLs8g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - - '@voidzero-dev/vite-plus-linux-arm64-gnu@0.1.14': - resolution: {integrity: sha512-GIjn35RABUEDB9gHD26nRq7T72Te+Qy2+NIzogwEaUE728PvPkatF5gMCeF4sigCoc8c4qxDwsG+A2A2LYGnDg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@voidzero-dev/vite-plus-linux-arm64-musl@0.1.14': - resolution: {integrity: sha512-qo2RToGirG0XCcxZ2AEOuonLM256z6dNbJzDDIo5gWYA+cIKigFQJbkPyr25zsT1tsP2aY0OTxt2038XbVlRkQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@voidzero-dev/vite-plus-linux-x64-gnu@0.1.14': - resolution: {integrity: sha512-BsMWKZfdfGcYLxxLyaePpg6NW54xqzzcfq8sFUwKfwby0kgOKQ4WymUXyBvO9nnBb0ZPsJQrV0sx+Onac/LTaw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@voidzero-dev/vite-plus-linux-x64-musl@0.1.14': - resolution: {integrity: sha512-mOrEpj7ntW9RopGbcOYG/L0pOs0qHzUG4Vz7NXbuf4dbOSlY4JjyoMOIWxjKQORQht02Hzuf8YrMGNwa6AjVSQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [musl] - - '@voidzero-dev/vite-plus-test@0.1.14': - resolution: {integrity: sha512-rjF+qpYD+5+THOJZ3gbE3+cxsk5sW7nJ0ODK7y6ZKeS4amREUMedEDYykzKBwR7OZDC/WwE90A0iLWCr6qAXhA==} - engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} - peerDependencies: - '@edge-runtime/vm': '*' - '@opentelemetry/api': ^1.9.0 - '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/ui': 4.1.1 - happy-dom: '*' - jsdom: '*' - vite: ^6.0.0 || ^7.0.0 || ^8.0.0 - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@opentelemetry/api': - optional: true - '@types/node': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - - '@voidzero-dev/vite-plus-win32-arm64-msvc@0.1.14': - resolution: {integrity: sha512-7iC+Ig+8D/zACy0IJf7w/vQ7duTjux9Ttmm3KOBdVWH4dl3JihydA7+SQVMhz71a4WiqJ6nPidoG8D6hUP4MVQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - - '@voidzero-dev/vite-plus-win32-x64-msvc@0.1.14': - resolution: {integrity: sha512-yRJ/8yAYFluNHx0Ej6Kevx65MIeM3wFKklnxosVZRlz2ZRL1Ea1Qh3tWATr3Ipk1ciRxBv8KJgp6zXqjxtZSoQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - - ansi-regex@4.1.1: - resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==} - engines: {node: '>=6'} - - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - - ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} - - any-promise@1.3.0: - resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - - assertion-error-formatter@3.0.0: - resolution: {integrity: sha512-6YyAVLrEze0kQ7CmJfUgrLHb+Y7XghmL2Ie7ijVa2Y9ynP3LV+VDiwFk62Dn0qtqbmY0BT0ss6p1xxpiF2PYbQ==} - - assertion-error@2.0.1: - resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} - engines: {node: '>=12'} - - balanced-match@4.0.4: - resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} - engines: {node: 18 || 20 || >=22} - - brace-expansion@5.0.5: - resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} - engines: {node: 18 || 20 || >=22} - - buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - - cac@7.0.0: - resolution: {integrity: sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==} - engines: {node: '>=20.19.0'} - - capital-case@1.0.4: - resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - class-transformer@0.5.1: - resolution: {integrity: sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==} - - cli-table3@0.6.5: - resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} - engines: {node: 10.* || >= 12.*} - - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - commander@14.0.0: - resolution: {integrity: sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==} - engines: {node: '>=20'} - - commander@14.0.2: - resolution: {integrity: sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==} - engines: {node: '>=20'} - - commander@14.0.3: - resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} - engines: {node: '>=20'} - - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - detect-libc@2.1.2: - resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} - engines: {node: '>=8'} - - diff@4.0.4: - resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==} - engines: {node: '>=0.3.1'} - - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - - error-stack-parser@2.1.4: - resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} - - es-module-lexer@1.7.0: - resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - - esbuild@0.27.4: - resolution: {integrity: sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==} - engines: {node: '>=18'} - hasBin: true - - escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - - fdir@6.5.0: - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - - figures@3.2.0: - resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} - engines: {node: '>=8'} - - find-up-simple@1.0.1: - resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==} - engines: {node: '>=18'} - - fsevents@2.3.2: - resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - get-tsconfig@4.13.7: - resolution: {integrity: sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==} - - glob@13.0.6: - resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} - engines: {node: 18 || 20 || >=22} - - global-dirs@3.0.1: - resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==} - engines: {node: '>=10'} - - has-ansi@4.0.1: - resolution: {integrity: sha512-Qr4RtTm30xvEdqUXbSBVWDu+PrTokJOwe/FU+VdfJPk+MXAPoeOzKpRyrDTnZIJwAkQ4oBLTU53nu0HrkF/Z2A==} - engines: {node: '>=8'} - - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - - hosted-git-info@9.0.2: - resolution: {integrity: sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==} - engines: {node: ^20.17.0 || >=22.9.0} - - indent-string@4.0.0: - resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} - engines: {node: '>=8'} - - index-to-position@1.2.0: - resolution: {integrity: sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==} - engines: {node: '>=18'} - - ini@2.0.0: - resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==} - engines: {node: '>=10'} - - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - - is-installed-globally@0.4.0: - resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==} - engines: {node: '>=10'} - - is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - - is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - knuth-shuffle-seeded@1.0.6: - resolution: {integrity: sha512-9pFH0SplrfyKyojCLxZfMcvkhf5hH0d+UwR9nTVJ/DDQJGuzcXjTwB7TP7sDfehSudlGGaOLblmEWqv04ERVWg==} - - lightningcss-android-arm64@1.32.0: - resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [android] - - lightningcss-darwin-arm64@1.32.0: - resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [darwin] - - lightningcss-darwin-x64@1.32.0: - resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [darwin] - - lightningcss-freebsd-x64@1.32.0: - resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [freebsd] - - lightningcss-linux-arm-gnueabihf@1.32.0: - resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} - engines: {node: '>= 12.0.0'} - cpu: [arm] - os: [linux] - - lightningcss-linux-arm64-gnu@1.32.0: - resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - libc: [glibc] - - lightningcss-linux-arm64-musl@1.32.0: - resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - libc: [musl] - - lightningcss-linux-x64-gnu@1.32.0: - resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - libc: [glibc] - - lightningcss-linux-x64-musl@1.32.0: - resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - libc: [musl] - - lightningcss-win32-arm64-msvc@1.32.0: - resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [win32] - - lightningcss-win32-x64-msvc@1.32.0: - resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [win32] - - lightningcss@1.32.0: - resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} - engines: {node: '>= 12.0.0'} - - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - - lodash.mergewith@4.6.2: - resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==} - - lodash.sortby@4.7.0: - resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} - - lower-case@2.0.2: - resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} - - lru-cache@11.2.7: - resolution: {integrity: sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==} - engines: {node: 20 || >=22} - - luxon@3.7.2: - resolution: {integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==} - engines: {node: '>=12'} - - mime@3.0.0: - resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} - engines: {node: '>=10.0.0'} - hasBin: true - - minimatch@10.2.4: - resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} - engines: {node: 18 || 20 || >=22} - - minipass@7.1.3: - resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} - engines: {node: '>=16 || 14 >=14.17'} - - mkdirp@3.0.1: - resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} - engines: {node: '>=10'} - hasBin: true - - mrmime@2.0.1: - resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} - engines: {node: '>=10'} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - mz@2.7.0: - resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - no-case@3.0.4: - resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} - - normalize-package-data@8.0.0: - resolution: {integrity: sha512-RWk+PI433eESQ7ounYxIp67CYuVsS1uYSonX3kA6ps/3LWfjVQa/ptEg6Y3T6uAMq1mWpX9PQ+qx+QaHpsc7gQ==} - engines: {node: ^20.17.0 || >=22.9.0} - - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - - obug@2.1.1: - resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} - - oxfmt@0.42.0: - resolution: {integrity: sha512-QhejGErLSMReNuZ6vxgFHDyGoPbjTRNi6uGHjy0cvIjOQFqD6xmr/T+3L41ixR3NIgzcNiJ6ylQKpvShTgDfqg==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - - oxlint-tsgolint@0.17.3: - resolution: {integrity: sha512-1eh4bcpOMw0e7+YYVxmhFc2mo/V6hJ2+zfukqf+GprvVn3y94b69M/xNrYLmx5A+VdYe0i/bJ2xOs6Hp/jRmRA==} - hasBin: true - - oxlint@1.57.0: - resolution: {integrity: sha512-DGFsuBX5MFZX9yiDdtKjTrYPq45CZ8Fft6qCltJITYZxfwYjVdGf/6wycGYTACloauwIPxUnYhBVeZbHvleGhw==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - oxlint-tsgolint: '>=0.15.0' - peerDependenciesMeta: - oxlint-tsgolint: - optional: true - - pad-right@0.2.2: - resolution: {integrity: sha512-4cy8M95ioIGolCoMmm2cMntGR1lPLEbOMzOKu8bzjuJP6JpzEMQcDHmh7hHLYGgob+nKe1YHFMaG4V59HQa89g==} - engines: {node: '>=0.10.0'} - - parse-json@8.3.0: - resolution: {integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==} - engines: {node: '>=18'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - path-scurry@2.0.2: - resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} - engines: {node: 18 || 20 || >=22} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - picomatch@4.0.4: - resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} - engines: {node: '>=12'} - - pixelmatch@7.1.0: - resolution: {integrity: sha512-1wrVzJ2STrpmONHKBy228LM1b84msXDUoAzVEl0R8Mz4Ce6EPr+IVtxm8+yvrqLYMHswREkjYFaMxnyGnaY3Ng==} - hasBin: true - - playwright-core@1.51.1: - resolution: {integrity: sha512-/crRMj8+j/Nq5s8QcvegseuyeZPxpQCZb6HNk3Sos3BlZyAknRjoyJPFWkpNn8v0+P3WiwqFF8P+zQo4eqiNuw==} - engines: {node: '>=18'} - hasBin: true - - playwright@1.51.1: - resolution: {integrity: sha512-kkx+MB2KQRkyxjYPc3a0wLZZoDczmppyGJIvQ43l+aZihkaVvmu/21kiyaHeHjiFxjxNNFnUncKmcGIyOojsaw==} - engines: {node: '>=18'} - hasBin: true - - pngjs@7.0.0: - resolution: {integrity: sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==} - engines: {node: '>=14.19.0'} - - postcss@8.5.8: - resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} - engines: {node: ^10 || ^12 || >=14} - - progress@2.0.3: - resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} - engines: {node: '>=0.4.0'} - - property-expr@2.0.6: - resolution: {integrity: sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==} - - read-package-up@12.0.0: - resolution: {integrity: sha512-Q5hMVBYur/eQNWDdbF4/Wqqr9Bjvtrw2kjGxxBbKLbx8bVCL8gcArjTy8zDUuLGQicftpMuU0riQNcAsbtOVsw==} - engines: {node: '>=20'} - - read-pkg@10.1.0: - resolution: {integrity: sha512-I8g2lArQiP78ll51UeMZojewtYgIRCKCWqZEgOO8c/uefTI+XDXvCSXu3+YNUaTNvZzobrL5+SqHjBrByRRTdg==} - engines: {node: '>=20'} - - reflect-metadata@0.2.2: - resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} - - regexp-match-indices@1.0.2: - resolution: {integrity: sha512-DwZuAkt8NF5mKwGGER1EGh2PRqyvhRhhLviH+R8y8dIuaQROlUfXjt4s9ZTXstIsSkptf06BSvwcEmmfheJJWQ==} - - regexp-tree@0.1.27: - resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} - hasBin: true - - repeat-string@1.6.1: - resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} - engines: {node: '>=0.10'} - - resolve-pkg-maps@1.0.0: - resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - - rolldown@1.0.0-rc.12: - resolution: {integrity: sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - - seed-random@2.2.0: - resolution: {integrity: sha512-34EQV6AAHQGhoc0tn/96a9Fsi6v2xdqe/dMUwljGRaFOzR3EgRmECvD0O8vi8X+/uQ50LGHfkNu/Eue5TPKZkQ==} - - semver@7.7.4: - resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} - engines: {node: '>=10'} - hasBin: true - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - sirv@3.0.2: - resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} - engines: {node: '>=18'} - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} - - source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - - spdx-correct@3.2.0: - resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} - - spdx-exceptions@2.5.0: - resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} - - spdx-expression-parse@3.0.1: - resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} - - spdx-license-ids@3.0.23: - resolution: {integrity: sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==} - - stackframe@1.3.4: - resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} - - std-env@4.0.0: - resolution: {integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==} - - string-argv@0.3.1: - resolution: {integrity: sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==} - engines: {node: '>=0.6.19'} - - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - - supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} - - tagged-tag@1.0.0: - resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} - engines: {node: '>=20'} - - thenify-all@1.6.0: - resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} - engines: {node: '>=0.8'} - - thenify@3.3.1: - resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} - - tiny-case@1.0.3: - resolution: {integrity: sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==} - - tinybench@2.9.0: - resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - - tinyexec@1.0.4: - resolution: {integrity: sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==} - engines: {node: '>=18'} - - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} - engines: {node: '>=12.0.0'} - - tinypool@2.1.0: - resolution: {integrity: sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw==} - engines: {node: ^20.0.0 || >=22.0.0} - - toposort@2.0.2: - resolution: {integrity: sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==} - - totalist@3.0.1: - resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} - engines: {node: '>=6'} - - ts-dedent@2.2.0: - resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} - engines: {node: '>=6.10'} - - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - - tsx@4.21.0: - resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} - engines: {node: '>=18.0.0'} - hasBin: true - - type-fest@2.19.0: - resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} - engines: {node: '>=12.20'} - - type-fest@4.41.0: - resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} - engines: {node: '>=16'} - - type-fest@5.5.0: - resolution: {integrity: sha512-PlBfpQwiUvGViBNX84Yxwjsdhd1TUlXr6zjX7eoirtCPIr08NAmxwa+fcYBTeRQxHo9YC9wwF3m9i700sHma8g==} - engines: {node: '>=20'} - - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} - hasBin: true - - undici-types@7.18.2: - resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} - - unicorn-magic@0.4.0: - resolution: {integrity: sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==} - engines: {node: '>=20'} - - upper-case-first@2.0.2: - resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==} - - util-arity@1.1.0: - resolution: {integrity: sha512-kkyIsXKwemfSy8ZEoaIz06ApApnWsk5hQO0vLjZS6UkBiGiW++Jsyb8vSBoc0WKlffGoGs5yYy/j5pp8zckrFA==} - - validate-npm-package-license@3.0.4: - resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} - - vite-plus@0.1.14: - resolution: {integrity: sha512-p4pWlpZZNiEsHxPWNdeIU9iuPix3ydm3ficb0dXPggoyIkdotfXtvn2NPX9KwfiQImU72EVEs4+VYBZYNcUYrw==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - - vite@8.0.3: - resolution: {integrity: sha512-B9ifbFudT1TFhfltfaIPgjo9Z3mDynBTJSUYxTjOQruf/zHH+ezCQKcoqO+h7a9Pw9Nm/OtlXAiGT1axBgwqrQ==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - '@vitejs/devtools': ^0.1.0 - esbuild: ^0.27.0 - jiti: '>=1.21.0' - less: ^4.0.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - '@vitejs/devtools': - optional: true - esbuild: - optional: true - jiti: - optional: true - less: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - ws@8.20.0: - resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - - xmlbuilder@15.1.1: - resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} - engines: {node: '>=8.0'} - - yaml@2.8.3: - resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==} - engines: {node: '>= 14.6'} - hasBin: true - - yup@1.7.1: - resolution: {integrity: sha512-GKHFX2nXul2/4Dtfxhozv701jLQHdf6J34YDh2cEkpqoo8le5Mg6/LrdseVLrFarmFygZTlfIhHx/QKfb/QWXw==} - -snapshots: - - '@babel/code-frame@7.29.0': - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/helper-validator-identifier@7.28.5': {} - - '@colors/colors@1.5.0': - optional: true - - '@cucumber/ci-environment@13.0.0': {} - - '@cucumber/cucumber-expressions@19.0.0': - dependencies: - regexp-match-indices: 1.0.2 - - '@cucumber/cucumber@12.7.0': - dependencies: - '@cucumber/ci-environment': 13.0.0 - '@cucumber/cucumber-expressions': 19.0.0 - '@cucumber/gherkin': 38.0.0 - '@cucumber/gherkin-streams': 6.0.0(@cucumber/gherkin@38.0.0)(@cucumber/message-streams@4.0.1(@cucumber/messages@32.0.1))(@cucumber/messages@32.0.1) - '@cucumber/gherkin-utils': 11.0.0 - '@cucumber/html-formatter': 23.0.0(@cucumber/messages@32.0.1) - '@cucumber/junit-xml-formatter': 0.9.0(@cucumber/messages@32.0.1) - '@cucumber/message-streams': 4.0.1(@cucumber/messages@32.0.1) - '@cucumber/messages': 32.0.1 - '@cucumber/pretty-formatter': 1.0.1(@cucumber/cucumber@12.7.0)(@cucumber/messages@32.0.1) - '@cucumber/tag-expressions': 9.1.0 - assertion-error-formatter: 3.0.0 - capital-case: 1.0.4 - chalk: 4.1.2 - cli-table3: 0.6.5 - commander: 14.0.3 - debug: 4.4.3(supports-color@8.1.1) - error-stack-parser: 2.1.4 - figures: 3.2.0 - glob: 13.0.6 - has-ansi: 4.0.1 - indent-string: 4.0.0 - is-installed-globally: 0.4.0 - is-stream: 2.0.1 - knuth-shuffle-seeded: 1.0.6 - lodash.merge: 4.6.2 - lodash.mergewith: 4.6.2 - luxon: 3.7.2 - mime: 3.0.0 - mkdirp: 3.0.1 - mz: 2.7.0 - progress: 2.0.3 - read-package-up: 12.0.0 - semver: 7.7.4 - string-argv: 0.3.1 - supports-color: 8.1.1 - type-fest: 4.41.0 - util-arity: 1.1.0 - yaml: 2.8.3 - yup: 1.7.1 - - '@cucumber/gherkin-streams@6.0.0(@cucumber/gherkin@38.0.0)(@cucumber/message-streams@4.0.1(@cucumber/messages@32.0.1))(@cucumber/messages@32.0.1)': - dependencies: - '@cucumber/gherkin': 38.0.0 - '@cucumber/message-streams': 4.0.1(@cucumber/messages@32.0.1) - '@cucumber/messages': 32.0.1 - commander: 14.0.0 - source-map-support: 0.5.21 - - '@cucumber/gherkin-utils@11.0.0': - dependencies: - '@cucumber/gherkin': 38.0.0 - '@cucumber/messages': 32.0.1 - '@teppeis/multimaps': 3.0.0 - commander: 14.0.2 - source-map-support: 0.5.21 - - '@cucumber/gherkin@38.0.0': - dependencies: - '@cucumber/messages': 32.0.1 - - '@cucumber/html-formatter@23.0.0(@cucumber/messages@32.0.1)': - dependencies: - '@cucumber/messages': 32.0.1 - - '@cucumber/junit-xml-formatter@0.9.0(@cucumber/messages@32.0.1)': - dependencies: - '@cucumber/messages': 32.0.1 - '@cucumber/query': 14.7.0(@cucumber/messages@32.0.1) - '@teppeis/multimaps': 3.0.0 - luxon: 3.7.2 - xmlbuilder: 15.1.1 - - '@cucumber/message-streams@4.0.1(@cucumber/messages@32.0.1)': - dependencies: - '@cucumber/messages': 32.0.1 - - '@cucumber/messages@32.0.1': - dependencies: - class-transformer: 0.5.1 - reflect-metadata: 0.2.2 - - '@cucumber/pretty-formatter@1.0.1(@cucumber/cucumber@12.7.0)(@cucumber/messages@32.0.1)': - dependencies: - '@cucumber/cucumber': 12.7.0 - '@cucumber/messages': 32.0.1 - ansi-styles: 5.2.0 - cli-table3: 0.6.5 - figures: 3.2.0 - ts-dedent: 2.2.0 - - '@cucumber/query@14.7.0(@cucumber/messages@32.0.1)': - dependencies: - '@cucumber/messages': 32.0.1 - '@teppeis/multimaps': 3.0.0 - lodash.sortby: 4.7.0 - - '@cucumber/tag-expressions@9.1.0': {} - - '@emnapi/core@1.9.1': - dependencies: - '@emnapi/wasi-threads': 1.2.0 - tslib: 2.8.1 - optional: true - - '@emnapi/runtime@1.9.1': - dependencies: - tslib: 2.8.1 - optional: true - - '@emnapi/wasi-threads@1.2.0': - dependencies: - tslib: 2.8.1 - optional: true - - '@esbuild/aix-ppc64@0.27.4': - optional: true - - '@esbuild/android-arm64@0.27.4': - optional: true - - '@esbuild/android-arm@0.27.4': - optional: true - - '@esbuild/android-x64@0.27.4': - optional: true - - '@esbuild/darwin-arm64@0.27.4': - optional: true - - '@esbuild/darwin-x64@0.27.4': - optional: true - - '@esbuild/freebsd-arm64@0.27.4': - optional: true - - '@esbuild/freebsd-x64@0.27.4': - optional: true - - '@esbuild/linux-arm64@0.27.4': - optional: true - - '@esbuild/linux-arm@0.27.4': - optional: true - - '@esbuild/linux-ia32@0.27.4': - optional: true - - '@esbuild/linux-loong64@0.27.4': - optional: true - - '@esbuild/linux-mips64el@0.27.4': - optional: true - - '@esbuild/linux-ppc64@0.27.4': - optional: true - - '@esbuild/linux-riscv64@0.27.4': - optional: true - - '@esbuild/linux-s390x@0.27.4': - optional: true - - '@esbuild/linux-x64@0.27.4': - optional: true - - '@esbuild/netbsd-arm64@0.27.4': - optional: true - - '@esbuild/netbsd-x64@0.27.4': - optional: true - - '@esbuild/openbsd-arm64@0.27.4': - optional: true - - '@esbuild/openbsd-x64@0.27.4': - optional: true - - '@esbuild/openharmony-arm64@0.27.4': - optional: true - - '@esbuild/sunos-x64@0.27.4': - optional: true - - '@esbuild/win32-arm64@0.27.4': - optional: true - - '@esbuild/win32-ia32@0.27.4': - optional: true - - '@esbuild/win32-x64@0.27.4': - optional: true - - '@napi-rs/wasm-runtime@1.1.1': - dependencies: - '@emnapi/core': 1.9.1 - '@emnapi/runtime': 1.9.1 - '@tybys/wasm-util': 0.10.1 - optional: true - - '@oxc-project/runtime@0.121.0': {} - - '@oxc-project/types@0.122.0': {} - - '@oxfmt/binding-android-arm-eabi@0.42.0': - optional: true - - '@oxfmt/binding-android-arm64@0.42.0': - optional: true - - '@oxfmt/binding-darwin-arm64@0.42.0': - optional: true - - '@oxfmt/binding-darwin-x64@0.42.0': - optional: true - - '@oxfmt/binding-freebsd-x64@0.42.0': - optional: true - - '@oxfmt/binding-linux-arm-gnueabihf@0.42.0': - optional: true - - '@oxfmt/binding-linux-arm-musleabihf@0.42.0': - optional: true - - '@oxfmt/binding-linux-arm64-gnu@0.42.0': - optional: true - - '@oxfmt/binding-linux-arm64-musl@0.42.0': - optional: true - - '@oxfmt/binding-linux-ppc64-gnu@0.42.0': - optional: true - - '@oxfmt/binding-linux-riscv64-gnu@0.42.0': - optional: true - - '@oxfmt/binding-linux-riscv64-musl@0.42.0': - optional: true - - '@oxfmt/binding-linux-s390x-gnu@0.42.0': - optional: true - - '@oxfmt/binding-linux-x64-gnu@0.42.0': - optional: true - - '@oxfmt/binding-linux-x64-musl@0.42.0': - optional: true - - '@oxfmt/binding-openharmony-arm64@0.42.0': - optional: true - - '@oxfmt/binding-win32-arm64-msvc@0.42.0': - optional: true - - '@oxfmt/binding-win32-ia32-msvc@0.42.0': - optional: true - - '@oxfmt/binding-win32-x64-msvc@0.42.0': - optional: true - - '@oxlint-tsgolint/darwin-arm64@0.17.3': - optional: true - - '@oxlint-tsgolint/darwin-x64@0.17.3': - optional: true - - '@oxlint-tsgolint/linux-arm64@0.17.3': - optional: true - - '@oxlint-tsgolint/linux-x64@0.17.3': - optional: true - - '@oxlint-tsgolint/win32-arm64@0.17.3': - optional: true - - '@oxlint-tsgolint/win32-x64@0.17.3': - optional: true - - '@oxlint/binding-android-arm-eabi@1.57.0': - optional: true - - '@oxlint/binding-android-arm64@1.57.0': - optional: true - - '@oxlint/binding-darwin-arm64@1.57.0': - optional: true - - '@oxlint/binding-darwin-x64@1.57.0': - optional: true - - '@oxlint/binding-freebsd-x64@1.57.0': - optional: true - - '@oxlint/binding-linux-arm-gnueabihf@1.57.0': - optional: true - - '@oxlint/binding-linux-arm-musleabihf@1.57.0': - optional: true - - '@oxlint/binding-linux-arm64-gnu@1.57.0': - optional: true - - '@oxlint/binding-linux-arm64-musl@1.57.0': - optional: true - - '@oxlint/binding-linux-ppc64-gnu@1.57.0': - optional: true - - '@oxlint/binding-linux-riscv64-gnu@1.57.0': - optional: true - - '@oxlint/binding-linux-riscv64-musl@1.57.0': - optional: true - - '@oxlint/binding-linux-s390x-gnu@1.57.0': - optional: true - - '@oxlint/binding-linux-x64-gnu@1.57.0': - optional: true - - '@oxlint/binding-linux-x64-musl@1.57.0': - optional: true - - '@oxlint/binding-openharmony-arm64@1.57.0': - optional: true - - '@oxlint/binding-win32-arm64-msvc@1.57.0': - optional: true - - '@oxlint/binding-win32-ia32-msvc@1.57.0': - optional: true - - '@oxlint/binding-win32-x64-msvc@1.57.0': - optional: true - - '@playwright/test@1.51.1': - dependencies: - playwright: 1.51.1 - - '@polka/url@1.0.0-next.29': {} - - '@rolldown/binding-android-arm64@1.0.0-rc.12': - optional: true - - '@rolldown/binding-darwin-arm64@1.0.0-rc.12': - optional: true - - '@rolldown/binding-darwin-x64@1.0.0-rc.12': - optional: true - - '@rolldown/binding-freebsd-x64@1.0.0-rc.12': - optional: true - - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.12': - optional: true - - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.12': - optional: true - - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.12': - optional: true - - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.12': - optional: true - - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.12': - optional: true - - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.12': - optional: true - - '@rolldown/binding-linux-x64-musl@1.0.0-rc.12': - optional: true - - '@rolldown/binding-openharmony-arm64@1.0.0-rc.12': - optional: true - - '@rolldown/binding-wasm32-wasi@1.0.0-rc.12': - dependencies: - '@napi-rs/wasm-runtime': 1.1.1 - optional: true - - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.12': - optional: true - - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.12': - optional: true - - '@rolldown/pluginutils@1.0.0-rc.12': {} - - '@standard-schema/spec@1.1.0': {} - - '@teppeis/multimaps@3.0.0': {} - - '@tybys/wasm-util@0.10.1': - dependencies: - tslib: 2.8.1 - optional: true - - '@types/chai@5.2.3': - dependencies: - '@types/deep-eql': 4.0.2 - assertion-error: 2.0.1 - - '@types/deep-eql@4.0.2': {} - - '@types/node@25.5.0': - dependencies: - undici-types: 7.18.2 - - '@types/normalize-package-data@2.4.4': {} - - '@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.4)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)': - dependencies: - '@oxc-project/runtime': 0.121.0 - '@oxc-project/types': 0.122.0 - lightningcss: 1.32.0 - postcss: 8.5.8 - optionalDependencies: - '@types/node': 25.5.0 - esbuild: 0.27.4 - fsevents: 2.3.3 - tsx: 4.21.0 - typescript: 5.9.3 - yaml: 2.8.3 - - '@voidzero-dev/vite-plus-darwin-arm64@0.1.14': - optional: true - - '@voidzero-dev/vite-plus-darwin-x64@0.1.14': - optional: true - - '@voidzero-dev/vite-plus-linux-arm64-gnu@0.1.14': - optional: true - - '@voidzero-dev/vite-plus-linux-arm64-musl@0.1.14': - optional: true - - '@voidzero-dev/vite-plus-linux-x64-gnu@0.1.14': - optional: true - - '@voidzero-dev/vite-plus-linux-x64-musl@0.1.14': - optional: true - - '@voidzero-dev/vite-plus-test@0.1.14(@types/node@25.5.0)(esbuild@0.27.4)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.3(@types/node@25.5.0)(esbuild@0.27.4)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)': - dependencies: - '@standard-schema/spec': 1.1.0 - '@types/chai': 5.2.3 - '@voidzero-dev/vite-plus-core': 0.1.14(@types/node@25.5.0)(esbuild@0.27.4)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) - es-module-lexer: 1.7.0 - obug: 2.1.1 - pixelmatch: 7.1.0 - pngjs: 7.0.0 - sirv: 3.0.2 - std-env: 4.0.0 - tinybench: 2.9.0 - tinyexec: 1.0.4 - tinyglobby: 0.2.15 - vite: 8.0.3(@types/node@25.5.0)(esbuild@0.27.4)(tsx@4.21.0)(yaml@2.8.3) - ws: 8.20.0 - optionalDependencies: - '@types/node': 25.5.0 - transitivePeerDependencies: - - '@arethetypeswrong/core' - - '@tsdown/css' - - '@tsdown/exe' - - '@vitejs/devtools' - - bufferutil - - esbuild - - jiti - - less - - publint - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - typescript - - unplugin-unused - - utf-8-validate - - yaml - - '@voidzero-dev/vite-plus-win32-arm64-msvc@0.1.14': - optional: true - - '@voidzero-dev/vite-plus-win32-x64-msvc@0.1.14': - optional: true - - ansi-regex@4.1.1: {} - - ansi-regex@5.0.1: {} - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - ansi-styles@5.2.0: {} - - any-promise@1.3.0: {} - - assertion-error-formatter@3.0.0: - dependencies: - diff: 4.0.4 - pad-right: 0.2.2 - repeat-string: 1.6.1 - - assertion-error@2.0.1: {} - - balanced-match@4.0.4: {} - - brace-expansion@5.0.5: - dependencies: - balanced-match: 4.0.4 - - buffer-from@1.1.2: {} - - cac@7.0.0: {} - - capital-case@1.0.4: - dependencies: - no-case: 3.0.4 - tslib: 2.8.1 - upper-case-first: 2.0.2 - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - class-transformer@0.5.1: {} - - cli-table3@0.6.5: - dependencies: - string-width: 4.2.3 - optionalDependencies: - '@colors/colors': 1.5.0 - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.4: {} - - commander@14.0.0: {} - - commander@14.0.2: {} - - commander@14.0.3: {} - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - debug@4.4.3(supports-color@8.1.1): - dependencies: - ms: 2.1.3 - optionalDependencies: - supports-color: 8.1.1 - - detect-libc@2.1.2: {} - - diff@4.0.4: {} - - emoji-regex@8.0.0: {} - - error-stack-parser@2.1.4: - dependencies: - stackframe: 1.3.4 - - es-module-lexer@1.7.0: {} - - esbuild@0.27.4: - optionalDependencies: - '@esbuild/aix-ppc64': 0.27.4 - '@esbuild/android-arm': 0.27.4 - '@esbuild/android-arm64': 0.27.4 - '@esbuild/android-x64': 0.27.4 - '@esbuild/darwin-arm64': 0.27.4 - '@esbuild/darwin-x64': 0.27.4 - '@esbuild/freebsd-arm64': 0.27.4 - '@esbuild/freebsd-x64': 0.27.4 - '@esbuild/linux-arm': 0.27.4 - '@esbuild/linux-arm64': 0.27.4 - '@esbuild/linux-ia32': 0.27.4 - '@esbuild/linux-loong64': 0.27.4 - '@esbuild/linux-mips64el': 0.27.4 - '@esbuild/linux-ppc64': 0.27.4 - '@esbuild/linux-riscv64': 0.27.4 - '@esbuild/linux-s390x': 0.27.4 - '@esbuild/linux-x64': 0.27.4 - '@esbuild/netbsd-arm64': 0.27.4 - '@esbuild/netbsd-x64': 0.27.4 - '@esbuild/openbsd-arm64': 0.27.4 - '@esbuild/openbsd-x64': 0.27.4 - '@esbuild/openharmony-arm64': 0.27.4 - '@esbuild/sunos-x64': 0.27.4 - '@esbuild/win32-arm64': 0.27.4 - '@esbuild/win32-ia32': 0.27.4 - '@esbuild/win32-x64': 0.27.4 - - escape-string-regexp@1.0.5: {} - - fdir@6.5.0(picomatch@4.0.4): - optionalDependencies: - picomatch: 4.0.4 - - figures@3.2.0: - dependencies: - escape-string-regexp: 1.0.5 - - find-up-simple@1.0.1: {} - - fsevents@2.3.2: - optional: true - - fsevents@2.3.3: - optional: true - - get-tsconfig@4.13.7: - dependencies: - resolve-pkg-maps: 1.0.0 - - glob@13.0.6: - dependencies: - minimatch: 10.2.4 - minipass: 7.1.3 - path-scurry: 2.0.2 - - global-dirs@3.0.1: - dependencies: - ini: 2.0.0 - - has-ansi@4.0.1: - dependencies: - ansi-regex: 4.1.1 - - has-flag@4.0.0: {} - - hosted-git-info@9.0.2: - dependencies: - lru-cache: 11.2.7 - - indent-string@4.0.0: {} - - index-to-position@1.2.0: {} - - ini@2.0.0: {} - - is-fullwidth-code-point@3.0.0: {} - - is-installed-globally@0.4.0: - dependencies: - global-dirs: 3.0.1 - is-path-inside: 3.0.3 - - is-path-inside@3.0.3: {} - - is-stream@2.0.1: {} - - isexe@2.0.0: {} - - js-tokens@4.0.0: {} - - knuth-shuffle-seeded@1.0.6: - dependencies: - seed-random: 2.2.0 - - lightningcss-android-arm64@1.32.0: - optional: true - - lightningcss-darwin-arm64@1.32.0: - optional: true - - lightningcss-darwin-x64@1.32.0: - optional: true - - lightningcss-freebsd-x64@1.32.0: - optional: true - - lightningcss-linux-arm-gnueabihf@1.32.0: - optional: true - - lightningcss-linux-arm64-gnu@1.32.0: - optional: true - - lightningcss-linux-arm64-musl@1.32.0: - optional: true - - lightningcss-linux-x64-gnu@1.32.0: - optional: true - - lightningcss-linux-x64-musl@1.32.0: - optional: true - - lightningcss-win32-arm64-msvc@1.32.0: - optional: true - - lightningcss-win32-x64-msvc@1.32.0: - optional: true - - lightningcss@1.32.0: - dependencies: - detect-libc: 2.1.2 - optionalDependencies: - lightningcss-android-arm64: 1.32.0 - lightningcss-darwin-arm64: 1.32.0 - lightningcss-darwin-x64: 1.32.0 - lightningcss-freebsd-x64: 1.32.0 - lightningcss-linux-arm-gnueabihf: 1.32.0 - lightningcss-linux-arm64-gnu: 1.32.0 - lightningcss-linux-arm64-musl: 1.32.0 - lightningcss-linux-x64-gnu: 1.32.0 - lightningcss-linux-x64-musl: 1.32.0 - lightningcss-win32-arm64-msvc: 1.32.0 - lightningcss-win32-x64-msvc: 1.32.0 - - lodash.merge@4.6.2: {} - - lodash.mergewith@4.6.2: {} - - lodash.sortby@4.7.0: {} - - lower-case@2.0.2: - dependencies: - tslib: 2.8.1 - - lru-cache@11.2.7: {} - - luxon@3.7.2: {} - - mime@3.0.0: {} - - minimatch@10.2.4: - dependencies: - brace-expansion: 5.0.5 - - minipass@7.1.3: {} - - mkdirp@3.0.1: {} - - mrmime@2.0.1: {} - - ms@2.1.3: {} - - mz@2.7.0: - dependencies: - any-promise: 1.3.0 - object-assign: 4.1.1 - thenify-all: 1.6.0 - - nanoid@3.3.11: {} - - no-case@3.0.4: - dependencies: - lower-case: 2.0.2 - tslib: 2.8.1 - - normalize-package-data@8.0.0: - dependencies: - hosted-git-info: 9.0.2 - semver: 7.7.4 - validate-npm-package-license: 3.0.4 - - object-assign@4.1.1: {} - - obug@2.1.1: {} - - oxfmt@0.42.0: - dependencies: - tinypool: 2.1.0 - optionalDependencies: - '@oxfmt/binding-android-arm-eabi': 0.42.0 - '@oxfmt/binding-android-arm64': 0.42.0 - '@oxfmt/binding-darwin-arm64': 0.42.0 - '@oxfmt/binding-darwin-x64': 0.42.0 - '@oxfmt/binding-freebsd-x64': 0.42.0 - '@oxfmt/binding-linux-arm-gnueabihf': 0.42.0 - '@oxfmt/binding-linux-arm-musleabihf': 0.42.0 - '@oxfmt/binding-linux-arm64-gnu': 0.42.0 - '@oxfmt/binding-linux-arm64-musl': 0.42.0 - '@oxfmt/binding-linux-ppc64-gnu': 0.42.0 - '@oxfmt/binding-linux-riscv64-gnu': 0.42.0 - '@oxfmt/binding-linux-riscv64-musl': 0.42.0 - '@oxfmt/binding-linux-s390x-gnu': 0.42.0 - '@oxfmt/binding-linux-x64-gnu': 0.42.0 - '@oxfmt/binding-linux-x64-musl': 0.42.0 - '@oxfmt/binding-openharmony-arm64': 0.42.0 - '@oxfmt/binding-win32-arm64-msvc': 0.42.0 - '@oxfmt/binding-win32-ia32-msvc': 0.42.0 - '@oxfmt/binding-win32-x64-msvc': 0.42.0 - - oxlint-tsgolint@0.17.3: - optionalDependencies: - '@oxlint-tsgolint/darwin-arm64': 0.17.3 - '@oxlint-tsgolint/darwin-x64': 0.17.3 - '@oxlint-tsgolint/linux-arm64': 0.17.3 - '@oxlint-tsgolint/linux-x64': 0.17.3 - '@oxlint-tsgolint/win32-arm64': 0.17.3 - '@oxlint-tsgolint/win32-x64': 0.17.3 - - oxlint@1.57.0(oxlint-tsgolint@0.17.3): - optionalDependencies: - '@oxlint/binding-android-arm-eabi': 1.57.0 - '@oxlint/binding-android-arm64': 1.57.0 - '@oxlint/binding-darwin-arm64': 1.57.0 - '@oxlint/binding-darwin-x64': 1.57.0 - '@oxlint/binding-freebsd-x64': 1.57.0 - '@oxlint/binding-linux-arm-gnueabihf': 1.57.0 - '@oxlint/binding-linux-arm-musleabihf': 1.57.0 - '@oxlint/binding-linux-arm64-gnu': 1.57.0 - '@oxlint/binding-linux-arm64-musl': 1.57.0 - '@oxlint/binding-linux-ppc64-gnu': 1.57.0 - '@oxlint/binding-linux-riscv64-gnu': 1.57.0 - '@oxlint/binding-linux-riscv64-musl': 1.57.0 - '@oxlint/binding-linux-s390x-gnu': 1.57.0 - '@oxlint/binding-linux-x64-gnu': 1.57.0 - '@oxlint/binding-linux-x64-musl': 1.57.0 - '@oxlint/binding-openharmony-arm64': 1.57.0 - '@oxlint/binding-win32-arm64-msvc': 1.57.0 - '@oxlint/binding-win32-ia32-msvc': 1.57.0 - '@oxlint/binding-win32-x64-msvc': 1.57.0 - oxlint-tsgolint: 0.17.3 - - pad-right@0.2.2: - dependencies: - repeat-string: 1.6.1 - - parse-json@8.3.0: - dependencies: - '@babel/code-frame': 7.29.0 - index-to-position: 1.2.0 - type-fest: 4.41.0 - - path-key@3.1.1: {} - - path-scurry@2.0.2: - dependencies: - lru-cache: 11.2.7 - minipass: 7.1.3 - - picocolors@1.1.1: {} - - picomatch@4.0.4: {} - - pixelmatch@7.1.0: - dependencies: - pngjs: 7.0.0 - - playwright-core@1.51.1: {} - - playwright@1.51.1: - dependencies: - playwright-core: 1.51.1 - optionalDependencies: - fsevents: 2.3.2 - - pngjs@7.0.0: {} - - postcss@8.5.8: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - progress@2.0.3: {} - - property-expr@2.0.6: {} - - read-package-up@12.0.0: - dependencies: - find-up-simple: 1.0.1 - read-pkg: 10.1.0 - type-fest: 5.5.0 - - read-pkg@10.1.0: - dependencies: - '@types/normalize-package-data': 2.4.4 - normalize-package-data: 8.0.0 - parse-json: 8.3.0 - type-fest: 5.5.0 - unicorn-magic: 0.4.0 - - reflect-metadata@0.2.2: {} - - regexp-match-indices@1.0.2: - dependencies: - regexp-tree: 0.1.27 - - regexp-tree@0.1.27: {} - - repeat-string@1.6.1: {} - - resolve-pkg-maps@1.0.0: {} - - rolldown@1.0.0-rc.12: - dependencies: - '@oxc-project/types': 0.122.0 - '@rolldown/pluginutils': 1.0.0-rc.12 - optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-rc.12 - '@rolldown/binding-darwin-arm64': 1.0.0-rc.12 - '@rolldown/binding-darwin-x64': 1.0.0-rc.12 - '@rolldown/binding-freebsd-x64': 1.0.0-rc.12 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.12 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.12 - '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.12 - '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.12 - '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.12 - '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.12 - '@rolldown/binding-linux-x64-musl': 1.0.0-rc.12 - '@rolldown/binding-openharmony-arm64': 1.0.0-rc.12 - '@rolldown/binding-wasm32-wasi': 1.0.0-rc.12 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.12 - '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.12 - - seed-random@2.2.0: {} - - semver@7.7.4: {} - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - sirv@3.0.2: - dependencies: - '@polka/url': 1.0.0-next.29 - mrmime: 2.0.1 - totalist: 3.0.1 - - source-map-js@1.2.1: {} - - source-map-support@0.5.21: - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - - source-map@0.6.1: {} - - spdx-correct@3.2.0: - dependencies: - spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.23 - - spdx-exceptions@2.5.0: {} - - spdx-expression-parse@3.0.1: - dependencies: - spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.23 - - spdx-license-ids@3.0.23: {} - - stackframe@1.3.4: {} - - std-env@4.0.0: {} - - string-argv@0.3.1: {} - - string-width@4.2.3: - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - - strip-ansi@6.0.1: - dependencies: - ansi-regex: 5.0.1 - - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - - supports-color@8.1.1: - dependencies: - has-flag: 4.0.0 - - tagged-tag@1.0.0: {} - - thenify-all@1.6.0: - dependencies: - thenify: 3.3.1 - - thenify@3.3.1: - dependencies: - any-promise: 1.3.0 - - tiny-case@1.0.3: {} - - tinybench@2.9.0: {} - - tinyexec@1.0.4: {} - - tinyglobby@0.2.15: - dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 - - tinypool@2.1.0: {} - - toposort@2.0.2: {} - - totalist@3.0.1: {} - - ts-dedent@2.2.0: {} - - tslib@2.8.1: {} - - tsx@4.21.0: - dependencies: - esbuild: 0.27.4 - get-tsconfig: 4.13.7 - optionalDependencies: - fsevents: 2.3.3 - - type-fest@2.19.0: {} - - type-fest@4.41.0: {} - - type-fest@5.5.0: - dependencies: - tagged-tag: 1.0.0 - - typescript@5.9.3: {} - - undici-types@7.18.2: {} - - unicorn-magic@0.4.0: {} - - upper-case-first@2.0.2: - dependencies: - tslib: 2.8.1 - - util-arity@1.1.0: {} - - validate-npm-package-license@3.0.4: - dependencies: - spdx-correct: 3.2.0 - spdx-expression-parse: 3.0.1 - - vite-plus@0.1.14(@types/node@25.5.0)(esbuild@0.27.4)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.3(@types/node@25.5.0)(esbuild@0.27.4)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3): - dependencies: - '@oxc-project/types': 0.122.0 - '@voidzero-dev/vite-plus-core': 0.1.14(@types/node@25.5.0)(esbuild@0.27.4)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) - '@voidzero-dev/vite-plus-test': 0.1.14(@types/node@25.5.0)(esbuild@0.27.4)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.3(@types/node@25.5.0)(esbuild@0.27.4)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) - cac: 7.0.0 - cross-spawn: 7.0.6 - oxfmt: 0.42.0 - oxlint: 1.57.0(oxlint-tsgolint@0.17.3) - oxlint-tsgolint: 0.17.3 - picocolors: 1.1.1 - optionalDependencies: - '@voidzero-dev/vite-plus-darwin-arm64': 0.1.14 - '@voidzero-dev/vite-plus-darwin-x64': 0.1.14 - '@voidzero-dev/vite-plus-linux-arm64-gnu': 0.1.14 - '@voidzero-dev/vite-plus-linux-arm64-musl': 0.1.14 - '@voidzero-dev/vite-plus-linux-x64-gnu': 0.1.14 - '@voidzero-dev/vite-plus-linux-x64-musl': 0.1.14 - '@voidzero-dev/vite-plus-win32-arm64-msvc': 0.1.14 - '@voidzero-dev/vite-plus-win32-x64-msvc': 0.1.14 - transitivePeerDependencies: - - '@arethetypeswrong/core' - - '@edge-runtime/vm' - - '@opentelemetry/api' - - '@tsdown/css' - - '@tsdown/exe' - - '@types/node' - - '@vitejs/devtools' - - '@vitest/ui' - - bufferutil - - esbuild - - happy-dom - - jiti - - jsdom - - less - - publint - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - typescript - - unplugin-unused - - utf-8-validate - - vite - - yaml - - vite@8.0.3(@types/node@25.5.0)(esbuild@0.27.4)(tsx@4.21.0)(yaml@2.8.3): - dependencies: - lightningcss: 1.32.0 - picomatch: 4.0.4 - postcss: 8.5.8 - rolldown: 1.0.0-rc.12 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 25.5.0 - esbuild: 0.27.4 - fsevents: 2.3.3 - tsx: 4.21.0 - yaml: 2.8.3 - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - ws@8.20.0: {} - - xmlbuilder@15.1.1: {} - - yaml@2.8.3: {} - - yup@1.7.1: - dependencies: - property-expr: 2.0.6 - tiny-case: 1.0.3 - toposort: 2.0.2 - type-fest: 2.19.0 diff --git a/package.json b/package.json new file mode 100644 index 0000000000..07f1e16153 --- /dev/null +++ b/package.json @@ -0,0 +1,11 @@ +{ + "name": "dify", + "private": true, + "engines": { + "node": "^22.22.1" + }, + "packageManager": "pnpm@10.33.0", + "devDependencies": { + "taze": "catalog:" + } +} diff --git a/web/pnpm-lock.yaml b/pnpm-lock.yaml similarity index 77% rename from web/pnpm-lock.yaml rename to pnpm-lock.yaml index cd1a8a8556..01a96c5585 100644 --- a/web/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,564 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +catalogs: + default: + '@amplitude/analytics-browser': + specifier: 2.38.0 + version: 2.38.0 + '@amplitude/plugin-session-replay-browser': + specifier: 1.27.5 + version: 1.27.5 + '@antfu/eslint-config': + specifier: 7.7.3 + version: 7.7.3 + '@base-ui/react': + specifier: 1.3.0 + version: 1.3.0 + '@chromatic-com/storybook': + specifier: 5.1.1 + version: 5.1.1 + '@cucumber/cucumber': + specifier: 12.7.0 + version: 12.7.0 + '@egoist/tailwindcss-icons': + specifier: 1.9.2 + version: 1.9.2 + '@emoji-mart/data': + specifier: 1.2.1 + version: 1.2.1 + '@eslint-react/eslint-plugin': + specifier: 3.0.0 + version: 3.0.0 + '@eslint/js': + specifier: ^10.0.1 + version: 10.0.1 + '@floating-ui/react': + specifier: 0.27.19 + version: 0.27.19 + '@formatjs/intl-localematcher': + specifier: 0.8.2 + version: 0.8.2 + '@headlessui/react': + specifier: 2.2.9 + version: 2.2.9 + '@heroicons/react': + specifier: 2.2.0 + version: 2.2.0 + '@hono/node-server': + specifier: 1.19.11 + version: 1.19.11 + '@iconify-json/heroicons': + specifier: 1.2.3 + version: 1.2.3 + '@iconify-json/ri': + specifier: 1.2.10 + version: 1.2.10 + '@lexical/link': + specifier: 0.42.0 + version: 0.42.0 + '@lexical/list': + specifier: 0.42.0 + version: 0.42.0 + '@lexical/react': + specifier: 0.42.0 + version: 0.42.0 + '@lexical/selection': + specifier: 0.42.0 + version: 0.42.0 + '@lexical/text': + specifier: 0.42.0 + version: 0.42.0 + '@lexical/utils': + specifier: 0.42.0 + version: 0.42.0 + '@mdx-js/loader': + specifier: 3.1.1 + version: 3.1.1 + '@mdx-js/react': + specifier: 3.1.1 + version: 3.1.1 + '@mdx-js/rollup': + specifier: 3.1.1 + version: 3.1.1 + '@monaco-editor/react': + specifier: 4.7.0 + version: 4.7.0 + '@next/eslint-plugin-next': + specifier: 16.2.1 + version: 16.2.1 + '@next/mdx': + specifier: 16.2.1 + version: 16.2.1 + '@orpc/client': + specifier: 1.13.13 + version: 1.13.13 + '@orpc/contract': + specifier: 1.13.13 + version: 1.13.13 + '@orpc/openapi-client': + specifier: 1.13.13 + version: 1.13.13 + '@orpc/tanstack-query': + specifier: 1.13.13 + version: 1.13.13 + '@playwright/test': + specifier: 1.58.2 + version: 1.58.2 + '@remixicon/react': + specifier: 4.9.0 + version: 4.9.0 + '@rgrove/parse-xml': + specifier: 4.2.0 + version: 4.2.0 + '@sentry/react': + specifier: 10.46.0 + version: 10.46.0 + '@storybook/addon-docs': + specifier: 10.3.3 + version: 10.3.3 + '@storybook/addon-links': + specifier: 10.3.3 + version: 10.3.3 + '@storybook/addon-onboarding': + specifier: 10.3.3 + version: 10.3.3 + '@storybook/addon-themes': + specifier: 10.3.3 + version: 10.3.3 + '@storybook/nextjs-vite': + specifier: 10.3.3 + version: 10.3.3 + '@storybook/react': + specifier: 10.3.3 + version: 10.3.3 + '@streamdown/math': + specifier: 1.0.2 + version: 1.0.2 + '@svgdotjs/svg.js': + specifier: 3.2.5 + version: 3.2.5 + '@t3-oss/env-nextjs': + specifier: 0.13.11 + version: 0.13.11 + '@tailwindcss/typography': + specifier: 0.5.19 + version: 0.5.19 + '@tanstack/eslint-plugin-query': + specifier: 5.95.2 + version: 5.95.2 + '@tanstack/react-devtools': + specifier: 0.10.0 + version: 0.10.0 + '@tanstack/react-form': + specifier: 1.28.5 + version: 1.28.5 + '@tanstack/react-form-devtools': + specifier: 0.2.19 + version: 0.2.19 + '@tanstack/react-query': + specifier: 5.95.2 + version: 5.95.2 + '@tanstack/react-query-devtools': + specifier: 5.95.2 + version: 5.95.2 + '@testing-library/dom': + specifier: 10.4.1 + version: 10.4.1 + '@testing-library/jest-dom': + specifier: 6.9.1 + version: 6.9.1 + '@testing-library/react': + specifier: 16.3.2 + version: 16.3.2 + '@testing-library/user-event': + specifier: 14.6.1 + version: 14.6.1 + '@tsslint/cli': + specifier: 3.0.2 + version: 3.0.2 + '@tsslint/compat-eslint': + specifier: 3.0.2 + version: 3.0.2 + '@tsslint/config': + specifier: 3.0.2 + version: 3.0.2 + '@types/js-cookie': + specifier: 3.0.6 + version: 3.0.6 + '@types/js-yaml': + specifier: 4.0.9 + version: 4.0.9 + '@types/negotiator': + specifier: 0.6.4 + version: 0.6.4 + '@types/node': + specifier: 25.5.0 + version: 25.5.0 + '@types/postcss-js': + specifier: 4.1.0 + version: 4.1.0 + '@types/qs': + specifier: 6.15.0 + version: 6.15.0 + '@types/react': + specifier: 19.2.14 + version: 19.2.14 + '@types/react-dom': + specifier: 19.2.3 + version: 19.2.3 + '@types/react-syntax-highlighter': + specifier: 15.5.13 + version: 15.5.13 + '@types/react-window': + specifier: 1.8.8 + version: 1.8.8 + '@types/sortablejs': + specifier: 1.15.9 + version: 1.15.9 + '@typescript-eslint/eslint-plugin': + specifier: ^8.57.2 + version: 8.57.2 + '@typescript-eslint/parser': + specifier: 8.57.2 + version: 8.57.2 + '@typescript/native-preview': + specifier: 7.0.0-dev.20260329.1 + version: 7.0.0-dev.20260329.1 + '@vitejs/plugin-react': + specifier: 6.0.1 + version: 6.0.1 + '@vitejs/plugin-rsc': + specifier: 0.5.21 + version: 0.5.21 + '@vitest/coverage-v8': + specifier: 4.1.2 + version: 4.1.2 + abcjs: + specifier: 6.6.2 + version: 6.6.2 + agentation: + specifier: 3.0.2 + version: 3.0.2 + ahooks: + specifier: 3.9.7 + version: 3.9.7 + autoprefixer: + specifier: 10.4.27 + version: 10.4.27 + axios: + specifier: ^1.14.0 + version: 1.14.0 + class-variance-authority: + specifier: 0.7.1 + version: 0.7.1 + clsx: + specifier: 2.1.1 + version: 2.1.1 + cmdk: + specifier: 1.1.1 + version: 1.1.1 + code-inspector-plugin: + specifier: 1.4.5 + version: 1.4.5 + copy-to-clipboard: + specifier: 3.3.3 + version: 3.3.3 + cron-parser: + specifier: 5.5.0 + version: 5.5.0 + dayjs: + specifier: 1.11.20 + version: 1.11.20 + decimal.js: + specifier: 10.6.0 + version: 10.6.0 + dompurify: + specifier: 3.3.3 + version: 3.3.3 + echarts: + specifier: 6.0.0 + version: 6.0.0 + echarts-for-react: + specifier: 3.0.6 + version: 3.0.6 + elkjs: + specifier: 0.11.1 + version: 0.11.1 + embla-carousel-autoplay: + specifier: 8.6.0 + version: 8.6.0 + embla-carousel-react: + specifier: 8.6.0 + version: 8.6.0 + emoji-mart: + specifier: 5.6.0 + version: 5.6.0 + es-toolkit: + specifier: 1.45.1 + version: 1.45.1 + eslint: + specifier: 10.1.0 + version: 10.1.0 + eslint-markdown: + specifier: 0.6.0 + version: 0.6.0 + eslint-plugin-better-tailwindcss: + specifier: 4.3.2 + version: 4.3.2 + eslint-plugin-hyoban: + specifier: 0.14.1 + version: 0.14.1 + eslint-plugin-markdown-preferences: + specifier: 0.40.3 + version: 0.40.3 + eslint-plugin-no-barrel-files: + specifier: 1.2.2 + version: 1.2.2 + eslint-plugin-react-hooks: + specifier: 7.0.1 + version: 7.0.1 + eslint-plugin-react-refresh: + specifier: 0.5.2 + version: 0.5.2 + eslint-plugin-sonarjs: + specifier: 4.0.2 + version: 4.0.2 + eslint-plugin-storybook: + specifier: 10.3.3 + version: 10.3.3 + fast-deep-equal: + specifier: 3.1.3 + version: 3.1.3 + foxact: + specifier: 0.3.0 + version: 0.3.0 + happy-dom: + specifier: 20.8.9 + version: 20.8.9 + hono: + specifier: 4.12.9 + version: 4.12.9 + html-entities: + specifier: 2.6.0 + version: 2.6.0 + html-to-image: + specifier: 1.11.13 + version: 1.11.13 + husky: + specifier: 9.1.7 + version: 9.1.7 + i18next: + specifier: 25.10.10 + version: 25.10.10 + i18next-resources-to-backend: + specifier: 1.2.1 + version: 1.2.1 + iconify-import-svg: + specifier: 0.1.2 + version: 0.1.2 + immer: + specifier: 11.1.4 + version: 11.1.4 + jotai: + specifier: 2.19.0 + version: 2.19.0 + js-audio-recorder: + specifier: 1.0.7 + version: 1.0.7 + js-cookie: + specifier: 3.0.5 + version: 3.0.5 + js-yaml: + specifier: 4.1.1 + version: 4.1.1 + jsonschema: + specifier: 1.5.0 + version: 1.5.0 + katex: + specifier: 0.16.44 + version: 0.16.44 + knip: + specifier: 6.1.0 + version: 6.1.0 + ky: + specifier: 1.14.3 + version: 1.14.3 + lamejs: + specifier: 1.2.1 + version: 1.2.1 + lexical: + specifier: 0.42.0 + version: 0.42.0 + lint-staged: + specifier: 16.4.0 + version: 16.4.0 + mermaid: + specifier: 11.13.0 + version: 11.13.0 + mime: + specifier: 4.1.0 + version: 4.1.0 + mitt: + specifier: 3.0.1 + version: 3.0.1 + negotiator: + specifier: 1.0.0 + version: 1.0.0 + next: + specifier: 16.2.1 + version: 16.2.1 + next-themes: + specifier: 0.4.6 + version: 0.4.6 + nuqs: + specifier: 2.8.9 + version: 2.8.9 + pinyin-pro: + specifier: 3.28.0 + version: 3.28.0 + postcss: + specifier: 8.5.8 + version: 8.5.8 + postcss-js: + specifier: 5.1.0 + version: 5.1.0 + qrcode.react: + specifier: 4.2.0 + version: 4.2.0 + qs: + specifier: 6.15.0 + version: 6.15.0 + react: + specifier: 19.2.4 + version: 19.2.4 + react-18-input-autosize: + specifier: 3.0.0 + version: 3.0.0 + react-dom: + specifier: 19.2.4 + version: 19.2.4 + react-easy-crop: + specifier: 5.5.7 + version: 5.5.7 + react-hotkeys-hook: + specifier: 5.2.4 + version: 5.2.4 + react-i18next: + specifier: 16.6.6 + version: 16.6.6 + react-multi-email: + specifier: 1.0.25 + version: 1.0.25 + react-papaparse: + specifier: 4.4.0 + version: 4.4.0 + react-pdf-highlighter: + specifier: 8.0.0-rc.0 + version: 8.0.0-rc.0 + react-server-dom-webpack: + specifier: 19.2.4 + version: 19.2.4 + react-sortablejs: + specifier: 6.1.4 + version: 6.1.4 + react-syntax-highlighter: + specifier: 15.6.6 + version: 15.6.6 + react-textarea-autosize: + specifier: 8.5.9 + version: 8.5.9 + react-window: + specifier: 1.8.11 + version: 1.8.11 + reactflow: + specifier: 11.11.4 + version: 11.11.4 + remark-breaks: + specifier: 4.0.0 + version: 4.0.0 + remark-directive: + specifier: 4.0.0 + version: 4.0.0 + sass: + specifier: 1.98.0 + version: 1.98.0 + scheduler: + specifier: 0.27.0 + version: 0.27.0 + sharp: + specifier: 0.34.5 + version: 0.34.5 + sortablejs: + specifier: 1.15.7 + version: 1.15.7 + std-semver: + specifier: 1.0.8 + version: 1.0.8 + storybook: + specifier: 10.3.3 + version: 10.3.3 + streamdown: + specifier: 2.5.0 + version: 2.5.0 + string-ts: + specifier: 2.3.1 + version: 2.3.1 + tailwind-merge: + specifier: 2.6.1 + version: 2.6.1 + tailwindcss: + specifier: 3.4.19 + version: 3.4.19 + taze: + specifier: 19.10.0 + version: 19.10.0 + tldts: + specifier: 7.0.27 + version: 7.0.27 + tsup: + specifier: ^8.5.1 + version: 8.5.1 + tsx: + specifier: 4.21.0 + version: 4.21.0 + typescript: + specifier: 5.9.3 + version: 5.9.3 + uglify-js: + specifier: 3.19.3 + version: 3.19.3 + unist-util-visit: + specifier: 5.1.0 + version: 5.1.0 + use-context-selector: + specifier: 2.0.0 + version: 2.0.0 + uuid: + specifier: 13.0.0 + version: 13.0.0 + vinext: + specifier: 0.0.38 + version: 0.0.38 + vite-plugin-inspect: + specifier: 12.0.0-beta.1 + version: 12.0.0-beta.1 + vite-plus: + specifier: 0.1.14 + version: 0.1.14 + vitest-canvas-mock: + specifier: 1.1.4 + version: 1.1.4 + zod: + specifier: 4.3.6 + version: 4.3.6 + zundo: + specifier: 2.3.0 + version: 2.3.0 + zustand: + specifier: 5.0.12 + version: 5.0.12 + overrides: '@lexical/code': npm:lexical-code-no-prism@0.41.0 '@monaco-editor/loader': 1.7.0 @@ -21,6 +579,7 @@ overrides: dompurify@>=3.1.3 <=3.3.1: 3.3.2 es-iterator-helpers: npm:@nolyfill/es-iterator-helpers@^1.0.21 esbuild@<0.27.2: 0.27.2 + flatted@<=3.4.1: 3.4.2 glob@>=10.2.0 <10.5.0: 11.1.0 hasown: npm:@nolyfill/hasown@^1.0.44 is-arguments: npm:@nolyfill/is-arguments@^1.0.44 @@ -55,8 +614,8 @@ overrides: tar@<=7.5.10: 7.5.11 typed-array-buffer: npm:@nolyfill/typed-array-buffer@^1.0.44 undici@>=7.0.0 <7.24.0: 7.24.0 - vite: npm:@voidzero-dev/vite-plus-core@0.1.13 - vitest: npm:@voidzero-dev/vite-plus-test@0.1.13 + vite: npm:@voidzero-dev/vite-plus-core@0.1.14 + vitest: npm:@voidzero-dev/vite-plus-test@0.1.14 which-typed-array: npm:@nolyfill/which-typed-array@^1.0.44 yaml@>=2.0.0 <2.8.3: 2.8.3 yauzl@<3.2.1: 3.2.1 @@ -64,554 +623,612 @@ overrides: importers: .: + devDependencies: + taze: + specifier: 'catalog:' + version: 19.10.0 + + e2e: + devDependencies: + '@cucumber/cucumber': + specifier: 'catalog:' + version: 12.7.0 + '@playwright/test': + specifier: 'catalog:' + version: 1.58.2 + '@types/node': + specifier: 'catalog:' + version: 25.5.0 + tsx: + specifier: 'catalog:' + version: 4.21.0 + typescript: + specifier: 'catalog:' + version: 5.9.3 + vite-plus: + specifier: 'catalog:' + version: 0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.2)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) + + sdks/nodejs-client: + dependencies: + axios: + specifier: 'catalog:' + version: 1.14.0 + devDependencies: + '@eslint/js': + specifier: 'catalog:' + version: 10.0.1(eslint@10.1.0(jiti@2.6.1)) + '@types/node': + specifier: 'catalog:' + version: 25.5.0 + '@typescript-eslint/eslint-plugin': + specifier: 'catalog:' + version: 8.57.2(@typescript-eslint/parser@8.57.2(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3))(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': + specifier: 'catalog:' + version: 8.57.2(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3) + '@vitest/coverage-v8': + specifier: 'catalog:' + version: 4.1.2(@voidzero-dev/vite-plus-test@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.2)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)) + eslint: + specifier: 'catalog:' + version: 10.1.0(jiti@2.6.1) + tsup: + specifier: 'catalog:' + version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + typescript: + specifier: 'catalog:' + version: 5.9.3 + vitest: + specifier: npm:@voidzero-dev/vite-plus-test@0.1.14 + version: '@voidzero-dev/vite-plus-test@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.2)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)' + + web: dependencies: '@amplitude/analytics-browser': - specifier: 2.37.0 - version: 2.37.0 + specifier: 'catalog:' + version: 2.38.0 '@amplitude/plugin-session-replay-browser': - specifier: 1.27.1 - version: 1.27.1(@amplitude/rrweb@2.0.0-alpha.36)(rollup@4.59.0) + specifier: 'catalog:' + version: 1.27.5(@amplitude/rrweb@2.0.0-alpha.37)(rollup@4.59.0) '@base-ui/react': - specifier: 1.3.0 + specifier: 'catalog:' version: 1.3.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@emoji-mart/data': - specifier: 1.2.1 + specifier: 'catalog:' version: 1.2.1 '@floating-ui/react': - specifier: 0.27.19 + specifier: 'catalog:' version: 0.27.19(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@formatjs/intl-localematcher': - specifier: 0.8.2 + specifier: 'catalog:' version: 0.8.2 '@headlessui/react': - specifier: 2.2.9 + specifier: 'catalog:' version: 2.2.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@heroicons/react': - specifier: 2.2.0 + specifier: 'catalog:' version: 2.2.0(react@19.2.4) '@lexical/code': specifier: npm:lexical-code-no-prism@0.41.0 version: lexical-code-no-prism@0.41.0(@lexical/utils@0.42.0)(lexical@0.42.0) '@lexical/link': - specifier: 0.42.0 + specifier: 'catalog:' version: 0.42.0 '@lexical/list': - specifier: 0.42.0 + specifier: 'catalog:' version: 0.42.0 '@lexical/react': - specifier: 0.42.0 + specifier: 'catalog:' version: 0.42.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(yjs@13.6.30) '@lexical/selection': - specifier: 0.42.0 + specifier: 'catalog:' version: 0.42.0 '@lexical/text': - specifier: 0.42.0 + specifier: 'catalog:' version: 0.42.0 '@lexical/utils': - specifier: 0.42.0 + specifier: 'catalog:' version: 0.42.0 '@monaco-editor/react': - specifier: 4.7.0 + specifier: 'catalog:' version: 4.7.0(monaco-editor@0.55.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@orpc/client': - specifier: 1.13.9 - version: 1.13.9 + specifier: 'catalog:' + version: 1.13.13 '@orpc/contract': - specifier: 1.13.9 - version: 1.13.9 + specifier: 'catalog:' + version: 1.13.13 '@orpc/openapi-client': - specifier: 1.13.9 - version: 1.13.9 + specifier: 'catalog:' + version: 1.13.13 '@orpc/tanstack-query': - specifier: 1.13.9 - version: 1.13.9(@orpc/client@1.13.9)(@tanstack/query-core@5.95.0) + specifier: 'catalog:' + version: 1.13.13(@orpc/client@1.13.13)(@tanstack/query-core@5.95.2) '@remixicon/react': - specifier: 4.9.0 + specifier: 'catalog:' version: 4.9.0(react@19.2.4) '@sentry/react': - specifier: 10.45.0 - version: 10.45.0(react@19.2.4) + specifier: 'catalog:' + version: 10.46.0(react@19.2.4) '@streamdown/math': - specifier: 1.0.2 + specifier: 'catalog:' version: 1.0.2(react@19.2.4) '@svgdotjs/svg.js': - specifier: 3.2.5 + specifier: 'catalog:' version: 3.2.5 '@t3-oss/env-nextjs': - specifier: 0.13.11 - version: 0.13.11(typescript@5.9.3)(valibot@1.3.0(typescript@5.9.3))(zod@4.3.6) + specifier: 'catalog:' + version: 0.13.11(typescript@5.9.3)(valibot@1.3.1(typescript@5.9.3))(zod@4.3.6) '@tailwindcss/typography': - specifier: 0.5.19 + specifier: 'catalog:' version: 0.5.19(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.3)) '@tanstack/react-form': - specifier: 1.28.5 + specifier: 'catalog:' version: 1.28.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/react-query': - specifier: 5.95.0 - version: 5.95.0(react@19.2.4) + specifier: 'catalog:' + version: 5.95.2(react@19.2.4) abcjs: - specifier: 6.6.2 + specifier: 'catalog:' version: 6.6.2 ahooks: - specifier: 3.9.6 - version: 3.9.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: 'catalog:' + version: 3.9.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4) class-variance-authority: - specifier: 0.7.1 + specifier: 'catalog:' version: 0.7.1 clsx: - specifier: 2.1.1 + specifier: 'catalog:' version: 2.1.1 cmdk: - specifier: 1.1.1 + specifier: 'catalog:' version: 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) copy-to-clipboard: - specifier: 3.3.3 + specifier: 'catalog:' version: 3.3.3 cron-parser: - specifier: 5.5.0 + specifier: 'catalog:' version: 5.5.0 dayjs: - specifier: 1.11.20 + specifier: 'catalog:' version: 1.11.20 decimal.js: - specifier: 10.6.0 + specifier: 'catalog:' version: 10.6.0 dompurify: - specifier: 3.3.3 + specifier: 'catalog:' version: 3.3.3 echarts: - specifier: 6.0.0 + specifier: 'catalog:' version: 6.0.0 echarts-for-react: - specifier: 3.0.6 + specifier: 'catalog:' version: 3.0.6(echarts@6.0.0)(react@19.2.4) elkjs: - specifier: 0.11.1 + specifier: 'catalog:' version: 0.11.1 embla-carousel-autoplay: - specifier: 8.6.0 + specifier: 'catalog:' version: 8.6.0(embla-carousel@8.6.0) embla-carousel-react: - specifier: 8.6.0 + specifier: 'catalog:' version: 8.6.0(react@19.2.4) emoji-mart: - specifier: 5.6.0 + specifier: 'catalog:' version: 5.6.0 es-toolkit: - specifier: 1.45.1 + specifier: 'catalog:' version: 1.45.1 fast-deep-equal: - specifier: 3.1.3 + specifier: 'catalog:' version: 3.1.3 foxact: - specifier: 0.3.0 + specifier: 'catalog:' version: 0.3.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) html-entities: - specifier: 2.6.0 + specifier: 'catalog:' version: 2.6.0 html-to-image: - specifier: 1.11.13 + specifier: 'catalog:' version: 1.11.13 i18next: - specifier: 25.10.4 - version: 25.10.4(typescript@5.9.3) + specifier: 'catalog:' + version: 25.10.10(typescript@5.9.3) i18next-resources-to-backend: - specifier: 1.2.1 + specifier: 'catalog:' version: 1.2.1 immer: - specifier: 11.1.4 + specifier: 'catalog:' version: 11.1.4 jotai: - specifier: 2.18.1 - version: 2.18.1(@babel/core@7.29.0)(@babel/template@7.28.6)(@types/react@19.2.14)(react@19.2.4) + specifier: 'catalog:' + version: 2.19.0(@babel/core@7.29.0)(@babel/template@7.28.6)(@types/react@19.2.14)(react@19.2.4) js-audio-recorder: - specifier: 1.0.7 + specifier: 'catalog:' version: 1.0.7 js-cookie: - specifier: 3.0.5 + specifier: 'catalog:' version: 3.0.5 js-yaml: - specifier: 4.1.1 + specifier: 'catalog:' version: 4.1.1 jsonschema: - specifier: 1.5.0 + specifier: 'catalog:' version: 1.5.0 katex: - specifier: 0.16.40 - version: 0.16.40 + specifier: 'catalog:' + version: 0.16.44 ky: - specifier: 1.14.3 + specifier: 'catalog:' version: 1.14.3 lamejs: - specifier: 1.2.1 + specifier: 'catalog:' version: 1.2.1 lexical: - specifier: 0.42.0 + specifier: 'catalog:' version: 0.42.0 mermaid: - specifier: 11.13.0 + specifier: 'catalog:' version: 11.13.0 mime: - specifier: 4.1.0 + specifier: 'catalog:' version: 4.1.0 mitt: - specifier: 3.0.1 + specifier: 'catalog:' version: 3.0.1 negotiator: - specifier: 1.0.0 + specifier: 'catalog:' version: 1.0.0 next: - specifier: 16.2.1 - version: 16.2.1(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0) + specifier: 'catalog:' + version: 16.2.1(@babel/core@7.29.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0) next-themes: - specifier: 0.4.6 + specifier: 'catalog:' version: 0.4.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) nuqs: - specifier: 2.8.9 - version: 2.8.9(next@16.2.1(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0))(react@19.2.4) + specifier: 'catalog:' + version: 2.8.9(next@16.2.1(@babel/core@7.29.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0))(react@19.2.4) pinyin-pro: - specifier: 3.28.0 + specifier: 'catalog:' version: 3.28.0 qrcode.react: - specifier: 4.2.0 + specifier: 'catalog:' version: 4.2.0(react@19.2.4) qs: - specifier: 6.15.0 + specifier: 'catalog:' version: 6.15.0 react: - specifier: 19.2.4 + specifier: 'catalog:' version: 19.2.4 react-18-input-autosize: - specifier: 3.0.0 + specifier: 'catalog:' version: 3.0.0(react@19.2.4) react-dom: - specifier: 19.2.4 + specifier: 'catalog:' version: 19.2.4(react@19.2.4) react-easy-crop: - specifier: 5.5.6 - version: 5.5.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: 'catalog:' + version: 5.5.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react-hotkeys-hook: - specifier: 5.2.4 + specifier: 'catalog:' version: 5.2.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react-i18next: - specifier: 16.6.1 - version: 16.6.1(i18next@25.10.4(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + specifier: 'catalog:' + version: 16.6.6(i18next@25.10.10(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) react-multi-email: - specifier: 1.0.25 + specifier: 'catalog:' version: 1.0.25(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react-papaparse: - specifier: 4.4.0 + specifier: 'catalog:' version: 4.4.0 react-pdf-highlighter: - specifier: 8.0.0-rc.0 + specifier: 'catalog:' version: 8.0.0-rc.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react-sortablejs: - specifier: 6.1.4 + specifier: 'catalog:' version: 6.1.4(@types/sortablejs@1.15.9)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sortablejs@1.15.7) react-syntax-highlighter: - specifier: 15.6.6 + specifier: 'catalog:' version: 15.6.6(react@19.2.4) react-textarea-autosize: - specifier: 8.5.9 + specifier: 'catalog:' version: 8.5.9(@types/react@19.2.14)(react@19.2.4) react-window: - specifier: 1.8.11 + specifier: 'catalog:' version: 1.8.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4) reactflow: - specifier: 11.11.4 + specifier: 'catalog:' version: 11.11.4(@types/react@19.2.14)(immer@11.1.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) remark-breaks: - specifier: 4.0.0 + specifier: 'catalog:' version: 4.0.0 remark-directive: - specifier: 4.0.0 + specifier: 'catalog:' version: 4.0.0 scheduler: - specifier: 0.27.0 + specifier: 'catalog:' version: 0.27.0 sharp: - specifier: 0.34.5 + specifier: 'catalog:' version: 0.34.5 sortablejs: - specifier: 1.15.7 + specifier: 'catalog:' version: 1.15.7 std-semver: - specifier: 1.0.8 + specifier: 'catalog:' version: 1.0.8 streamdown: - specifier: 2.5.0 + specifier: 'catalog:' version: 2.5.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) string-ts: - specifier: 2.3.1 + specifier: 'catalog:' version: 2.3.1 tailwind-merge: - specifier: 2.6.1 + specifier: 'catalog:' version: 2.6.1 tldts: - specifier: 7.0.27 + specifier: 'catalog:' version: 7.0.27 unist-util-visit: - specifier: 5.1.0 + specifier: 'catalog:' version: 5.1.0 use-context-selector: - specifier: 2.0.0 + specifier: 'catalog:' version: 2.0.0(react@19.2.4)(scheduler@0.27.0) uuid: - specifier: 13.0.0 + specifier: 'catalog:' version: 13.0.0 zod: - specifier: 4.3.6 + specifier: 'catalog:' version: 4.3.6 zundo: - specifier: 2.3.0 + specifier: 'catalog:' version: 2.3.0(zustand@5.0.12(@types/react@19.2.14)(immer@11.1.4)(react@19.2.4)(use-sync-external-store@1.6.0(react@19.2.4))) zustand: - specifier: 5.0.12 + specifier: 'catalog:' version: 5.0.12(@types/react@19.2.14)(immer@11.1.4)(react@19.2.4)(use-sync-external-store@1.6.0(react@19.2.4)) devDependencies: '@antfu/eslint-config': - specifier: 7.7.3 - version: 7.7.3(@eslint-react/eslint-plugin@3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(@next/eslint-plugin-next@16.2.1)(@typescript-eslint/rule-tester@8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(@typescript-eslint/typescript-estree@8.57.1(typescript@5.9.3))(@typescript-eslint/utils@8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(@voidzero-dev/vite-plus-test@0.1.13(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(jsdom@29.0.1(canvas@3.2.2))(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(@vue/compiler-sfc@3.5.30)(eslint-plugin-react-hooks@7.0.1(eslint@10.1.0(jiti@1.21.7)))(eslint-plugin-react-refresh@0.5.2(eslint@10.1.0(jiti@1.21.7)))(eslint@10.1.0(jiti@1.21.7))(oxlint@1.56.0(oxlint-tsgolint@0.17.1))(typescript@5.9.3) + specifier: 'catalog:' + version: 7.7.3(@eslint-react/eslint-plugin@3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(@next/eslint-plugin-next@16.2.1)(@typescript-eslint/rule-tester@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(@typescript-eslint/typescript-estree@8.57.2(typescript@5.9.3))(@typescript-eslint/utils@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(@voidzero-dev/vite-plus-test@0.1.14(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(@vue/compiler-sfc@3.5.31)(eslint-plugin-react-hooks@7.0.1(eslint@10.1.0(jiti@1.21.7)))(eslint-plugin-react-refresh@0.5.2(eslint@10.1.0(jiti@1.21.7)))(eslint@10.1.0(jiti@1.21.7))(oxlint@1.57.0(oxlint-tsgolint@0.17.3))(typescript@5.9.3) '@chromatic-com/storybook': - specifier: 5.0.2 - version: 5.0.2(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + specifier: 'catalog:' + version: 5.1.1(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) '@egoist/tailwindcss-icons': - specifier: 1.9.2 + specifier: 'catalog:' version: 1.9.2(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.3)) '@eslint-react/eslint-plugin': - specifier: 3.0.0 + specifier: 'catalog:' version: 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) '@hono/node-server': - specifier: 1.19.11 - version: 1.19.11(hono@4.12.8) + specifier: 'catalog:' + version: 1.19.11(hono@4.12.9) '@iconify-json/heroicons': - specifier: 1.2.3 + specifier: 'catalog:' version: 1.2.3 '@iconify-json/ri': - specifier: 1.2.10 + specifier: 'catalog:' version: 1.2.10 '@mdx-js/loader': - specifier: 3.1.1 + specifier: 'catalog:' version: 3.1.1(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3)) '@mdx-js/react': - specifier: 3.1.1 + specifier: 'catalog:' version: 3.1.1(@types/react@19.2.14)(react@19.2.4) '@mdx-js/rollup': - specifier: 3.1.1 + specifier: 'catalog:' version: 3.1.1(rollup@4.59.0) '@next/eslint-plugin-next': - specifier: 16.2.1 + specifier: 'catalog:' version: 16.2.1 '@next/mdx': - specifier: 16.2.1 + specifier: 'catalog:' version: 16.2.1(@mdx-js/loader@3.1.1(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4)) '@rgrove/parse-xml': - specifier: 4.2.0 + specifier: 'catalog:' version: 4.2.0 '@storybook/addon-docs': - specifier: 10.3.1 - version: 10.3.1(@types/react@19.2.14)(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(rollup@4.59.0)(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3)) + specifier: 'catalog:' + version: 10.3.3(@types/react@19.2.14)(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(rollup@4.59.0)(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3)) '@storybook/addon-links': - specifier: 10.3.1 - version: 10.3.1(react@19.2.4)(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + specifier: 'catalog:' + version: 10.3.3(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) '@storybook/addon-onboarding': - specifier: 10.3.1 - version: 10.3.1(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + specifier: 'catalog:' + version: 10.3.3(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) '@storybook/addon-themes': - specifier: 10.3.1 - version: 10.3.1(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + specifier: 'catalog:' + version: 10.3.3(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) '@storybook/nextjs-vite': - specifier: 10.3.1 - version: 10.3.1(@babel/core@7.29.0)(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(next@16.2.1(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.59.0)(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3)) + specifier: 'catalog:' + version: 10.3.3(@babel/core@7.29.0)(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(next@16.2.1(@babel/core@7.29.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.59.0)(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3)) '@storybook/react': - specifier: 10.3.1 - version: 10.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) + specifier: 'catalog:' + version: 10.3.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) '@tanstack/eslint-plugin-query': - specifier: 5.95.0 - version: 5.95.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + specifier: 'catalog:' + version: 5.95.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) '@tanstack/react-devtools': - specifier: 0.10.0 + specifier: 'catalog:' version: 0.10.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.11) '@tanstack/react-form-devtools': - specifier: 0.2.19 + specifier: 'catalog:' version: 0.2.19(@types/react@19.2.14)(csstype@3.2.3)(react@19.2.4)(solid-js@1.9.11) '@tanstack/react-query-devtools': - specifier: 5.95.0 - version: 5.95.0(@tanstack/react-query@5.95.0(react@19.2.4))(react@19.2.4) + specifier: 'catalog:' + version: 5.95.2(@tanstack/react-query@5.95.2(react@19.2.4))(react@19.2.4) '@testing-library/dom': - specifier: 10.4.1 + specifier: 'catalog:' version: 10.4.1 '@testing-library/jest-dom': - specifier: 6.9.1 + specifier: 'catalog:' version: 6.9.1 '@testing-library/react': - specifier: 16.3.2 + specifier: 'catalog:' version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@testing-library/user-event': - specifier: 14.6.1 + specifier: 'catalog:' version: 14.6.1(@testing-library/dom@10.4.1) '@tsslint/cli': - specifier: 3.0.2 + specifier: 'catalog:' version: 3.0.2(@tsslint/compat-eslint@3.0.2(jiti@1.21.7)(typescript@5.9.3))(typescript@5.9.3) '@tsslint/compat-eslint': - specifier: 3.0.2 + specifier: 'catalog:' version: 3.0.2(jiti@1.21.7)(typescript@5.9.3) '@tsslint/config': - specifier: 3.0.2 + specifier: 'catalog:' version: 3.0.2(@tsslint/compat-eslint@3.0.2(jiti@1.21.7)(typescript@5.9.3))(typescript@5.9.3) '@types/js-cookie': - specifier: 3.0.6 + specifier: 'catalog:' version: 3.0.6 '@types/js-yaml': - specifier: 4.0.9 + specifier: 'catalog:' version: 4.0.9 '@types/negotiator': - specifier: 0.6.4 + specifier: 'catalog:' version: 0.6.4 '@types/node': - specifier: 25.5.0 + specifier: 'catalog:' version: 25.5.0 '@types/postcss-js': - specifier: 4.1.0 + specifier: 'catalog:' version: 4.1.0 '@types/qs': - specifier: 6.15.0 + specifier: 'catalog:' version: 6.15.0 '@types/react': - specifier: 19.2.14 + specifier: 'catalog:' version: 19.2.14 '@types/react-dom': - specifier: 19.2.3 + specifier: 'catalog:' version: 19.2.3(@types/react@19.2.14) '@types/react-syntax-highlighter': - specifier: 15.5.13 + specifier: 'catalog:' version: 15.5.13 '@types/react-window': - specifier: 1.8.8 + specifier: 'catalog:' version: 1.8.8 '@types/sortablejs': - specifier: 1.15.9 + specifier: 'catalog:' version: 1.15.9 '@typescript-eslint/parser': - specifier: 8.57.1 - version: 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + specifier: 'catalog:' + version: 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) '@typescript/native-preview': - specifier: 7.0.0-dev.20260322.1 - version: 7.0.0-dev.20260322.1 + specifier: 'catalog:' + version: 7.0.0-dev.20260329.1 '@vitejs/plugin-react': - specifier: 6.0.1 - version: 6.0.1(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)) + specifier: 'catalog:' + version: 6.0.1(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)) '@vitejs/plugin-rsc': - specifier: 0.5.21 - version: 0.5.21(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(react-dom@19.2.4(react@19.2.4))(react-server-dom-webpack@19.2.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3)))(react@19.2.4) + specifier: 'catalog:' + version: 0.5.21(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(react-dom@19.2.4(react@19.2.4))(react-server-dom-webpack@19.2.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3)))(react@19.2.4) '@vitest/coverage-v8': - specifier: 4.1.0 - version: 4.1.0(@voidzero-dev/vite-plus-test@0.1.13(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(jsdom@29.0.1(canvas@3.2.2))(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)) + specifier: 'catalog:' + version: 4.1.2(@voidzero-dev/vite-plus-test@0.1.14(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)) agentation: - specifier: 2.3.3 - version: 2.3.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: 'catalog:' + version: 3.0.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) autoprefixer: - specifier: 10.4.27 + specifier: 'catalog:' version: 10.4.27(postcss@8.5.8) code-inspector-plugin: - specifier: 1.4.5 + specifier: 'catalog:' version: 1.4.5 eslint: - specifier: 10.1.0 + specifier: 'catalog:' version: 10.1.0(jiti@1.21.7) eslint-markdown: - specifier: 0.6.0 + specifier: 'catalog:' version: 0.6.0(eslint@10.1.0(jiti@1.21.7)) eslint-plugin-better-tailwindcss: - specifier: 4.3.2 - version: 4.3.2(eslint@10.1.0(jiti@1.21.7))(oxlint@1.56.0(oxlint-tsgolint@0.17.1))(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.3))(typescript@5.9.3) + specifier: 'catalog:' + version: 4.3.2(eslint@10.1.0(jiti@1.21.7))(oxlint@1.57.0(oxlint-tsgolint@0.17.3))(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.3))(typescript@5.9.3) eslint-plugin-hyoban: - specifier: 0.14.1 + specifier: 'catalog:' version: 0.14.1(eslint@10.1.0(jiti@1.21.7)) eslint-plugin-markdown-preferences: - specifier: 0.40.3 + specifier: 'catalog:' version: 0.40.3(@eslint/markdown@7.5.1)(eslint@10.1.0(jiti@1.21.7)) eslint-plugin-no-barrel-files: - specifier: 1.2.2 + specifier: 'catalog:' version: 1.2.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) eslint-plugin-react-hooks: - specifier: 7.0.1 + specifier: 'catalog:' version: 7.0.1(eslint@10.1.0(jiti@1.21.7)) eslint-plugin-react-refresh: - specifier: 0.5.2 + specifier: 'catalog:' version: 0.5.2(eslint@10.1.0(jiti@1.21.7)) eslint-plugin-sonarjs: - specifier: 4.0.2 + specifier: 'catalog:' version: 4.0.2(eslint@10.1.0(jiti@1.21.7)) eslint-plugin-storybook: - specifier: 10.3.1 - version: 10.3.1(eslint@10.1.0(jiti@1.21.7))(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) + specifier: 'catalog:' + version: 10.3.3(eslint@10.1.0(jiti@1.21.7))(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) happy-dom: - specifier: 20.8.9 + specifier: 'catalog:' version: 20.8.9 hono: - specifier: 4.12.8 - version: 4.12.8 + specifier: 'catalog:' + version: 4.12.9 husky: - specifier: 9.1.7 + specifier: 'catalog:' version: 9.1.7 iconify-import-svg: - specifier: 0.1.2 + specifier: 'catalog:' version: 0.1.2 knip: - specifier: 6.0.2 - version: 6.0.2 + specifier: 'catalog:' + version: 6.1.0(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1) lint-staged: - specifier: 16.4.0 + specifier: 'catalog:' version: 16.4.0 postcss: - specifier: 8.5.8 + specifier: 'catalog:' version: 8.5.8 postcss-js: - specifier: 5.1.0 + specifier: 'catalog:' version: 5.1.0(postcss@8.5.8) react-server-dom-webpack: - specifier: 19.2.4 + specifier: 'catalog:' version: 19.2.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3)) sass: - specifier: 1.98.0 + specifier: 'catalog:' version: 1.98.0 storybook: - specifier: 10.3.1 - version: 10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: 'catalog:' + version: 10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) tailwindcss: - specifier: 3.4.19 + specifier: 'catalog:' version: 3.4.19(tsx@4.21.0)(yaml@2.8.3) - taze: - specifier: 19.10.0 - version: 19.10.0 tsx: - specifier: 4.21.0 + specifier: 'catalog:' version: 4.21.0 typescript: - specifier: 5.9.3 + specifier: 'catalog:' version: 5.9.3 uglify-js: - specifier: 3.19.3 + specifier: 'catalog:' version: 3.19.3 vinext: - specifier: https://pkg.pr.new/vinext@b6a2cac - version: https://pkg.pr.new/vinext@b6a2cac(33c71b051bfc49f90bf5d8b6a8976975) + specifier: 'catalog:' + version: 0.0.38(f5786d681f520e26604259e094ebaa46) vite: - specifier: npm:@voidzero-dev/vite-plus-core@0.1.13 - version: '@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' + specifier: npm:@voidzero-dev/vite-plus-core@0.1.14 + version: '@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' vite-plugin-inspect: - specifier: 11.3.3 - version: 11.3.3(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)) + specifier: 'catalog:' + version: 12.0.0-beta.1(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(typescript@5.9.3)(ws@8.20.0) vite-plus: - specifier: 0.1.13 - version: 0.1.13(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(jsdom@29.0.1(canvas@3.2.2))(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + specifier: 'catalog:' + version: 0.1.14(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) vitest: - specifier: npm:@voidzero-dev/vite-plus-test@0.1.13 - version: '@voidzero-dev/vite-plus-test@0.1.13(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(jsdom@29.0.1(canvas@3.2.2))(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' + specifier: npm:@voidzero-dev/vite-plus-test@0.1.14 + version: '@voidzero-dev/vite-plus-test@0.1.14(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' vitest-canvas-mock: - specifier: 1.1.3 - version: 1.1.3(@voidzero-dev/vite-plus-test@0.1.13(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(jsdom@29.0.1(canvas@3.2.2))(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)) + specifier: 'catalog:' + version: 1.1.4(@voidzero-dev/vite-plus-test@0.1.14(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)) packages: @@ -622,17 +1239,17 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} - '@amplitude/analytics-browser@2.37.0': - resolution: {integrity: sha512-/BWDneHRfq6+9bcPQC09Ep79SEj7aRJLZ1jJrPHtxA9KZJUz2au2COlJc1ReCaNzCcrA1xXv/MQ0Fv7TwoBglg==} + '@amplitude/analytics-browser@2.38.0': + resolution: {integrity: sha512-MhqyEkr1gGAR4s4GSSflDhFVheIx9Nv3FfElQu9NlNrXB2Hh3BEOyVgdK7hgfi6NJwFyfw30+t5lym+njtA8hA==} - '@amplitude/analytics-client-common@2.4.39': - resolution: {integrity: sha512-DFzi2/D2eu7EBCyslk86lToQa+qo1AmKgvZQVDDqkLG37/meTRcBAZiL0FAdTX21AYwpC/Ym4FWowD04foiBIQ==} + '@amplitude/analytics-client-common@2.4.41': + resolution: {integrity: sha512-+GbvtvhsUROotPBwfAxbrqovKePhC0oQKXtxjbeNQleOHjBjsAs5jEOCHpJenCKtaRpucg/FuK3NVOS09MfW7Q==} '@amplitude/analytics-connector@1.6.4': resolution: {integrity: sha512-SpIv0IQMNIq6SH3UqFGiaZyGSc7PBZwRdq7lvP0pBxW8i4Ny+8zwI0pV+VMfMHQwWY3wdIbWw5WQphNjpdq1/Q==} - '@amplitude/analytics-core@2.43.0': - resolution: {integrity: sha512-rcDqi4cmI9Ro7hN5wjAuTm92IdN2i0lhIDAj+JOd9BP3SRMrhhiw2lzcScj3owig8CiV9X7EHPTuZe6XCTfIgQ==} + '@amplitude/analytics-core@2.44.0': + resolution: {integrity: sha512-z9QuTxLqEQ8KIeAT6Vmy6K48rP9TUmjnb4GwUMYoV/fxu3B9ClTaN18zqXQMmDw9HwUiIreHiVbwTb7OQRN5aA==} '@amplitude/analytics-types@2.11.1': resolution: {integrity: sha512-wFEgb0t99ly2uJKm5oZ28Lti0Kh5RecR5XBkwfUpDzn84IoCIZ8GJTsMw/nThu8FZFc7xFDA4UAt76zhZKrs9A==} @@ -640,29 +1257,29 @@ packages: '@amplitude/experiment-core@0.7.2': resolution: {integrity: sha512-Wc2NWvgQ+bLJLeF0A9wBSPIaw0XuqqgkPKsoNFQrmS7r5Djd56um75In05tqmVntPJZRvGKU46pAp8o5tdf4mA==} - '@amplitude/plugin-autocapture-browser@1.24.1': - resolution: {integrity: sha512-cvjOFew2MFNBDTbk3+H7WNi3D0Jdp476m6faCaVhY99M5zqRCHDMRS7dC4HczvL9zYXlAcW9jAWucwES2m3TiQ==} + '@amplitude/plugin-autocapture-browser@1.25.0': + resolution: {integrity: sha512-YuWsz8XmJuKu3NlMxkvlhLey/5tGCeOwwfsROHficR0yDWO9gNG0WtHl7A0Pw1PUc9iaXjqfG2AjYumAtiq16Q==} - '@amplitude/plugin-custom-enrichment-browser@0.1.0': - resolution: {integrity: sha512-y3VmqZvCP1Z3jNgo/mtKVHON9L0P2SyqkMmUsbbFuLu1+TKIkicotnVq/lzlLU1TrW68mkInOM+We8JngasZBA==} + '@amplitude/plugin-custom-enrichment-browser@0.1.2': + resolution: {integrity: sha512-ZX9BKqs1E1OI7l7QCGu9JnB/1kqLN+zqIePgM2tuEhZNFQJaw4NhAMUaMRqvNnaCkHlmpVRISzSj/4D3tWMRtA==} - '@amplitude/plugin-network-capture-browser@1.9.9': - resolution: {integrity: sha512-SJIOQN04Mk9vCsnVd9QRcIvkMV7XSGZIKfbaKNQY5O3ueV33Kc8opm7YjPg2sWcxdzTcJijbCkOI0wCwOaRolg==} + '@amplitude/plugin-network-capture-browser@1.9.11': + resolution: {integrity: sha512-49o3zYnKUmRdrxgAEcr1iHnXR1um40e1icO0hzugSq04k19hs27zcl3zpEk9geO+nNKwO744ryE1q93gqVbHrQ==} - '@amplitude/plugin-page-url-enrichment-browser@0.7.0': - resolution: {integrity: sha512-MkM7TDq24k7ilUDNZISqjDSkVfmDJxWcnUagwYEXjLILhno5hGm7wdgFvVXXzKlZQHEogBxkbnq7wZXS9/YsMw==} + '@amplitude/plugin-page-url-enrichment-browser@0.7.3': + resolution: {integrity: sha512-3UZq/zKg4lcsRgziWAPSEeaUsNsbyjjxmsAE9kSDi/hIj5RaWnwWhY6TGhv45UAReugTA4vVZyFRg9btf3c/Fg==} - '@amplitude/plugin-page-view-tracking-browser@2.9.1': - resolution: {integrity: sha512-jkxz2lkJDAfsjj7mpbPUZx9N3qJssC3uYyv8Nk73z+p+v0wjBikWdOoKuNQkcuP09701zRdXp9ziU8+qwkGusw==} + '@amplitude/plugin-page-view-tracking-browser@2.9.4': + resolution: {integrity: sha512-J16zmEadnzNpkHSmzpTiQN2q9pGJ/4SkHONA9O8KxUsMU/MYTDgof3rAYY/w5B5rmvdxfMRCjqWtvnkizzgZ6w==} - '@amplitude/plugin-session-replay-browser@1.27.1': - resolution: {integrity: sha512-IEkAU7O3LbL23piMD7Lu0ej9wT/LQdQsyY1okTW5y2Nov8ZCmqLhZPLk6s9vKCUxGukDi7IL6gqXpURTLYj5rQ==} + '@amplitude/plugin-session-replay-browser@1.27.5': + resolution: {integrity: sha512-tf0Ty1nNF8OJ5QQ5scEqdGfzdgIaqkRf2MSzQfHbGcTIoYuVmAKuCgn3yMLk62MKnwgG3IsTIugMdRRv7l85PA==} - '@amplitude/plugin-web-vitals-browser@1.1.24': - resolution: {integrity: sha512-7AaytUK78RKdyDsblYJCKYan1lQi3Qzsp1WHItHJ+RSXPccmi4mCcvNtx0e8T9LmNJlUnsmYeEGR/6FaWvyvFg==} + '@amplitude/plugin-web-vitals-browser@1.1.26': + resolution: {integrity: sha512-wiD4vy+f2fepr+8Lnn26TYYjDEnWsmlGhJog99x+xfbZ/D+stGdaCIOz5AOjU1TpTRvxvamEu2XuOh+8EZOCSA==} - '@amplitude/rrdom@2.0.0-alpha.36': - resolution: {integrity: sha512-8jNhYEzjp6aaZON7qY/IpZIVbl8SUojb8kxD58StknlvnjKeGV7nHheXbkIz+T1LSVbWsdh+noIWuqhyFWzvgg==} + '@amplitude/rrdom@2.0.0-alpha.37': + resolution: {integrity: sha512-u4dSnBtlbJ8oU5P/Ywl2RLqvjqWbkl4ScMUbvQA7in4pWcx+0NRN+VVjLZXQcd8Fn7E/rcxjeUh7e7HfwvdasQ==} '@amplitude/rrweb-packer@2.0.0-alpha.36': resolution: {integrity: sha512-kqKg6OGoxHZvG4jwyO4kIjLdf8MkL6JcY5iLB09PQNP7O36ysnrH+ecJfa4V1Rld99kX25Pefkw4bzKmmFAqcg==} @@ -675,20 +1292,26 @@ packages: '@amplitude/rrweb-record@2.0.0-alpha.36': resolution: {integrity: sha512-zSHvmG5NUG4jNgWNVM7Oj3+rJPagv+TiHlnSiJ1X0WWLIg1GbUnOoTqpincZS5QupqTxQchNQaUg9MNu0MM3sQ==} - '@amplitude/rrweb-snapshot@2.0.0-alpha.36': - resolution: {integrity: sha512-vUvTXkNcu+cN736tykQDUVWERetFz1hyzgS0Yib5qSeWJwbse/4BaiWaZ7c5WevbbtcjLbDJqYKySJM92H5SxQ==} + '@amplitude/rrweb-snapshot@2.0.0-alpha.37': + resolution: {integrity: sha512-OPW2r8ESAguq+1R+z+WxGyzZzkMtojZ49Lpp6NrataNFyjdKaNXehDuLoNlEQkkUZGyDBiA7RSYvUw+JPSmmSQ==} '@amplitude/rrweb-types@2.0.0-alpha.36': resolution: {integrity: sha512-Bd2r3Bs0XIJt5fgPRWVl8bhvA9FCjJn8vQlDTO8ffPxilGPIzUXLQ06+xoLYkK9v+PDKJnCapOTL4A2LilDmgA==} + '@amplitude/rrweb-types@2.0.0-alpha.37': + resolution: {integrity: sha512-LW9wQ85umaAW/qlemTrUC408WVoBx99hvFCjsNRnxAyUmRemWyYY7+o8xPyeUexoWGqizPMkkNnPEO8t1NFjtw==} + '@amplitude/rrweb-utils@2.0.0-alpha.36': resolution: {integrity: sha512-w5RGROLU1Kyrq9j+trxcvvfkTp05MEKJ70Ig+YvHyZsE0nElh1PCF8PHAjV0/kji68+KqB03c0hoyaV99CDaDw==} - '@amplitude/rrweb@2.0.0-alpha.36': - resolution: {integrity: sha512-8vhPOk4fvszfxYZTk37EObW3n7uwEgO//funRSMt/QiBWtgQ8jhpFV9FcOAYdgde0Yw1uIM8oUbWZfy/XrexNw==} + '@amplitude/rrweb-utils@2.0.0-alpha.37': + resolution: {integrity: sha512-40YvPj24ietFQ3BTLfvFRPriRqdNOp3DzGiPU+WDOZkI3KjInQrEsibaqNBSXzJ+kMWrm8/eEwcQ0FkLk7Achw==} - '@amplitude/session-replay-browser@1.34.1': - resolution: {integrity: sha512-oQ9Pi/vcEhcRxmMIDMOZopt9vSaGYB4X64kp8idKut2Or8/DBhdztSjujwvkYvU48jNfqmT7oxIY5sCLYdiM6w==} + '@amplitude/rrweb@2.0.0-alpha.37': + resolution: {integrity: sha512-jJkSpPYiVgOZB422pb2jOJJn3pvb5E5f9vKK8CEmUlk2mVAl6kPQzW98mb05M65OJFj5nn9tSe9h5r5+Cl93ag==} + + '@amplitude/session-replay-browser@1.35.0': + resolution: {integrity: sha512-aGqu807oC8UIMmP+g1jBYsgN+/VeR/ThtK6fpxuZCugEogx7EZ9sXDEeudUmyvkQQfWmD+nLmrhYPX8FpROT5w==} '@amplitude/targeting@0.2.0': resolution: {integrity: sha512-/50ywTrC4hfcfJVBbh5DFbqMPPfaIOivZeb5Gb+OGM03QrA+lsUqdvtnKLNuWtceD4H6QQ2KFzPJ5aAJLyzVDA==} @@ -768,17 +1391,6 @@ packages: '@antfu/utils@8.1.1': resolution: {integrity: sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ==} - '@asamuzakjp/css-color@5.1.1': - resolution: {integrity: sha512-iGWN8E45Ws0XWx3D44Q1t6vX2LqhCKcwfmwBYCDsFrYFS6m4q/Ks61L2veETaLv+ckDC6+dTETJoaAAb7VjLiw==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - - '@asamuzakjp/dom-selector@7.0.4': - resolution: {integrity: sha512-jXR6x4AcT3eIrS2fSNAwJpwirOkGcd+E7F7CP3zjdTqz9B/2huHOL8YJZBgekKwLML+u7qB/6P1LXQuMScsx0w==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - - '@asamuzakjp/nwsapi@2.3.9': - resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} - '@babel/code-frame@7.29.0': resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} @@ -878,10 +1490,6 @@ packages: '@braintree/sanitize-url@7.1.2': resolution: {integrity: sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==} - '@bramus/specificity@2.4.2': - resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} - hasBin: true - '@chevrotain/cst-dts-gen@11.1.2': resolution: {integrity: sha512-XTsjvDVB5nDZBQB8o0o/0ozNelQtn2KrUVteIHSlPd2VAV2utEb6JzyCJaJ8tGxACR4RiBNWy5uYUHX2eji88Q==} @@ -897,8 +1505,8 @@ packages: '@chevrotain/utils@11.1.2': resolution: {integrity: sha512-4mudFAQ6H+MqBTfqLmU7G1ZwRzCLfJEooL/fsF6rCX5eePMbGhoy5n4g+G4vlh2muDcsCTJtL+uKbOzWxs5LHA==} - '@chromatic-com/storybook@5.0.2': - resolution: {integrity: sha512-uLd5gyvcz8q83GI0rYWjml45ryO3ZJwZLretLEZvWFJ3UlFk5C5Km9cwRcKZgZp0F3zYwbb8nEe6PJdgA1eKxg==} + '@chromatic-com/storybook@5.1.1': + resolution: {integrity: sha512-BPoAXHM71XgeCK2u0jKr9i8apeQMm/Z9IWGyndA2FMijfQG9m8ox45DdWh/pxFkK5ClhGgirv5QwMhFIeHmThg==} engines: {node: '>=20.0.0', yarn: '>=1.22.18'} peerDependencies: storybook: ^0.0.0-0 || ^10.1.0 || ^10.1.0-0 || ^10.2.0-0 || ^10.3.0-0 || ^10.4.0-0 @@ -933,41 +1541,67 @@ packages: '@code-inspector/webpack@1.4.5': resolution: {integrity: sha512-lwUv+X1FNSUWz+FKcUsE2dT2pg6VFRRXKt16hg/m+Lwtdet2adfi6BFLZmNz3OPIEGbRB5Kjx6bfaghZhbDCCg==} - '@csstools/color-helpers@6.0.2': - resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==} - engines: {node: '>=20.19.0'} + '@colors/colors@1.5.0': + resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} + engines: {node: '>=0.1.90'} - '@csstools/css-calc@3.1.1': - resolution: {integrity: sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==} - engines: {node: '>=20.19.0'} + '@cucumber/ci-environment@13.0.0': + resolution: {integrity: sha512-cs+3NzfNkGbcmHPddjEv4TKFiBpZRQ6WJEEufB9mw+ExS22V/4R/zpDSEG+fsJ/iSNCd6A2sATdY8PFOyY3YnA==} + + '@cucumber/cucumber-expressions@19.0.0': + resolution: {integrity: sha512-4FKoOQh2Uf6F6/Ln+1OxuK8LkTg6PyAqekhf2Ix8zqV2M54sH+m7XNJNLhOFOAW/t9nxzRbw2CcvXbCLjcvHZg==} + + '@cucumber/cucumber@12.7.0': + resolution: {integrity: sha512-7A/9CJpJDxv1SQ7hAZU0zPn2yRxx6XMR+LO4T94Enm3cYNWsEEj+RGX38NLX4INT+H6w5raX3Csb/qs4vUBsOA==} + engines: {node: 20 || 22 || >=24} + hasBin: true + + '@cucumber/gherkin-streams@6.0.0': + resolution: {integrity: sha512-HLSHMmdDH0vCr7vsVEURcDA4WwnRLdjkhqr6a4HQ3i4RFK1wiDGPjBGVdGJLyuXuRdJpJbFc6QxHvT8pU4t6jw==} + hasBin: true peerDependencies: - '@csstools/css-parser-algorithms': ^4.0.0 - '@csstools/css-tokenizer': ^4.0.0 + '@cucumber/gherkin': '>=22.0.0' + '@cucumber/message-streams': '>=4.0.0' + '@cucumber/messages': '>=17.1.1' - '@csstools/css-color-parser@4.0.2': - resolution: {integrity: sha512-0GEfbBLmTFf0dJlpsNU7zwxRIH0/BGEMuXLTCvFYxuL1tNhqzTbtnFICyJLTNK4a+RechKP75e7w42ClXSnJQw==} - engines: {node: '>=20.19.0'} + '@cucumber/gherkin-utils@11.0.0': + resolution: {integrity: sha512-LJ+s4+TepHTgdKWDR4zbPyT7rQjmYIcukTwNbwNwgqr6i8Gjcmzf6NmtbYDA19m1ZFg6kWbFsmHnj37ZuX+kZA==} + hasBin: true + + '@cucumber/gherkin@38.0.0': + resolution: {integrity: sha512-duEXK+KDfQUzu3vsSzXjkxQ2tirF5PRsc1Xrts6THKHJO6mjw4RjM8RV+vliuDasmhhrmdLcOcM7d9nurNTJKw==} + + '@cucumber/html-formatter@23.0.0': + resolution: {integrity: sha512-WwcRzdM8Ixy4e53j+Frm3fKM5rNuIyWUfy4HajEN+Xk/YcjA6yW0ACGTFDReB++VDZz/iUtwYdTlPRY36NbqJg==} peerDependencies: - '@csstools/css-parser-algorithms': ^4.0.0 - '@csstools/css-tokenizer': ^4.0.0 + '@cucumber/messages': '>=18' - '@csstools/css-parser-algorithms@4.0.0': - resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==} - engines: {node: '>=20.19.0'} + '@cucumber/junit-xml-formatter@0.9.0': + resolution: {integrity: sha512-WF+A7pBaXpKMD1i7K59Nk5519zj4extxY4+4nSgv5XLsGXHDf1gJnb84BkLUzevNtp2o2QzMG0vWLwSm8V5blw==} peerDependencies: - '@csstools/css-tokenizer': ^4.0.0 + '@cucumber/messages': '*' - '@csstools/css-syntax-patches-for-csstree@1.1.2': - resolution: {integrity: sha512-5GkLzz4prTIpoyeUiIu3iV6CSG3Plo7xRVOFPKI7FVEJ3mZ0A8SwK0XU3Gl7xAkiQ+mDyam+NNp875/C5y+jSA==} + '@cucumber/message-streams@4.0.1': + resolution: {integrity: sha512-Kxap9uP5jD8tHUZVjTWgzxemi/0uOsbGjd4LBOSxcJoOCRbESFwemUzilJuzNTB8pcTQUh8D5oudUyxfkJOKmA==} peerDependencies: - css-tree: ^3.2.1 - peerDependenciesMeta: - css-tree: - optional: true + '@cucumber/messages': '>=17.1.1' - '@csstools/css-tokenizer@4.0.0': - resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} - engines: {node: '>=20.19.0'} + '@cucumber/messages@32.0.1': + resolution: {integrity: sha512-1OSoW+GQvFUNAl6tdP2CTBexTXMNJF0094goVUcvugtQeXtJ0K8sCP0xbq7GGoiezs/eJAAOD03+zAPT64orHQ==} + + '@cucumber/pretty-formatter@1.0.1': + resolution: {integrity: sha512-A1lU4VVP0aUWdOTmpdzvXOyEYuPtBDI0xYwYJnmoMDplzxMdhcHk86lyyvYDoMoPzzq6OkOE3isuosvUU4X7IQ==} + peerDependencies: + '@cucumber/cucumber': '>=7.0.0' + '@cucumber/messages': '*' + + '@cucumber/query@14.7.0': + resolution: {integrity: sha512-fiqZ4gMEgYjmbuWproF/YeCdD5y+gD2BqgBIGbpihOsx6UlNsyzoDSfO+Tny0q65DxfK+pHo2UkPyEl7dO7wmQ==} + peerDependencies: + '@cucumber/messages': '*' + + '@cucumber/tag-expressions@9.1.0': + resolution: {integrity: sha512-bvHjcRFZ+J1TqIa9eFNO1wGHqwx4V9ZKV3hYgkuK/VahHx73uiP4rKV3JVrvWSMrwrFvJG6C8aEwnCWSvbyFdQ==} '@e18e/eslint-plugin@0.2.0': resolution: {integrity: sha512-mXgODVwhuDjTJ+UT+XSvmMmCidtGKfrV5nMIv1UtpWex2pYLsIM3RSpT8HWIMAebS9qANbXPKlSX4BE7ZvuCgA==} @@ -985,11 +1619,11 @@ packages: peerDependencies: tailwindcss: '*' - '@emnapi/core@1.9.0': - resolution: {integrity: sha512-0DQ98G9ZQZOxfUcQn1waV2yS8aWdZ6kJMbYCJB3oUBecjWYO1fqJ+a1DRfPF3O5JEkwqwP1A9QEN/9mYm2Yd0w==} + '@emnapi/core@1.9.1': + resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==} - '@emnapi/runtime@1.9.0': - resolution: {integrity: sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw==} + '@emnapi/runtime@1.9.1': + resolution: {integrity: sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==} '@emnapi/wasi-threads@1.2.0': resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} @@ -1261,6 +1895,15 @@ packages: resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/js@10.0.1': + resolution: {integrity: sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + peerDependencies: + eslint: ^10.0.0 + peerDependenciesMeta: + eslint: + optional: true + '@eslint/js@9.27.0': resolution: {integrity: sha512-G5JD9Tu5HJEu4z2Uo4aHY2sLV64B7CDMXxFzqzjl3NKd6RVzSXNoE80jk7Y0lJkTTkjiIhBAqmlYwjuBY3tvpA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1289,15 +1932,6 @@ packages: resolution: {integrity: sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@exodus/bytes@1.15.0': - resolution: {integrity: sha512-UY0nlA+feH81UGSHv92sLEPLCeZFjXOuHhrIo0HQydScuQc8s0A7kL/UdgwgDq8g8ilksmuoF35YVTNphV2aBQ==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - peerDependencies: - '@noble/hashes': ^1.8.0 || ^2.0.0 - peerDependenciesMeta: - '@noble/hashes': - optional: true - '@floating-ui/core@1.7.5': resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} @@ -1680,8 +2314,11 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@napi-rs/wasm-runtime@1.1.1': - resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} + '@napi-rs/wasm-runtime@1.1.2': + resolution: {integrity: sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 '@neoconfetti/react@1.0.0': resolution: {integrity: sha512-klcSooChXXOzIm+SE5IISIAn3bYzYfPjbX7D7HoqZL84oAfgREeSg5vSIaSFH+DaGzzvImTyWe1OyrJ67vik4A==} @@ -1770,6 +2407,10 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@nolyfill/hasown@1.0.44': + resolution: {integrity: sha512-GA/21lkTr2PAQuT6jGnhLuBD5IFd/AEhBXJ/tf33+/bVxPxg+5ejKx9jGQGnyV/P0eSmdup5E+s8b2HL6lOrwQ==} + engines: {node: '>=12.4.0'} + '@nolyfill/is-core-module@1.0.39': resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} engines: {node: '>=12.4.0'} @@ -1782,175 +2423,178 @@ packages: resolution: {integrity: sha512-y3SvzjuY1ygnzWA4Krwx/WaJAsTMP11DN+e21A8Fa8PW1oDtVB5NSRW7LWurAiS2oKRkuCgcjTYMkBuBkcPCRg==} engines: {node: '>=12.4.0'} - '@orpc/client@1.13.9': - resolution: {integrity: sha512-RmD2HDgmGgF6zgHHdybE4zH6QJoHjC+/C3n56yLf+fmWbiZtwnOUETgGCroY6S8aK2fpy6hJ3wZaJUjfWVuGHg==} + '@orpc/client@1.13.13': + resolution: {integrity: sha512-jagx/Sa+9K4HEC5lBrUlMSrmR/06hvZctWh93/sKZc8GBk4zM0+71oT1kXQVw1oRYFV2XAq3xy3m6NdM6gfKYA==} - '@orpc/contract@1.13.9': - resolution: {integrity: sha512-0zxMyF82pxE8DwHzarCsCtOHQK96PE23qubMMBkxkP0XTtLJ7f8aYhrG8F16pNApypmTHiRlQlqNX8VXNViMqQ==} + '@orpc/contract@1.13.13': + resolution: {integrity: sha512-md6iyrYkePBSJNs1VnVEEnAUORMDPHIf3JGRSHxyssIcNakev/iOjP0HvpH0Sx0MlTBhihAJo6uFL8Vpth58Nw==} - '@orpc/openapi-client@1.13.9': - resolution: {integrity: sha512-zvNrc7wgF/INKeewH2ih48U/q9tG7rLZCnmMrb5/1jdZgYYOBAEuILlDAejeQwGdRce6W18GTBjLKIEdP3WwqA==} + '@orpc/openapi-client@1.13.13': + resolution: {integrity: sha512-k8od+bD7MqysKPPybAkxgfaNIaNseFPXtbidWkZAdCZ5w34SnDc7QPZJ0PQbyt9n9B+jOXSADNwQSTWSuGpjyA==} - '@orpc/shared@1.13.9': - resolution: {integrity: sha512-gpMY2e9jDsSyikh4DjBCO2Cs0wGj2I6xo2juIcmogYK5ecsTGO/U5huIftQn+2NUMk1cItwmykJBwc4pqHWVHw==} + '@orpc/shared@1.13.13': + resolution: {integrity: sha512-kNpYOBjHvmgKHla6munWOaEeA0utEfAvoiZpXjiRjjt1RxTibdwQvVHgxRIBNMXfQsb+ON3Q/wDkoaUhvvSnIw==} peerDependencies: '@opentelemetry/api': '>=1.9.0' peerDependenciesMeta: '@opentelemetry/api': optional: true - '@orpc/standard-server-fetch@1.13.9': - resolution: {integrity: sha512-/dJmHO+EVONyvmX3CFZkRjlRHeBfq0+6nnpFIVueGo4fNUbtQc+qurKEtpQqPxL/b7GSehskNH21XKLE0IE0gQ==} + '@orpc/standard-server-fetch@1.13.13': + resolution: {integrity: sha512-Lffy26+WtCQkwOUacsrdyeJF1GNzrhm75O3LXKVFXqmSdyVVdyI6zuqLn/YKGODU2L9IqGxZ2CwsV2tE298SSA==} - '@orpc/standard-server-peer@1.13.9': - resolution: {integrity: sha512-r8hSykxNIKwXSMuLYWBxQx1c3DU8b6nU8V76DZhtwC5g1SLYIzw+dzT/EgHplOfmsFeyodiEDXXX1k/twRLuzw==} + '@orpc/standard-server-peer@1.13.13': + resolution: {integrity: sha512-FeWAbXfnZDPYQRajM0hD6GJvHeC3DZILngAjdcLHy5zt3riu6nL2lLPSWDv5yNWWscmYU+CfKmXWd0Z01BOeWA==} - '@orpc/standard-server@1.13.9': - resolution: {integrity: sha512-dwsky7CScgOaDBa7CBF85aPGk/3UoB4fJjitVghb/sZD0Nt+CGIeiPHMsjEgxw5rJwgawMWLI5KxFH9euAJlWw==} + '@orpc/standard-server@1.13.13': + resolution: {integrity: sha512-9pgS8XvauuRQElkyuD8F3om+nN0KBEnTkhblDHCBzkZERjWkmfirJmshQrWHoFaDTk+nnXHIaY6d7TBTxXdPRw==} - '@orpc/tanstack-query@1.13.9': - resolution: {integrity: sha512-gOVJkCT9JGfu0e0TlTY3YUueXP2+Kzp6TcgfL2U3yXcYdTLv+jTrNOVJdtAAbeweUIU6dBEtatlhAQ7OgHWbsw==} + '@orpc/tanstack-query@1.13.13': + resolution: {integrity: sha512-6+Cheaiu+RDPdszdeRKoBINrF8MQp64zSeZB+L3gqgF43zlYDhLOgELZMzYa6U3U6bLk4rmIeubpk+i1kACfRg==} peerDependencies: - '@orpc/client': 1.13.9 + '@orpc/client': 1.13.13 '@tanstack/query-core': '>=5.80.2' '@ota-meshi/ast-token-store@0.3.0': resolution: {integrity: sha512-XRO0zi2NIUKq2lUk3T1ecFSld1fMWRKE6naRFGkgkdeosx7IslyUKNv5Dcb5PJTja9tHJoFu0v/7yEpAkrkrTg==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@oxc-parser/binding-android-arm-eabi@0.120.0': - resolution: {integrity: sha512-WU3qtINx802wOl8RxAF1v0VvmC2O4D9M8Sv486nLeQ7iPHVmncYZrtBhB4SYyX+XZxj2PNnCcN+PW21jHgiOxg==} + '@oxc-parser/binding-android-arm-eabi@0.121.0': + resolution: {integrity: sha512-n07FQcySwOlzap424/PLMtOkbS7xOu8nsJduKL8P3COGHKgKoDYXwoAHCbChfgFpHnviehrLWIPX0lKGtbEk/A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxc-parser/binding-android-arm64@0.120.0': - resolution: {integrity: sha512-SEf80EHdhlbjZEgzeWm0ZA/br4GKMenDW3QB/gtyeTV1gStvvZeFi40ioHDZvds2m4Z9J1bUAUL8yn1/+A6iGg==} + '@oxc-parser/binding-android-arm64@0.121.0': + resolution: {integrity: sha512-/Dd1xIXboYAicw+twT2utxPD7bL8qh7d3ej0qvaYIMj3/EgIrGR+tSnjCUkiCT6g6uTC0neSS4JY8LxhdSU/sA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxc-parser/binding-darwin-arm64@0.120.0': - resolution: {integrity: sha512-xVrrbCai8R8CUIBu3CjryutQnEYhZqs1maIqDvtUCFZb8vY33H7uh9mHpL3a0JBIKoBUKjPH8+rzyAeXnS2d6A==} + '@oxc-parser/binding-darwin-arm64@0.121.0': + resolution: {integrity: sha512-A0jNEvv7QMtCO1yk205t3DWU9sWUjQ2KNF0hSVO5W9R9r/R1BIvzG01UQAfmtC0dQm7sCrs5puixurKSfr2bRQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxc-parser/binding-darwin-x64@0.120.0': - resolution: {integrity: sha512-xyHBbnJ6mydnQUH7MAcafOkkrNzQC6T+LXgDH/3InEq2BWl/g424IMRiJVSpVqGjB+p2bd0h0WRR8iIwzjU7rw==} + '@oxc-parser/binding-darwin-x64@0.121.0': + resolution: {integrity: sha512-SsHzipdxTKUs3I9EOAPmnIimEeJOemqRlRDOp9LIj+96wtxZejF51gNibmoGq8KoqbT1ssAI5po/E3J+vEtXGA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxc-parser/binding-freebsd-x64@0.120.0': - resolution: {integrity: sha512-UMnVRllquXUYTeNfFKmxTTEdZ/ix1nLl0ducDzMSREoWYGVIHnOOxoKMWlCOvRr9Wk/HZqo2rh1jeumbPGPV9A==} + '@oxc-parser/binding-freebsd-x64@0.121.0': + resolution: {integrity: sha512-v1APOTkCp+RWOIDAHRoaeW/UoaHF15a60E8eUL6kUQXh+i4K7PBwq2Wi7jm8p0ymID5/m/oC1w3W31Z/+r7HQw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxc-parser/binding-linux-arm-gnueabihf@0.120.0': - resolution: {integrity: sha512-tkvn2CQ7QdcsMnpfiX3fd3wA3EFsWKYlcQzq9cFw/xc89Al7W6Y4O0FgLVkVQpo0Tnq/qtE1XfkJOnRRA9S/NA==} + '@oxc-parser/binding-linux-arm-gnueabihf@0.121.0': + resolution: {integrity: sha512-PmqPQuqHZyFVWA4ycr0eu4VnTMmq9laOHZd+8R359w6kzuNZPvmmunmNJ8ybkm769A0nCoVp3TJ6dUz7B3FYIQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxc-parser/binding-linux-arm-musleabihf@0.120.0': - resolution: {integrity: sha512-WN5y135Ic42gQDk9grbwY9++fDhqf8knN6fnP+0WALlAUh4odY/BDK1nfTJRSfpJD9P3r1BwU0m3pW2DU89whQ==} + '@oxc-parser/binding-linux-arm-musleabihf@0.121.0': + resolution: {integrity: sha512-vF24htj+MOH+Q7y9A8NuC6pUZu8t/C2Fr/kDOi2OcNf28oogr2xadBPXAbml802E8wRAVfbta6YLDQTearz+jw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxc-parser/binding-linux-arm64-gnu@0.120.0': - resolution: {integrity: sha512-1GgQBCcXvFMw99EPdMy+4NZ3aYyXsxjf9kbUUg8HuAy3ZBXzOry5KfFEzT9nqmgZI1cuetvApkiJBZLAPo8uaw==} + '@oxc-parser/binding-linux-arm64-gnu@0.121.0': + resolution: {integrity: sha512-wjH8cIG2Lu/3d64iZpbYr73hREMgKAfu7fqpXjgM2S16y2zhTfDIp8EQjxO8vlDtKP5Rc7waZW72lh8nZtWrpA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@oxc-parser/binding-linux-arm64-musl@0.120.0': - resolution: {integrity: sha512-gmMQ70gsPdDBgpcErvJEoWNBr7bJooSLlvOBVBSGfOzlP5NvJ3bFvnUeZZ9d+dPrqSngtonf7nyzWUTUj/U+lw==} + '@oxc-parser/binding-linux-arm64-musl@0.121.0': + resolution: {integrity: sha512-qT663J/W8yQFw3dtscbEi9LKJevr20V7uWs2MPGTnvNZ3rm8anhhE16gXGpxDOHeg9raySaSHKhd4IGa3YZvuw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@oxc-parser/binding-linux-ppc64-gnu@0.120.0': - resolution: {integrity: sha512-T/kZuU0ajop0xhzVMwH5r3srC9Nqup5HaIo+3uFjIN5uPxa0LvSxC1ZqP4aQGJVW5G0z8/nCkjIfSMS91P/wzw==} + '@oxc-parser/binding-linux-ppc64-gnu@0.121.0': + resolution: {integrity: sha512-mYNe4NhVvDBbPkAP8JaVS8lC1dsoJZWH5WCjpw5E+sjhk1R08wt3NnXYUzum7tIiWPfgQxbCMcoxgeemFASbRw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@oxc-parser/binding-linux-riscv64-gnu@0.120.0': - resolution: {integrity: sha512-vn21KXLAXzaI3N5CZWlBr1iWeXLl9QFIMor7S1hUjUGTeUuWCoE6JZB040/ZNDwf+JXPX8Ao9KbmJq9FMC2iGw==} + '@oxc-parser/binding-linux-riscv64-gnu@0.121.0': + resolution: {integrity: sha512-+QiFoGxhAbaI/amqX567784cDyyuZIpinBrJNxUzb+/L2aBRX67mN6Jv40pqduHf15yYByI+K5gUEygCuv0z9w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - '@oxc-parser/binding-linux-riscv64-musl@0.120.0': - resolution: {integrity: sha512-SUbUxlar007LTGmSLGIC5x/WJvwhdX+PwNzFJ9f/nOzZOrCFbOT4ikt7pJIRg1tXVsEfzk5mWpGO1NFiSs4PIw==} + '@oxc-parser/binding-linux-riscv64-musl@0.121.0': + resolution: {integrity: sha512-9ykEgyTa5JD/Uhv2sttbKnCfl2PieUfOjyxJC/oDL2UO0qtXOtjPLl7H8Kaj5G7p3hIvFgu3YWvAxvE0sqY+hQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - '@oxc-parser/binding-linux-s390x-gnu@0.120.0': - resolution: {integrity: sha512-hYiPJTxyfJY2+lMBFk3p2bo0R9GN+TtpPFlRqVchL1qvLG+pznstramHNvJlw9AjaoRUHwp9IKR7UZQnRPGjgQ==} + '@oxc-parser/binding-linux-s390x-gnu@0.121.0': + resolution: {integrity: sha512-DB1EW5VHZdc1lIRjOI3bW/wV6R6y0xlfvdVrqj6kKi7Ayu2U3UqUBdq9KviVkcUGd5Oq+dROqvUEEFRXGAM7EQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@oxc-parser/binding-linux-x64-gnu@0.120.0': - resolution: {integrity: sha512-q+5jSVZkprJCIy3dzJpApat0InJaoxQLsJuD6DkX8hrUS61z2lHQ1Fe9L2+TYbKHXCLWbL0zXe7ovkIdopBGMQ==} + '@oxc-parser/binding-linux-x64-gnu@0.121.0': + resolution: {integrity: sha512-s4lfobX9p4kPTclvMiH3gcQUd88VlnkMTF6n2MTMDAyX5FPNRhhRSFZK05Ykhf8Zy5NibV4PbGR6DnK7FGNN6A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@oxc-parser/binding-linux-x64-musl@0.120.0': - resolution: {integrity: sha512-D9QDDZNnH24e7X4ftSa6ar/2hCavETfW3uk0zgcMIrZNy459O5deTbWrjGzZiVrSWigGtlQwzs2McBP0QsfV1w==} + '@oxc-parser/binding-linux-x64-musl@0.121.0': + resolution: {integrity: sha512-P9KlyTpuBuMi3NRGpJO8MicuGZfOoqZVRP1WjOecwx8yk4L/+mrCRNc5egSi0byhuReblBF2oVoDSMgV9Bj4Hw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@oxc-parser/binding-openharmony-arm64@0.120.0': - resolution: {integrity: sha512-TBU8ZwOUWAOUWVfmI16CYWbvh4uQb9zHnGBHsw5Cp2JUVG044OIY1CSHODLifqzQIMTXvDvLzcL89GGdUIqNrA==} + '@oxc-parser/binding-openharmony-arm64@0.121.0': + resolution: {integrity: sha512-R+4jrWOfF2OAPPhj3Eb3U5CaKNAH9/btMveMULIrcNW/hjfysFQlF8wE0GaVBr81dWz8JLgQlsxwctoL78JwXw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxc-parser/binding-wasm32-wasi@0.120.0': - resolution: {integrity: sha512-WG/FOZgDJCpJnuF3ToG/K28rcOmSY7FmFmfBKYb2fmLyhDzPpUldFGV7/Fz4ru0Iz/v4KPmf8xVgO8N3lO4KHA==} + '@oxc-parser/binding-wasm32-wasi@0.121.0': + resolution: {integrity: sha512-5TFISkPTymKvsmIlKasPVTPuWxzCcrT8pM+p77+mtQbIZDd1UC8zww4CJcRI46kolmgrEX6QpKO8AvWMVZ+ifw==} engines: {node: '>=14.0.0'} cpu: [wasm32] - '@oxc-parser/binding-win32-arm64-msvc@0.120.0': - resolution: {integrity: sha512-1T0HKGcsz/BKo77t7+89L8Qvu4f9DoleKWHp3C5sJEcbCjDOLx3m9m722bWZTY+hANlUEs+yjlK+lBFsA+vrVQ==} + '@oxc-parser/binding-win32-arm64-msvc@0.121.0': + resolution: {integrity: sha512-V0pxh4mql4XTt3aiEtRNUeBAUFOw5jzZNxPABLaOKAWrVzSr9+XUaB095lY7jqMf5t8vkfh8NManGB28zanYKw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxc-parser/binding-win32-ia32-msvc@0.120.0': - resolution: {integrity: sha512-L7vfLzbOXsjBXV0rv/6Y3Jd9BRjPeCivINZAqrSyAOZN3moCopDN+Psq9ZrGNZtJzP8946MtlRFZ0Als0wBCOw==} + '@oxc-parser/binding-win32-ia32-msvc@0.121.0': + resolution: {integrity: sha512-4Ob1qvYMPnlF2N9rdmKdkQFdrq16QVcQwBsO8yiPZXof0fHKFF+LmQV501XFbi7lHyrKm8rlJRfQ/M8bZZPVLw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxc-parser/binding-win32-x64-msvc@0.120.0': - resolution: {integrity: sha512-ys+upfqNtSu58huAhJMBKl3XCkGzyVFBlMlGPzHeFKgpFF/OdgNs1MMf8oaJIbgMH8ZxgGF7qfue39eJohmKIg==} + '@oxc-parser/binding-win32-x64-msvc@0.121.0': + resolution: {integrity: sha512-BOp1KCzdboB1tPqoCPXgntgFs0jjeSyOXHzgxVFR7B/qfr3F8r4YDacHkTOUNXtDgM8YwKnkf3rE5gwALYX7NA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@oxc-project/runtime@0.120.0': - resolution: {integrity: sha512-7fvACzS46TkHuzA+Tag8ac40qfwURXRTdc4AtyItF59AoNPOO/QjPMqPyvJH8CaUdGu0ntWDX1CCUNyLMxxX5g==} + '@oxc-project/runtime@0.121.0': + resolution: {integrity: sha512-p0bQukD8OEHxzY4T9OlANBbEFGnOnjo1CYi50HES7OD36UO2yPh6T+uOJKLtlg06eclxroipRCpQGMpeH8EJ/g==} engines: {node: ^20.19.0 || >=22.12.0} - '@oxc-project/types@0.120.0': - resolution: {integrity: sha512-k1YNu55DuvAip/MGE1FTsIuU3FUCn6v/ujG9V7Nq5Df/kX2CWb13hhwD0lmJGMGqE+bE1MXvv9SZVnMzEXlWcg==} + '@oxc-project/types@0.121.0': + resolution: {integrity: sha512-CGtOARQb9tyv7ECgdAlFxi0Fv7lmzvmlm2rpD/RdijOO9rfk/JvB1CjT8EnoD+tjna/IYgKKw3IV7objRb+aYw==} + + '@oxc-project/types@0.122.0': + resolution: {integrity: sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==} '@oxc-resolver/binding-android-arm-eabi@11.19.1': resolution: {integrity: sha512-aUs47y+xyXHUKlbhqHUjBABjvycq6YSD7bpxSW7vplUmdzAlJ93yXY6ZR0c1o1x5A/QKbENCvs3+NlY8IpIVzg==} @@ -2060,276 +2704,276 @@ packages: cpu: [x64] os: [win32] - '@oxfmt/binding-android-arm-eabi@0.41.0': - resolution: {integrity: sha512-REfrqeMKGkfMP+m/ScX4f5jJBSmVNYcpoDF8vP8f8eYPDuPGZmzp56NIUsYmx3h7f6NzC6cE3gqh8GDWrJHCKw==} + '@oxfmt/binding-android-arm-eabi@0.42.0': + resolution: {integrity: sha512-dsqPTYsozeokRjlrt/b4E7Pj0z3eS3Eg74TWQuuKbjY4VttBmA88rB7d50Xrd+TZ986qdXCNeZRPEzZHAe+jow==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxfmt/binding-android-arm64@0.41.0': - resolution: {integrity: sha512-s0b1dxNgb2KomspFV2LfogC2XtSJB42POXF4bMCLJyvQmAGos4ZtjGPfQreToQEaY0FQFjz3030ggI36rF1q5g==} + '@oxfmt/binding-android-arm64@0.42.0': + resolution: {integrity: sha512-t+aAjHxcr5eOBphFHdg1ouQU9qmZZoRxnX7UOJSaTwSoKsb6TYezNKO0YbWytGXCECObRqNcUxPoPr0KaraAIg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxfmt/binding-darwin-arm64@0.41.0': - resolution: {integrity: sha512-EGXGualADbv/ZmamE7/2DbsrYmjoPlAmHEpTL4vapLF4EfVD6fr8/uQDFnPJkUBjiSWFJZtFNsGeN1B6V3owmA==} + '@oxfmt/binding-darwin-arm64@0.42.0': + resolution: {integrity: sha512-ulpSEYMKg61C5bRMZinFHrKJYRoKGVbvMEXA5zM1puX3O9T6Q4XXDbft20yrDijpYWeuG59z3Nabt+npeTsM1A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxfmt/binding-darwin-x64@0.41.0': - resolution: {integrity: sha512-WxySJEvdQQYMmyvISH3qDpTvoS0ebnIP63IMxLLWowJyPp/AAH0hdWtlo+iGNK5y3eVfa5jZguwNaQkDKWpGSw==} + '@oxfmt/binding-darwin-x64@0.42.0': + resolution: {integrity: sha512-ttxLKhQYPdFiM8I/Ri37cvqChE4Xa562nNOsZFcv1CKTVLeEozXjKuYClNvxkXmNlcF55nzM80P+CQkdFBu+uQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxfmt/binding-freebsd-x64@0.41.0': - resolution: {integrity: sha512-Y2kzMkv3U3oyuYaR4wTfGjOTYTXiFC/hXmG0yVASKkbh02BJkvD98Ij8bIevr45hNZ0DmZEgqiXF+9buD4yMYQ==} + '@oxfmt/binding-freebsd-x64@0.42.0': + resolution: {integrity: sha512-Og7QS3yI3tdIKYZ58SXik0rADxIk2jmd+/YvuHRyKULWpG4V2fR5V4hvKm624Mc0cQET35waPXiCQWvjQEjwYQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxfmt/binding-linux-arm-gnueabihf@0.41.0': - resolution: {integrity: sha512-ptazDjdUyhket01IjPTT6ULS1KFuBfTUU97osTP96X5y/0oso+AgAaJzuH81oP0+XXyrWIHbRzozSAuQm4p48g==} + '@oxfmt/binding-linux-arm-gnueabihf@0.42.0': + resolution: {integrity: sha512-jwLOw/3CW4H6Vxcry4/buQHk7zm9Ne2YsidzTL1kpiMe4qqrRCwev3dkyWe2YkFmP+iZCQ7zku4KwjcLRoh8ew==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxfmt/binding-linux-arm-musleabihf@0.41.0': - resolution: {integrity: sha512-UkoL2OKxFD+56bPEBcdGn+4juTW4HRv/T6w1dIDLnvKKWr6DbarB/mtHXlADKlFiJubJz8pRkttOR7qjYR6lTA==} + '@oxfmt/binding-linux-arm-musleabihf@0.42.0': + resolution: {integrity: sha512-XwXu2vkMtiq2h7tfvN+WA/9/5/1IoGAVCFPiiQUvcAuG3efR97KNcRGM8BetmbYouFotQ2bDal3yyjUx6IPsTg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxfmt/binding-linux-arm64-gnu@0.41.0': - resolution: {integrity: sha512-gofu0PuumSOHYczD8p62CPY4UF6ee+rSLZJdUXkpwxg6pILiwSDBIouPskjF/5nF3A7QZTz2O9KFNkNxxFN9tA==} + '@oxfmt/binding-linux-arm64-gnu@0.42.0': + resolution: {integrity: sha512-ea7s/XUJoT7ENAtUQDudFe3nkSM3e3Qpz4nJFRdzO2wbgXEcjnchKLEsV3+t4ev3r8nWxIYr9NRjPWtnyIFJVA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-arm64-musl@0.41.0': - resolution: {integrity: sha512-VfVZxL0+6RU86T8F8vKiDBa+iHsr8PAjQmKGBzSCAX70b6x+UOMFl+2dNihmKmUwqkCazCPfYjt6SuAPOeQJ3g==} + '@oxfmt/binding-linux-arm64-musl@0.42.0': + resolution: {integrity: sha512-+JA0YMlSdDqmacygGi2REp57c3fN+tzARD8nwsukx9pkCHK+6DkbAA9ojS4lNKsiBjIW8WWa0pBrBWhdZEqfuw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@oxfmt/binding-linux-ppc64-gnu@0.41.0': - resolution: {integrity: sha512-bwzokz2eGvdfJbc0i+zXMJ4BBjQPqg13jyWpEEZDOrBCQ91r8KeY2Mi2kUeuMTZNFXju+jcAbAbpyJxRGla0eg==} + '@oxfmt/binding-linux-ppc64-gnu@0.42.0': + resolution: {integrity: sha512-VfnET0j4Y5mdfCzh5gBt0NK28lgn5DKx+8WgSMLYYeSooHhohdbzwAStLki9pNuGy51y4I7IoW8bqwAaCMiJQg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-riscv64-gnu@0.41.0': - resolution: {integrity: sha512-POLM//PCH9uqDeNDwWL3b3DkMmI3oI2cU6hwc2lnztD1o7dzrQs3R9nq555BZ6wI7t2lyhT9CS+CRaz5X0XqLA==} + '@oxfmt/binding-linux-riscv64-gnu@0.42.0': + resolution: {integrity: sha512-gVlCbmBkB0fxBWbhBj9rcxezPydsQHf4MFKeHoTSPicOQ+8oGeTQgQ8EeesSybWeiFPVRx3bgdt4IJnH6nOjAA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-riscv64-musl@0.41.0': - resolution: {integrity: sha512-NNK7PzhFqLUwx/G12Xtm6scGv7UITvyGdAR5Y+TlqsG+essnuRWR4jRNODWRjzLZod0T3SayRbnkSIWMBov33w==} + '@oxfmt/binding-linux-riscv64-musl@0.42.0': + resolution: {integrity: sha512-zN5OfstL0avgt/IgvRu0zjQzVh/EPkcLzs33E9LMAzpqlLWiPWeMDZyMGFlSRGOdDjuNmlZBCgj0pFnK5u32TQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - '@oxfmt/binding-linux-s390x-gnu@0.41.0': - resolution: {integrity: sha512-qVf/zDC5cN9eKe4qI/O/m445er1IRl6swsSl7jHkqmOSVfknwCe5JXitYjZca+V/cNJSU/xPlC5EFMabMMFDpw==} + '@oxfmt/binding-linux-s390x-gnu@0.42.0': + resolution: {integrity: sha512-9X6+H2L0qMc2sCAgO9HS03bkGLMKvOFjmEdchaFlany3vNZOjnVui//D8k/xZAtQv2vaCs1reD5KAgPoIU4msA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-x64-gnu@0.41.0': - resolution: {integrity: sha512-ojxYWu7vUb6ysYqVCPHuAPVZHAI40gfZ0PDtZAMwVmh2f0V8ExpPIKoAKr7/8sNbAXJBBpZhs2coypIo2jJX4w==} + '@oxfmt/binding-linux-x64-gnu@0.42.0': + resolution: {integrity: sha512-BajxJ6KQvMMdpXGPWhBGyjb2Jvx4uec0w+wi6TJZ6Tv7+MzPwe0pO8g5h1U0jyFgoaF7mDl6yKPW3ykWcbUJRw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-x64-musl@0.41.0': - resolution: {integrity: sha512-O2exZLBxoCMIv2vlvcbkdedazJPTdG0VSup+0QUCfYQtx751zCZNboX2ZUOiQ/gDTdhtXvSiot0h6GEGkOyalA==} + '@oxfmt/binding-linux-x64-musl@0.42.0': + resolution: {integrity: sha512-0wV284I6vc5f0AqAhgAbHU2935B4bVpncPoe5n/WzVZY/KnHgqxC8iSFGeSyLWEgstFboIcWkOPck7tqbdHkzA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@oxfmt/binding-openharmony-arm64@0.41.0': - resolution: {integrity: sha512-N+31/VoL+z+NNBt8viy3I4NaIdPbiYeOnB884LKqvXldaE2dRztdPv3q5ipfZYv0RwFp7JfqS4I27K/DSHCakg==} + '@oxfmt/binding-openharmony-arm64@0.42.0': + resolution: {integrity: sha512-p4BG6HpGnhfgHk1rzZfyR6zcWkE7iLrWxyehHfXUy4Qa5j3e0roglFOdP/Nj5cJJ58MA3isQ5dlfkW2nNEpolw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxfmt/binding-win32-arm64-msvc@0.41.0': - resolution: {integrity: sha512-Z7NAtu/RN8kjCQ1y5oDD0nTAeRswh3GJ93qwcW51srmidP7XPBmZbLlwERu1W5veCevQJtPS9xmkpcDTYsGIwQ==} + '@oxfmt/binding-win32-arm64-msvc@0.42.0': + resolution: {integrity: sha512-mn//WV60A+IetORDxYieYGAoQso4KnVRRjORDewMcod4irlRe0OSC7YPhhwaexYNPQz/GCFk+v9iUcZ2W22yxQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxfmt/binding-win32-ia32-msvc@0.41.0': - resolution: {integrity: sha512-uNxxP3l4bJ6VyzIeRqCmBU2Q0SkCFgIhvx9/9dJ9V8t/v+jP1IBsuaLwCXGR8JPHtkj4tFp+RHtUmU2ZYAUpMA==} + '@oxfmt/binding-win32-ia32-msvc@0.42.0': + resolution: {integrity: sha512-3gWltUrvuz4LPJXWivoAxZ28Of2O4N7OGuM5/X3ubPXCEV8hmgECLZzjz7UYvSDUS3grfdccQwmjynm+51EFpw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxfmt/binding-win32-x64-msvc@0.41.0': - resolution: {integrity: sha512-49ZSpbZ1noozyPapE8SUOSm3IN0Ze4b5nkO+4+7fq6oEYQQJFhE0saj5k/Gg4oewVPdjn0L3ZFeWk2Vehjcw7A==} + '@oxfmt/binding-win32-x64-msvc@0.42.0': + resolution: {integrity: sha512-Wg4TMAfQRL9J9AZevJ/ZNy3uyyDztDYQtGr4P8UyyzIhLhFrdSmz1J/9JT+rv0fiCDLaFOBQnj3f3K3+a5PzDQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@oxlint-tsgolint/darwin-arm64@0.17.1': - resolution: {integrity: sha512-JNWNwyvSDcUQSBlQRl10XrCeNcN66TMvDw3gIDQeop5SNa1F7wFhsEx4zitYb7fGHwGh9095tsNttmuCaNXCbw==} + '@oxlint-tsgolint/darwin-arm64@0.17.3': + resolution: {integrity: sha512-5aDl4mxXWs+Bj02pNrX6YY6v9KMZjLIytXoqolLEo0dfBNVeZUonZgJAa/w0aUmijwIRrBhxEzb42oLuUtfkGw==} cpu: [arm64] os: [darwin] - '@oxlint-tsgolint/darwin-x64@0.17.1': - resolution: {integrity: sha512-SluNf6CW88pgGPqQUGC5GoK5qESWo2ct1PRDbza3vbf9SK2npx3igvylGQIgE9qYYOcjgnVdLOJ0+q0gItgUmQ==} + '@oxlint-tsgolint/darwin-x64@0.17.3': + resolution: {integrity: sha512-gPBy4DS5ueCgXzko20XsNZzDe/Cxde056B+QuPLGvz05CGEAtmRfpImwnyY2lAXXjPL+SmnC/OYexu8zI12yHQ==} cpu: [x64] os: [darwin] - '@oxlint-tsgolint/linux-arm64@0.17.1': - resolution: {integrity: sha512-BJxQ7/cdo2dNdGIBs2PIR6BaPA7cPfe+r1HE/uY+K7g2ygip+0LHB3GUO9GaNDZuWpsnDyjLYYowEGrVK8dokA==} + '@oxlint-tsgolint/linux-arm64@0.17.3': + resolution: {integrity: sha512-+pkunvCfB6pB0G9qHVVXUao3nqzXQPo4O3DReIi+5nGa+bOU3J3Srgy+Zb8VyOL+WDsSMJ+U7+r09cKHWhz3hg==} cpu: [arm64] os: [linux] - '@oxlint-tsgolint/linux-x64@0.17.1': - resolution: {integrity: sha512-s6UjmuaJbZ4zz/wJKdEw/s5mc0t41rgwxQJCSHPuzMumMK6ylrB7nydhDf8ObTtzhTIZdAS/2S/uayJmDcGbxw==} + '@oxlint-tsgolint/linux-x64@0.17.3': + resolution: {integrity: sha512-/kW5oXtBThu4FjmgIBthdmMjWLzT3M1TEDQhxDu7hQU5xDeTd60CDXb2SSwKCbue9xu7MbiFoJu83LN0Z/d38g==} cpu: [x64] os: [linux] - '@oxlint-tsgolint/win32-arm64@0.17.1': - resolution: {integrity: sha512-EO/Oj0ixHX+UQdu9hM7YUzibZI888MvPUo/DF8lSxFBt4JNEt8qGkwJEbCYjB/1LhUNmPHzSw2Tr9dCFVfW9nw==} + '@oxlint-tsgolint/win32-arm64@0.17.3': + resolution: {integrity: sha512-NMELRvbz4Ed4dxg8WiqZxtu3k4OJEp2B9KInZW+BMfqEqbwZdEJY83tbqz2hD1EjKO2akrqBQ0GpRUJEkd8kKw==} cpu: [arm64] os: [win32] - '@oxlint-tsgolint/win32-x64@0.17.1': - resolution: {integrity: sha512-jhv7XktAJ1sMRSb//yDYTauFSZ06H81i2SLEBPaSUKxSKoPMK8p1ACUJlnmwZX2MgapRLEj1Ml22B6+HiM2YIA==} + '@oxlint-tsgolint/win32-x64@0.17.3': + resolution: {integrity: sha512-+pJ7r8J3SLPws5uoidVplZc8R/lpKyKPE6LoPGv9BME00Y1VjT6jWGx/dtUN8PWvcu3iTC6k+8u3ojFSJNmWTg==} cpu: [x64] os: [win32] - '@oxlint/binding-android-arm-eabi@1.56.0': - resolution: {integrity: sha512-IyfYPthZyiSKwAv/dLjeO18SaK8MxLI9Yss2JrRDyweQAkuL3LhEy7pwIwI7uA3KQc1Vdn20kdmj3q0oUIQL6A==} + '@oxlint/binding-android-arm-eabi@1.57.0': + resolution: {integrity: sha512-C7EiyfAJG4B70496eV543nKiq5cH0o/xIh/ufbjQz3SIvHhlDDsyn+mRFh+aW8KskTyUpyH2LGWL8p2oN6bl1A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxlint/binding-android-arm64@1.56.0': - resolution: {integrity: sha512-Ga5zYrzH6vc/VFxhn6MmyUnYEfy9vRpwTIks99mY3j6Nz30yYpIkWryI0QKPCgvGUtDSXVLEaMum5nA+WrNOSg==} + '@oxlint/binding-android-arm64@1.57.0': + resolution: {integrity: sha512-9i80AresjZ/FZf5xK8tKFbhQnijD4s1eOZw6/FHUwD59HEZbVLRc2C88ADYJfLZrF5XofWDiRX/Ja9KefCLy7w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxlint/binding-darwin-arm64@1.56.0': - resolution: {integrity: sha512-ogmbdJysnw/D4bDcpf1sPLpFThZ48lYp4aKYm10Z/6Nh1SON6NtnNhTNOlhEY296tDFItsZUz+2tgcSYqh8Eyw==} + '@oxlint/binding-darwin-arm64@1.57.0': + resolution: {integrity: sha512-0eUfhRz5L2yKa9I8k3qpyl37XK3oBS5BvrgdVIx599WZK63P8sMbg+0s4IuxmIiZuBK68Ek+Z+gcKgeYf0otsg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxlint/binding-darwin-x64@1.56.0': - resolution: {integrity: sha512-x8QE1h+RAtQ2g+3KPsP6Fk/tdz6zJQUv5c7fTrJxXV3GHOo+Ry5p/PsogU4U+iUZg0rj6hS+E4xi+mnwwlDCWQ==} + '@oxlint/binding-darwin-x64@1.57.0': + resolution: {integrity: sha512-UvrSuzBaYOue+QMAcuDITe0k/Vhj6KZGjfnI6x+NkxBTke/VoM7ZisaxgNY0LWuBkTnd1OmeQfEQdQ48fRjkQg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxlint/binding-freebsd-x64@1.56.0': - resolution: {integrity: sha512-6G+WMZvwJpMvY7my+/SHEjb7BTk/PFbePqLpmVmUJRIsJMy/UlyYqjpuh0RCgYYkPLcnXm1rUM04kbTk8yS1Yg==} + '@oxlint/binding-freebsd-x64@1.57.0': + resolution: {integrity: sha512-wtQq0dCoiw4bUwlsNVDJJ3pxJA218fOezpgtLKrbQqUtQJcM9yP8z+I9fu14aHg0uyAxIY+99toL6uBa2r7nxA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxlint/binding-linux-arm-gnueabihf@1.56.0': - resolution: {integrity: sha512-YYHBsk/sl7fYwQOok+6W5lBPeUEvisznV/HZD2IfZmF3Bns6cPC3Z0vCtSEOaAWTjYWN3jVsdu55jMxKlsdlhg==} + '@oxlint/binding-linux-arm-gnueabihf@1.57.0': + resolution: {integrity: sha512-qxFWl2BBBFcT4djKa+OtMdnLgoHEJXpqjyGwz8OhW35ImoCwR5qtAGqApNYce5260FQqoAHW8S8eZTjiX67Tsg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm-musleabihf@1.56.0': - resolution: {integrity: sha512-+AZK8rOUr78y8WT6XkDb04IbMRqauNV+vgT6f8ZLOH8wnpQ9i7Nol0XLxAu+Cq7Sb+J9wC0j6Km5hG8rj47/yQ==} + '@oxlint/binding-linux-arm-musleabihf@1.57.0': + resolution: {integrity: sha512-SQoIsBU7J0bDW15/f0/RvxHfY3Y0+eB/caKBQtNFbuerTiA6JCYx9P1MrrFTwY2dTm/lMgTSgskvCEYk2AtG/Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm64-gnu@1.56.0': - resolution: {integrity: sha512-urse2SnugwJRojUkGSSeH2LPMaje5Q50yQtvtL9HFckiyeqXzoFwOAZqD5TR29R2lq7UHidfFDM9EGcchcbb8A==} + '@oxlint/binding-linux-arm64-gnu@1.57.0': + resolution: {integrity: sha512-jqxYd1W6WMeozsCmqe9Rzbu3SRrGTyGDAipRlRggetyYbUksJqJKvUNTQtZR/KFoJPb+grnSm5SHhdWrywv3RQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-arm64-musl@1.56.0': - resolution: {integrity: sha512-rkTZkBfJ4TYLjansjSzL6mgZOdN5IvUnSq3oNJSLwBcNvy3dlgQtpHPrRxrCEbbcp7oQ6If0tkNaqfOsphYZ9g==} + '@oxlint/binding-linux-arm64-musl@1.57.0': + resolution: {integrity: sha512-i66WyEPVEvq9bxRUCJ/MP5EBfnTDN3nhwEdFZFTO5MmLLvzngfWEG3NSdXQzTT3vk5B9i6C2XSIYBh+aG6uqyg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@oxlint/binding-linux-ppc64-gnu@1.56.0': - resolution: {integrity: sha512-uqL1kMH3u69/e1CH2EJhP3CP28jw2ExLsku4o8RVAZ7fySo9zOyI2fy9pVlTAp4voBLVgzndXi3SgtdyCTa2aA==} + '@oxlint/binding-linux-ppc64-gnu@1.57.0': + resolution: {integrity: sha512-oMZDCwz4NobclZU3pH+V1/upVlJZiZvne4jQP+zhJwt+lmio4XXr4qG47CehvrW1Lx2YZiIHuxM2D4YpkG3KVA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-gnu@1.56.0': - resolution: {integrity: sha512-j0CcMBOgV6KsRaBdsebIeiy7hCjEvq2KdEsiULf2LZqAq0v1M1lWjelhCV57LxsqaIGChXFuFJ0RiFrSRHPhSg==} + '@oxlint/binding-linux-riscv64-gnu@1.57.0': + resolution: {integrity: sha512-uoBnjJ3MMEBbfnWC1jSFr7/nSCkcQYa72NYoNtLl1imshDnWSolYCjzb8LVCwYCCfLJXD+0gBLD7fyC14c0+0g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-musl@1.56.0': - resolution: {integrity: sha512-7VDOiL8cDG3DQ/CY3yKjbV1c4YPvc4vH8qW09Vv+5ukq3l/Kcyr6XGCd5NvxUmxqDb2vjMpM+eW/4JrEEsUetA==} + '@oxlint/binding-linux-riscv64-musl@1.57.0': + resolution: {integrity: sha512-BdrwD7haPZ8a9KrZhKJRSj6jwCor+Z8tHFZ3PT89Y3Jq5v3LfMfEePeAmD0LOTWpiTmzSzdmyw9ijneapiVHKQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - '@oxlint/binding-linux-s390x-gnu@1.56.0': - resolution: {integrity: sha512-JGRpX0M+ikD3WpwJ7vKcHKV6Kg0dT52BW2Eu2BupXotYeqGXBrbY+QPkAyKO6MNgKozyTNaRh3r7g+VWgyAQYQ==} + '@oxlint/binding-linux-s390x-gnu@1.57.0': + resolution: {integrity: sha512-BNs+7ZNsRstVg2tpNxAXfMX/Iv5oZh204dVyb8Z37+/gCh+yZqNTlg6YwCLIMPSk5wLWIGOaQjT0GUOahKYImw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-gnu@1.56.0': - resolution: {integrity: sha512-dNaICPvtmuxFP/VbqdofrLqdS3bM/AKJN3LMJD52si44ea7Be1cBk6NpfIahaysG9Uo+L98QKddU9CD5L8UHnQ==} + '@oxlint/binding-linux-x64-gnu@1.57.0': + resolution: {integrity: sha512-AghS18w+XcENcAX0+BQGLiqjpqpaxKJa4cWWP0OWNLacs27vHBxu7TYkv9LUSGe5w8lOJHeMxcYfZNOAPqw2bg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-musl@1.56.0': - resolution: {integrity: sha512-pF1vOtM+GuXmbklM1hV8WMsn6tCNPvkUzklj/Ej98JhlanbmA2RB1BILgOpwSuCTRTIYx2MXssmEyQQ90QF5aA==} + '@oxlint/binding-linux-x64-musl@1.57.0': + resolution: {integrity: sha512-E/FV3GB8phu/Rpkhz5T96hAiJlGzn91qX5yj5gU754P5cmVGXY1Jw/VSjDSlZBCY3VHjsVLdzgdkJaomEmcNOg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@oxlint/binding-openharmony-arm64@1.56.0': - resolution: {integrity: sha512-bp8NQ4RE6fDIFLa4bdBiOA+TAvkNkg+rslR+AvvjlLTYXLy9/uKAYLQudaQouWihLD/hgkrXIKKzXi5IXOewwg==} + '@oxlint/binding-openharmony-arm64@1.57.0': + resolution: {integrity: sha512-xvZ2yZt0nUVfU14iuGv3V25jpr9pov5N0Wr28RXnHFxHCRxNDMtYPHV61gGLhN9IlXM96gI4pyYpLSJC5ClLCQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxlint/binding-win32-arm64-msvc@1.56.0': - resolution: {integrity: sha512-PxT4OJDfMOQBzo3OlzFb9gkoSD+n8qSBxyVq2wQSZIHFQYGEqIRTo9M0ZStvZm5fdhMqaVYpOnJvH2hUMEDk/g==} + '@oxlint/binding-win32-arm64-msvc@1.57.0': + resolution: {integrity: sha512-Z4D8Pd0AyHBKeazhdIXeUUy5sIS3Mo0veOlzlDECg6PhRRKgEsBJCCV1n+keUZtQ04OP+i7+itS3kOykUyNhDg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxlint/binding-win32-ia32-msvc@1.56.0': - resolution: {integrity: sha512-PTRy6sIEPqy2x8PTP1baBNReN/BNEFmde0L+mYeHmjXE1Vlcc9+I5nsqENsB2yAm5wLkzPoTNCMY/7AnabT4/A==} + '@oxlint/binding-win32-ia32-msvc@1.57.0': + resolution: {integrity: sha512-StOZ9nFMVKvevicbQfql6Pouu9pgbeQnu60Fvhz2S6yfMaii+wnueLnqQ5I1JPgNF0Syew4voBlAaHD13wH6tw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxlint/binding-win32-x64-msvc@1.56.0': - resolution: {integrity: sha512-ZHa0clocjLmIDr+1LwoWtxRcoYniAvERotvwKUYKhH41NVfl0Y4LNbyQkwMZzwDvKklKGvGZ5+DAG58/Ik47tQ==} + '@oxlint/binding-win32-x64-msvc@1.57.0': + resolution: {integrity: sha512-6PuxhYgth8TuW0+ABPOIkGdBYw+qYGxgIdXPHSVpiCDm+hqTTWCmC739St1Xni0DJBt8HnSHTG67i1y6gr8qrA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -2426,6 +3070,11 @@ packages: resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@playwright/test@1.58.2': + resolution: {integrity: sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==} + engines: {node: '>=18'} + hasBin: true + '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} @@ -2714,6 +3363,104 @@ packages: resolution: {integrity: sha512-UuBOt7BOsKVOkFXRe4Ypd/lADuNIfqJXv8GvHqtXaTYXPPKkj2nS2zPllVsrtRjcomDhIJVBnZwfmlI222WH8g==} engines: {node: '>=14.0.0'} + '@rolldown/binding-android-arm64@1.0.0-rc.12': + resolution: {integrity: sha512-pv1y2Fv0JybcykuiiD3qBOBdz6RteYojRFY1d+b95WVuzx211CRh+ytI/+9iVyWQ6koTh5dawe4S/yRfOFjgaA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.0-rc.12': + resolution: {integrity: sha512-cFYr6zTG/3PXXF3pUO+umXxt1wkRK/0AYT8lDwuqvRC+LuKYWSAQAQZjCWDQpAH172ZV6ieYrNnFzVVcnSflAg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.0-rc.12': + resolution: {integrity: sha512-ZCsYknnHzeXYps0lGBz8JrF37GpE9bFVefrlmDrAQhOEi4IOIlcoU1+FwHEtyXGx2VkYAvhu7dyBf75EJQffBw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.0-rc.12': + resolution: {integrity: sha512-dMLeprcVsyJsKolRXyoTH3NL6qtsT0Y2xeuEA8WQJquWFXkEC4bcu1rLZZSnZRMtAqwtrF/Ib9Ddtpa/Gkge9Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.12': + resolution: {integrity: sha512-YqWjAgGC/9M1lz3GR1r1rP79nMgo3mQiiA+Hfo+pvKFK1fAJ1bCi0ZQVh8noOqNacuY1qIcfyVfP6HoyBRZ85Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.12': + resolution: {integrity: sha512-/I5AS4cIroLpslsmzXfwbe5OmWvSsrFuEw3mwvbQ1kDxJ822hFHIx+vsN/TAzNVyepI/j/GSzrtCIwQPeKCLIg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.12': + resolution: {integrity: sha512-V6/wZztnBqlx5hJQqNWwFdxIKN0m38p8Jas+VoSfgH54HSj9tKTt1dZvG6JRHcjh6D7TvrJPWFGaY9UBVOaWPw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.12': + resolution: {integrity: sha512-AP3E9BpcUYliZCxa3w5Kwj9OtEVDYK6sVoUzy4vTOJsjPOgdaJZKFmN4oOlX0Wp0RPV2ETfmIra9x1xuayFB7g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.12': + resolution: {integrity: sha512-nWwpvUSPkoFmZo0kQazZYOrT7J5DGOJ/+QHHzjvNlooDZED8oH82Yg67HvehPPLAg5fUff7TfWFHQS8IV1n3og==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.12': + resolution: {integrity: sha512-RNrafz5bcwRy+O9e6P8Z/OCAJW/A+qtBczIqVYwTs14pf4iV1/+eKEjdOUta93q2TsT/FI0XYDP3TCky38LMAg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.0.0-rc.12': + resolution: {integrity: sha512-Jpw/0iwoKWx3LJ2rc1yjFrj+T7iHZn2JDg1Yny1ma0luviFS4mhAIcd1LFNxK3EYu3DHWCps0ydXQ5i/rrJ2ig==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.12': + resolution: {integrity: sha512-vRugONE4yMfVn0+7lUKdKvN4D5YusEiPilaoO2sgUWpCvrncvWgPMzK00ZFFJuiPgLwgFNP5eSiUlv2tfc+lpA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.0-rc.12': + resolution: {integrity: sha512-ykGiLr/6kkiHc0XnBfmFJuCjr5ZYKKofkx+chJWDjitX+KsJuAmrzWhwyOMSHzPhzOHOy7u9HlFoa5MoAOJ/Zg==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.12': + resolution: {integrity: sha512-5eOND4duWkwx1AzCxadcOrNeighiLwMInEADT0YM7xeEOOFcovWZCq8dadXgcRHSf3Ulh1kFo/qvzoFiCLOL1Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.12': + resolution: {integrity: sha512-PyqoipaswDLAZtot351MLhrlrh6lcZPo2LSYE+VDxbVk24LVKAGOuE4hb8xZQmrPAuEtTZW8E6D2zc5EUZX4Lw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.0-rc.12': + resolution: {integrity: sha512-HHMwmarRKvoFsJorqYlFeFRzXZqCt2ETQlEDOb9aqssrnVBB1/+xgTGtuTrIk5vzLNX1MjMtTf7W9z3tsSbrxw==} + '@rolldown/pluginutils@1.0.0-rc.5': resolution: {integrity: sha512-RxlLX/DPoarZ9PtxVrQgZhPoor987YtKQqCo5zkjX+0S0yLJ7Vv515Wk6+xtTL67VONKJKxETWZwuZjss2idYw==} @@ -2876,32 +3623,32 @@ packages: cpu: [x64] os: [win32] - '@sentry-internal/browser-utils@10.45.0': - resolution: {integrity: sha512-ZPZpeIarXKScvquGx2AfNKcYiVNDA4wegMmjyGVsTA2JPmP0TrJoO3UybJS6KGDeee8V3I3EfD/ruauMm7jOFQ==} + '@sentry-internal/browser-utils@10.46.0': + resolution: {integrity: sha512-WB1gBT9G13V02ekZ6NpUhoI1aGHV2eNfjEPthkU2bGBvFpQKnstwzjg7waIRGR7cu+YSW2Q6UI6aQLgBeOPD1g==} engines: {node: '>=18'} - '@sentry-internal/feedback@10.45.0': - resolution: {integrity: sha512-vCSurazFVq7RUeYiM5X326jA5gOVrWYD6lYX2fbjBOMcyCEhDnveNxMT62zKkZDyNT/jyD194nz/cjntBUkyWA==} + '@sentry-internal/feedback@10.46.0': + resolution: {integrity: sha512-c4pI/z9nZCQXe9GYEw/hE/YTY9AxGBp8/wgKI+T8zylrN35SGHaXv63szzE1WbI8lacBY8lBF7rstq9bQVCaHw==} engines: {node: '>=18'} - '@sentry-internal/replay-canvas@10.45.0': - resolution: {integrity: sha512-nvq/AocdZTuD7y0KSiWi3gVaY0s5HOFy86mC/v1kDZmT/jsBAzN5LDkk/f1FvsWma1peqQmpUqxvhC+YIW294Q==} + '@sentry-internal/replay-canvas@10.46.0': + resolution: {integrity: sha512-ub314MWUsekVCuoH0/HJbbimlI24SkV745UW2pj9xRbxOAEf1wjkmIzxKrMDbTgJGuEunug02XZVdJFJUzOcDw==} engines: {node: '>=18'} - '@sentry-internal/replay@10.45.0': - resolution: {integrity: sha512-vjosRoGA1bzhVAEO1oce+CsRdd70quzBeo7WvYqpcUnoLe/Rv8qpOMqWX3j26z7XfFHMExWQNQeLxmtYOArvlw==} + '@sentry-internal/replay@10.46.0': + resolution: {integrity: sha512-JBsWeXG6bRbxBFK8GzWymWGOB9QE7Kl57BeF3jzgdHTuHSWZ2mRnAmb1K05T4LU+gVygk6yW0KmdC8Py9Qzg9A==} engines: {node: '>=18'} - '@sentry/browser@10.45.0': - resolution: {integrity: sha512-e/a8UMiQhqqv706McSIcG6XK+AoQf9INthi2pD+giZfNRTzXTdqHzUT5OIO5hg8Am6eF63nDJc+vrYNPhzs51Q==} + '@sentry/browser@10.46.0': + resolution: {integrity: sha512-80DmGlTk5Z2/OxVOzLNxwolMyouuAYKqG8KUcoyintZqHbF6kO1RulI610HmyUt3OagKeBCqt9S7w0VIfCRL+Q==} engines: {node: '>=18'} - '@sentry/core@10.45.0': - resolution: {integrity: sha512-s69UXxvefeQxuZ5nY7/THtTrIEvJxNVCp3ns4kwoCw1qMpgpvn/296WCKVmM7MiwnaAdzEKnAvLAwaxZc2nM7Q==} + '@sentry/core@10.46.0': + resolution: {integrity: sha512-N3fj4zqBQOhXliS1Ne9euqIKuciHCGOJfPGQLwBoW9DNz03jF+NB8+dUKtrJ79YLoftjVgf8nbgwtADK7NR+2Q==} engines: {node: '>=18'} - '@sentry/react@10.45.0': - resolution: {integrity: sha512-jLezuxi4BUIU3raKyAPR5xMbQG/nhwnWmKo5p11NCbLmWzkS+lxoyDTUB4B8TAKZLfdtdkKLOn1S0tFc8vbUHw==} + '@sentry/react@10.46.0': + resolution: {integrity: sha512-Rb1S+9OuUPVwsz7GWnQ6Kgf3azbsseUymIegg3JZHNcW/fM1nPpaljzTBnuineia113DH0pgMBcdrrZDLaosFQ==} engines: {node: '>=18'} peerDependencies: react: ^16.14.0 || 17.x || 18.x || 19.x @@ -2951,42 +3698,42 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@storybook/addon-docs@10.3.1': - resolution: {integrity: sha512-0FBhfMEg96QUmhdtks3rchktEEWF2hKcEsr3XluybBoBi4xAIw1vm+RJtL9Jm45ppTdg28LF7U+OeMx5LwkMzQ==} + '@storybook/addon-docs@10.3.3': + resolution: {integrity: sha512-trJQTpOtuOEuNv1Rn8X2Sopp5hSPpb0u0soEJ71BZAbxe4d2Y1d/1MYcxBdRKwncum6sCTsnxTpqQ/qvSJKlTQ==} peerDependencies: - storybook: ^10.3.1 + storybook: ^10.3.3 - '@storybook/addon-links@10.3.1': - resolution: {integrity: sha512-ooV8FU9PhcmSwpkSETZW6SYzVwQ0ui3DEp8gx5Kzf0JXAkESwxnzQVikxzHCLaP6KgYPb9gajN6jhin2KUGrhw==} + '@storybook/addon-links@10.3.3': + resolution: {integrity: sha512-tazBHlB+YbU62bde5DWsq0lnxZjcAsPB3YRUpN2hSMfAySsudRingyWrgu5KeOxXhJvKJj0ohjQvGcMx/wgQUA==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.3.1 + storybook: ^10.3.3 peerDependenciesMeta: react: optional: true - '@storybook/addon-onboarding@10.3.1': - resolution: {integrity: sha512-fXhkG0dPvsuwlOmK2eOmc0CYJXUeWV8hZWlnthkqGKrzUyqXx0YmM3VdnKwk0/OnOCp1zykDoMtnjnDqWW4saQ==} + '@storybook/addon-onboarding@10.3.3': + resolution: {integrity: sha512-HZiHfXdcLc29WkYFW+1VAMtJCeAZOOLRYPvs97woJUcZqW8yfWEJ9MWH+j++736SFAv2aqZWNmP47OdBJ/kMkw==} peerDependencies: - storybook: ^10.3.1 + storybook: ^10.3.3 - '@storybook/addon-themes@10.3.1': - resolution: {integrity: sha512-Y4ZCof3C+nsXvfhDmUvxt1klnZ6SPh1tLuDWo4eE8MUG1jQ2tixiIQX6Ups8fqfYCN8RgjcDDHnIyNZRZlgB2Q==} + '@storybook/addon-themes@10.3.3': + resolution: {integrity: sha512-6PgH1o7yNnWRVj4lAT1DNcX/eZXKgzjhfmzgWh3oFpPfDDvUzpFxx+MClM5f/ZieIbyQscxEuq8li7+e/F5VEQ==} peerDependencies: - storybook: ^10.3.1 + storybook: ^10.3.3 - '@storybook/builder-vite@10.3.1': - resolution: {integrity: sha512-8X3Mv6VxVaVHip51ZuTAjQv7jI3K4GxpgW0ZAhaLi8atSTHezu7hQOuISC1cHAwhMV0GhGHtCCKi33G9EGx5hw==} + '@storybook/builder-vite@10.3.3': + resolution: {integrity: sha512-awspKCTZvXyeV3KabL0id62mFbxR5u/5yyGQultwCiSb2/yVgBfip2MAqLyS850pvTiB6QFVM9deOyd2/G/bEA==} peerDependencies: - storybook: ^10.3.1 + storybook: ^10.3.3 vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - '@storybook/csf-plugin@10.3.1': - resolution: {integrity: sha512-P1WUSoyueV+ULpNeip4eIjjDvOXDBQI4gaq/s1PdAg1Szz/0GhDPu/CXuwukgkmyHaJP3aVR3pHPvSfeLfMCrA==} + '@storybook/csf-plugin@10.3.3': + resolution: {integrity: sha512-Utlh7zubm+4iOzBBfzLW4F4vD99UBtl2Do4edlzK2F7krQIcFvR2ontjAE8S1FQVLZAC3WHalCOS+Ch8zf3knA==} peerDependencies: esbuild: 0.27.2 rollup: 4.59.0 - storybook: ^10.3.1 + storybook: ^10.3.3 vite: '*' webpack: '*' peerDependenciesMeta: @@ -3008,40 +3755,40 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@storybook/nextjs-vite@10.3.1': - resolution: {integrity: sha512-//xqijMeZGYSagUMmuRZVW4pHYWqiQozEil2NM6HUseqc3bReFNqPpDAThCVGKAckIulVIIUZbF/4Lh9OYplOA==} + '@storybook/nextjs-vite@10.3.3': + resolution: {integrity: sha512-/OzOo0dSd0eFIAF9ft+ptwaXHa5Xj01cw3NXEtmPdODZXl0eiPmTvWYIJeP26UEPzI2FFSm4fK64ZZJluKpGOA==} peerDependencies: next: ^14.1.0 || ^15.0.0 || ^16.0.0 react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.3.1 + storybook: ^10.3.3 typescript: '*' vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - '@storybook/react-dom-shim@10.3.1': - resolution: {integrity: sha512-X337d639Bw9ej8vIi29bxgRsHcrFHhux1gMSmDifYjBRhTUXE3/OeDtoEl6ZV5Pgc5BAabUF5L2cl0mb428BYQ==} + '@storybook/react-dom-shim@10.3.3': + resolution: {integrity: sha512-lkhuh4G3UTreU9M3Iz5Dt32c6U+l/4XuvqLtbe1sDHENZH6aPj7y0b5FwnfHyvuTvYRhtbo29xZrF5Bp9kCC0w==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.3.1 + storybook: ^10.3.3 - '@storybook/react-vite@10.3.1': - resolution: {integrity: sha512-6ATC5oZKXtNFdyLR1DyJY9s6qDltFL/Dfew6loJK4bBqd5a46+wpNJebMBhBxdhHa9FDJS5tv2noNSO5kXc+Sw==} + '@storybook/react-vite@10.3.3': + resolution: {integrity: sha512-qHdlBe1hjqFAGXa8JL7bWTLbP/gDqXbWDm+SYCB646NHh5yvVDkZLwigP5Y+UL7M2ASfqFtosnroUK9tcCM2dw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.3.1 + storybook: ^10.3.3 vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - '@storybook/react@10.3.1': - resolution: {integrity: sha512-DoiOwfVG8VVIxA9JD3wz5lE30RTxwOnSHJJv4qdlCCiPIJWBGjxug9bqFxUZlqDkkbUzFLGDOBxYDp05Y66dbQ==} + '@storybook/react@10.3.3': + resolution: {integrity: sha512-cGG5TbR8Tdx9zwlpsWyBEfWrejm5iWdYF26EwIhwuKq9GFUTAVrQzo0Rs7Tqc3ZyVhRS/YfsRiWSEH+zmq2JiQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.3.1 + storybook: ^10.3.3 typescript: '>= 4.9.x' peerDependenciesMeta: typescript: @@ -3064,8 +3811,8 @@ packages: '@swc/helpers@0.5.15': resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} - '@swc/helpers@0.5.19': - resolution: {integrity: sha512-QamiFeIK3txNjgUTNppE6MiG3p7TdninpZu0E0PbqVh1a9FNLT2FRhisaa4NcaX52XVhA5l7Pk58Ft7Sqi/2sA==} + '@swc/helpers@0.5.20': + resolution: {integrity: sha512-2egEBHUMasdypIzrprsu8g+OEVd7Vp2MM3a2eVlM/cyFYto0nGz5BX5BTgh/ShZZI9ed+ozEq+Ngt+rgmUs8tw==} '@t3-oss/env-core@0.13.11': resolution: {integrity: sha512-sM7GYY+KL7H/Hl0BE0inWfk3nRHZOLhmVn7sHGxaZt9FAR6KqREXAE+6TqKfiavfXmpRxO/OZ2QgKRd+oiBYRQ==} @@ -3154,8 +3901,8 @@ packages: peerDependencies: solid-js: 1.9.11 - '@tanstack/eslint-plugin-query@5.95.0': - resolution: {integrity: sha512-XvEfgHyZoeGYGt0uOFwEbgkNMrRxoPt8Gy44cu3OwYFw6CU8uPAaUUiDJCqeyvYNNkuhnR4gWRn6vu5fcFSTUQ==} + '@tanstack/eslint-plugin-query@5.95.2': + resolution: {integrity: sha512-EYUFRaqjBep4EHMPpZR12sXP7Kr5qv9iDIlq93NfbhHwhITaW6Txu3ROO6dLFz5r84T8p+oZXBG77pa2Wuok7A==} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: ^5.4.0 @@ -3175,11 +3922,11 @@ packages: resolution: {integrity: sha512-y/xtNPNt/YeyoVxE/JCx+T7yjEzpezmbb+toK8DDD1P4m7Kzs5YR956+7OKexG3f8aXgC3rLZl7b1V+yNUSy5w==} engines: {node: '>=18'} - '@tanstack/query-core@5.95.0': - resolution: {integrity: sha512-H1/CWCe8tGL3YIVeo770Z6kPbt0B3M1d/iQXIIK1qlFiFt6G2neYdkHgLapOC8uMYNt9DmHjmGukEKgdMk1P+A==} + '@tanstack/query-core@5.95.2': + resolution: {integrity: sha512-o4T8vZHZET4Bib3jZ/tCW9/7080urD4c+0/AUaYVpIqOsr7y0reBc1oX3ttNaSW5mYyvZHctiQ/UOP2PfdmFEQ==} - '@tanstack/query-devtools@5.95.0': - resolution: {integrity: sha512-i8IzjIsZSE9y9XGndeVYeUusrZpKyhOnOPIzWKao8iAVzmk8ZesPe5URt02aLwC5A0Rg72N+vgqolXXCXm4fFg==} + '@tanstack/query-devtools@5.95.2': + resolution: {integrity: sha512-QfaoqBn9uAZ+ICkA8brd1EHj+qBF6glCFgt94U8XP5BT6ppSsDBI8IJ00BU+cAGjQzp6wcKJL2EmRYvxy0TWIg==} '@tanstack/react-devtools@0.10.0': resolution: {integrity: sha512-cUMzOQb1IHmkb8MsD0TrxHT8EL92Rx3G0Huq+IFkWeoaZPGlIiaIcGTpS5VvQDeI4BVUT+ZGt6CQTpx8oSTECg==} @@ -3204,19 +3951,19 @@ packages: '@tanstack/react-start': optional: true - '@tanstack/react-query-devtools@5.95.0': - resolution: {integrity: sha512-w4lYQTuyGM6l8C32UDIvxeodCrOwbw0JGSK6sQXYlF24CJnTcNmCxvfvrW2L3f3NObyvEQYcGTfjOr0Vw8jaWA==} + '@tanstack/react-query-devtools@5.95.2': + resolution: {integrity: sha512-AFQFmbznVkbtfpx8VJ2DylW17wWagQel/qLstVLkYmNRo2CmJt3SNej5hvl6EnEeljJIdC3BTB+W7HZtpsH+3g==} peerDependencies: - '@tanstack/react-query': ^5.95.0 + '@tanstack/react-query': ^5.95.2 react: ^18 || ^19 - '@tanstack/react-query@5.95.0': - resolution: {integrity: sha512-EMP8B+BK9zvnAemT8M/y3z/WO0NjZ7fIUY3T3wnHYK6AA3qK/k33i7tPgCXCejhX0cd4I6bJIXN2GmjrHjDBzg==} + '@tanstack/react-query@5.95.2': + resolution: {integrity: sha512-/wGkvLj/st5Ud1Q76KF1uFxScV7WeqN1slQx5280ycwAyYkIPGaRZAEgHxe3bjirSd5Zpwkj6zNcR4cqYni/ZA==} peerDependencies: react: ^18 || ^19 - '@tanstack/react-store@0.9.2': - resolution: {integrity: sha512-Vt5usJE5sHG/cMechQfmwvwne6ktGCELe89Lmvoxe3LKRoFrhPa8OCKWs0NliG8HTJElEIj7PLtaBQIcux5pAQ==} + '@tanstack/react-store@0.9.3': + resolution: {integrity: sha512-y2iHd/N9OkoQbFJLUX1T9vbc2O9tjH0pQRgTcx1/Nz4IlwLvkgpuglXUx+mXt0g5ZDFrEeDnONPqkbfxXJKwRg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -3227,12 +3974,16 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@tanstack/store@0.9.2': - resolution: {integrity: sha512-K013lUJEFJK2ofFQ/hZKJUmCnpcV00ebLyOyFOWQvyQHUOZp/iYO84BM6aOGiV81JzwbX0APTVmW8YI7yiG5oA==} + '@tanstack/store@0.9.3': + resolution: {integrity: sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw==} '@tanstack/virtual-core@3.13.23': resolution: {integrity: sha512-zSz2Z2HNyLjCplANTDyl3BcdQJc2k1+yyFoKhNRmCr7V7dY8o8q5m8uFTI1/Pg1kL+Hgrz6u3Xo6eFUB7l66cg==} + '@teppeis/multimaps@3.0.0': + resolution: {integrity: sha512-ID7fosbc50TbT0MK0EG12O+gAP3W3Aa/Pz4DaTtQtEvlc9Odaqi0de+xuZ7Li2GtK4HzEX7IuRWS/JmZLksR3Q==} + engines: {node: '>=14'} + '@testing-library/dom@10.4.1': resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} engines: {node: '>=18'} @@ -3409,8 +4160,8 @@ packages: '@types/d3@7.4.3': resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} - '@types/debug@4.1.12': - resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} @@ -3469,6 +4220,9 @@ packages: '@types/node@25.5.0': resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==} + '@types/normalize-package-data@2.4.4': + resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + '@types/papaparse@5.5.2': resolution: {integrity: sha512-gFnFp/JMzLHCwRf7tQHrNnfhN4eYBVYYI897CGX4MY1tzY9l2aLkVyx2IlKZ/SAqDbB3I1AOZW5gTMGGsqWliA==} @@ -3519,108 +4273,108 @@ packages: '@types/zen-observable@0.8.3': resolution: {integrity: sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw==} - '@typescript-eslint/eslint-plugin@8.57.1': - resolution: {integrity: sha512-Gn3aqnvNl4NGc6x3/Bqk1AOn0thyTU9bqDRhiRnUWezgvr2OnhYCWCgC8zXXRVqBsIL1pSDt7T9nJUe0oM0kDQ==} + '@typescript-eslint/eslint-plugin@8.57.2': + resolution: {integrity: sha512-NZZgp0Fm2IkD+La5PR81sd+g+8oS6JwJje+aRWsDocxHkjyRw0J5L5ZTlN3LI1LlOcGL7ph3eaIUmTXMIjLk0w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.57.1 + '@typescript-eslint/parser': ^8.57.2 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.57.1': - resolution: {integrity: sha512-k4eNDan0EIMTT/dUKc/g+rsJ6wcHYhNPdY19VoX/EOtaAG8DLtKCykhrUnuHPYvinn5jhAPgD2Qw9hXBwrahsw==} + '@typescript-eslint/parser@8.57.2': + resolution: {integrity: sha512-30ScMRHIAD33JJQkgfGW1t8CURZtjc2JpTrq5n2HFhOefbAhb7ucc7xJwdWcrEtqUIYJ73Nybpsggii6GtAHjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.57.1': - resolution: {integrity: sha512-vx1F37BRO1OftsYlmG9xay1TqnjNVlqALymwWVuYTdo18XuKxtBpCj1QlzNIEHlvlB27osvXFWptYiEWsVdYsg==} + '@typescript-eslint/project-service@8.57.2': + resolution: {integrity: sha512-FuH0wipFywXRTHf+bTTjNyuNQQsQC3qh/dYzaM4I4W0jrCqjCVuUh99+xd9KamUfmCGPvbO8NDngo/vsnNVqgw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/rule-tester@8.57.1': - resolution: {integrity: sha512-gk0q0rLa7a1uEB0iD2t1GZELK1z6HfudiKYeSVhjQ5gW5FdL0OcZ+8f09Lg7NbmHSBF3V+S9BDuw0qoCFkHR+w==} + '@typescript-eslint/rule-tester@8.57.2': + resolution: {integrity: sha512-cb5m0irr1449waTuYzGi4KD3SGUH3khL4ta/o9lzShvT7gnIwR5qVhU0VM0p966kCrtFId8hwmkvz1fOElsxTg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - '@typescript-eslint/scope-manager@8.57.1': - resolution: {integrity: sha512-hs/QcpCwlwT2L5S+3fT6gp0PabyGk4Q0Rv2doJXA0435/OpnSR3VRgvrp8Xdoc3UAYSg9cyUjTeFXZEPg/3OKg==} + '@typescript-eslint/scope-manager@8.57.2': + resolution: {integrity: sha512-snZKH+W4WbWkrBqj4gUNRIGb/jipDW3qMqVJ4C9rzdFc+wLwruxk+2a5D+uoFcKPAqyqEnSb4l2ULuZf95eSkw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.57.1': - resolution: {integrity: sha512-0lgOZB8cl19fHO4eI46YUx2EceQqhgkPSuCGLlGi79L2jwYY1cxeYc1Nae8Aw1xjgW3PKVDLlr3YJ6Bxx8HkWg==} + '@typescript-eslint/tsconfig-utils@8.57.2': + resolution: {integrity: sha512-3Lm5DSM+DCowsUOJC+YqHHnKEfFh5CoGkj5Z31NQSNF4l5wdOwqGn99wmwN/LImhfY3KJnmordBq/4+VDe2eKw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.57.1': - resolution: {integrity: sha512-+Bwwm0ScukFdyoJsh2u6pp4S9ktegF98pYUU0hkphOOqdMB+1sNQhIz8y5E9+4pOioZijrkfNO/HUJVAFFfPKA==} + '@typescript-eslint/type-utils@8.57.2': + resolution: {integrity: sha512-Co6ZCShm6kIbAM/s+oYVpKFfW7LBc6FXoPXjTRQ449PPNBY8U0KZXuevz5IFuuUj2H9ss40atTaf9dlGLzbWZg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.57.1': - resolution: {integrity: sha512-S29BOBPJSFUiblEl6RzPPjJt6w25A6XsBqRVDt53tA/tlL8q7ceQNZHTjPeONt/3S7KRI4quk+yP9jK2WjBiPQ==} + '@typescript-eslint/types@8.57.2': + resolution: {integrity: sha512-/iZM6FnM4tnx9csuTxspMW4BOSegshwX5oBDznJ7S4WggL7Vczz5d2W11ecc4vRrQMQHXRSxzrCsyG5EsPPTbA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.57.1': - resolution: {integrity: sha512-ybe2hS9G6pXpqGtPli9Gx9quNV0TWLOmh58ADlmZe9DguLq0tiAKVjirSbtM1szG6+QH6rVXyU6GTLQbWnMY+g==} + '@typescript-eslint/typescript-estree@8.57.2': + resolution: {integrity: sha512-2MKM+I6g8tJxfSmFKOnHv2t8Sk3T6rF20A1Puk0svLK+uVapDZB/4pfAeB7nE83uAZrU6OxW+HmOd5wHVdXwXA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.57.1': - resolution: {integrity: sha512-XUNSJ/lEVFttPMMoDVA2r2bwrl8/oPx8cURtczkSEswY5T3AeLmCy+EKWQNdL4u0MmAHOjcWrqJp2cdvgjn8dQ==} + '@typescript-eslint/utils@8.57.2': + resolution: {integrity: sha512-krRIbvPK1ju1WBKIefiX+bngPs+odIQUtR7kymzPfo1POVw3jlF+nLkmexdSSd4UCbDcQn+wMBATOOmpBbqgKg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@8.57.1': - resolution: {integrity: sha512-YWnmJkXbofiz9KbnbbwuA2rpGkFPLbAIetcCNO6mJ8gdhdZ/v7WDXsoGFAJuM6ikUFKTlSQnjWnVO4ux+UzS6A==} + '@typescript-eslint/visitor-keys@8.57.2': + resolution: {integrity: sha512-zhahknjobV2FiD6Ee9iLbS7OV9zi10rG26odsQdfBO/hjSzUQbkIYgda+iNKK1zNiW2ey+Lf8MU5btN17V3dUw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260322.1': - resolution: {integrity: sha512-5wSilxwLGX5fMKJgsUkCBwOfW9GMG3WF5j77CVBOdFI7miFaR3JQaPzTA+uyHDMNIIeSDo1KtV77GT48Y/d0Xg==} + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260329.1': + resolution: {integrity: sha512-zS1thDk7luD82nXVwvMd97F7FgxAE6jGtSmnHeXdaQ+6hJQcQLOVkfUdaehhdodqKDapWA2jEURxQAYjDGvv3g==} cpu: [arm64] os: [darwin] - '@typescript/native-preview-darwin-x64@7.0.0-dev.20260322.1': - resolution: {integrity: sha512-G806SrfxkYNAgZ9Xk53+OvbmIg9iD5hjaiD2QhDQL2aZjzy10D4MhcdaZEOoMfw0OI/PoJPYOiPD+9/x2kw3Lg==} + '@typescript/native-preview-darwin-x64@7.0.0-dev.20260329.1': + resolution: {integrity: sha512-3IJ2qmpjQ1OXpZNUhJRjF1+SbDuqGC14Ug8DjWJlPBp06isi1fcJph90f5qW//FxEsNnJPYRcNwpP0A2RbTASg==} cpu: [x64] os: [darwin] - '@typescript/native-preview-linux-arm64@7.0.0-dev.20260322.1': - resolution: {integrity: sha512-+FyomEEt3K8TBO//n3Ijr61SDM2F7cxZCVqGt+Wk3rLcOCQ2i+8+p64gdsZCmImy3CyP0hBnxPydEbyNkZLtvg==} + '@typescript/native-preview-linux-arm64@7.0.0-dev.20260329.1': + resolution: {integrity: sha512-gQb6SjB5JlUKDaDuz6mv/m+/OBWVDlcjHINFOykBZZYZtgxBx6nEDjLrT8TiJRjmHEG6hSbv+yisUL9IThWycA==} cpu: [arm64] os: [linux] - '@typescript/native-preview-linux-arm@7.0.0-dev.20260322.1': - resolution: {integrity: sha512-0a12pp19ELiNHMqTglfQQQNMsxvtzpjAa4qf12oMJoGyy+UnguKEmaaaCHdp75KvBXGDzlssfDAdiy+NirN19A==} + '@typescript/native-preview-linux-arm@7.0.0-dev.20260329.1': + resolution: {integrity: sha512-WKSSJrH611DFFAg6YCkgbnkdy0a4RRpzvDpNXtPzLTbMYC5oJdq3Dpvncx5nrJvGh4J4yvzXoMxraGPyygqGLw==} cpu: [arm] os: [linux] - '@typescript/native-preview-linux-x64@7.0.0-dev.20260322.1': - resolution: {integrity: sha512-MviQe5x4WqQGv/Vhu4hcv2A0qTW/BTaZPbOLYCtvhuovNFO6D++ZmJAbHvA0h/bJEaNTgxKZdZPHMpCfSEKfjA==} + '@typescript/native-preview-linux-x64@7.0.0-dev.20260329.1': + resolution: {integrity: sha512-kg4r+ssxoEWruBynUg9bFMdcMpo5NupzAPqNBlV8uWbmYGZjaPLonFWAi9ZZMiVJY/x5ZQ9GBl6xskwLdd3PJQ==} cpu: [x64] os: [linux] - '@typescript/native-preview-win32-arm64@7.0.0-dev.20260322.1': - resolution: {integrity: sha512-ibnMaXDJPSgMXKC61NHiFlww/xjAEINgc1mcn2ntTfuGHwduU4P9Bi038TxXg95Wmu3v6xIPIorXXsBOdE+p3Q==} + '@typescript/native-preview-win32-arm64@7.0.0-dev.20260329.1': + resolution: {integrity: sha512-Qi4lddVxl5MG7Tk67gYhCFnoqqLGd4TvaI8RN4qHFjt3GV8s6c+0cQGsJXJnVgMx27qbyDTdsyAa2pvb42rYcQ==} cpu: [arm64] os: [win32] - '@typescript/native-preview-win32-x64@7.0.0-dev.20260322.1': - resolution: {integrity: sha512-O+r1RToWBbGkK7NXC7DpraLObSWyxvSqRiSfr/BlZ351Cdq1q3121zCGzVtqERGeRtVoEMRrzS5ITOd6On/pCw==} + '@typescript/native-preview-win32-x64@7.0.0-dev.20260329.1': + resolution: {integrity: sha512-+k5+usuB8HZ6Xc+enLdb95ZJd25bQqsnI1zXxfRCHP+RS9mxs70Mi9ezQz3lKOLZFFXShSH7iW9iulm8KwVzCQ==} cpu: [x64] os: [win32] - '@typescript/native-preview@7.0.0-dev.20260322.1': - resolution: {integrity: sha512-CmzQTKvesYHmz3g92G+XPDis25ocvHqa/gK8m98w+bML99KJLEWQKVlvkLrYA85JiJEK+XBIiz+6lCgUqRkWXA==} + '@typescript/native-preview@7.0.0-dev.20260329.1': + resolution: {integrity: sha512-v5lJ0TgSt2m9yVk2xoj9+NH/gTDeWTLaWGPx6MJsUKOYd6bmCJhHbMcWmb8d/zlfhE9ffpixUKYj62CdYfriqA==} hasBin: true '@ungap/structured-clone@1.3.0': @@ -3651,6 +4405,19 @@ packages: resolution: {integrity: sha512-hBcWIOppZV14bi+eAmCZj8Elj8hVSUZJTpf1lgGBhVD85pervzQ1poM/qYfFUlPraYSZYP+ASg6To5BwYmUSGQ==} engines: {node: '>=16'} + '@vitejs/devtools-kit@0.1.11': + resolution: {integrity: sha512-ZmBr54Nk8IwdbNCBNtOkQ3WcskWcL55ndfiB0UM8eTZ0ZoNwzPTCHiHgk/RnbhviXiB0kTowyTTYp4RfqGEWUQ==} + peerDependencies: + vite: '*' + + '@vitejs/devtools-rpc@0.1.11': + resolution: {integrity: sha512-APo34qbV05bNJB//Jmn4QLDrCU1CQuFvYbQdqvvyCKjxwWuoHhGobqzgoRS5V23tn8Sbliz7/Fyhfh+7C0LtKA==} + peerDependencies: + ws: '*' + peerDependenciesMeta: + ws: + optional: true + '@vitejs/plugin-react@6.0.1': resolution: {integrity: sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3675,23 +4442,26 @@ packages: react-server-dom-webpack: optional: true - '@vitest/coverage-v8@4.1.0': - resolution: {integrity: sha512-nDWulKeik2bL2Va/Wl4x7DLuTKAXa906iRFooIRPR+huHkcvp9QDkPQ2RJdmjOFrqOqvNfoSQLF68deE3xC3CQ==} + '@vitest/coverage-v8@4.1.2': + resolution: {integrity: sha512-sPK//PHO+kAkScb8XITeB1bf7fsk85Km7+rt4eeuRR3VS1/crD47cmV5wicisJmjNdfeokTZwjMk4Mj2d58Mgg==} peerDependencies: - '@vitest/browser': 4.1.0 - vitest: 4.1.0 + '@vitest/browser': 4.1.2 + vitest: 4.1.2 peerDependenciesMeta: '@vitest/browser': optional: true - '@vitest/eslint-plugin@1.6.12': - resolution: {integrity: sha512-4kI47BJNFE+EQ5bmPbHzBF+ibNzx2Fj0Jo9xhWsTPxMddlHwIWl6YAxagefh461hrwx/W0QwBZpxGS404kBXyg==} + '@vitest/eslint-plugin@1.6.13': + resolution: {integrity: sha512-ui7JGWBoQpS5NKKW0FDb1eTuFEZ5EupEv2Psemuyfba7DfA5K52SeDLelt6P4pQJJ/4UGkker/BgMk/KrjH3WQ==} engines: {node: '>=18'} peerDependencies: + '@typescript-eslint/eslint-plugin': '*' eslint: '>=8.57.0' typescript: '>=5.0.0' vitest: '*' peerDependenciesMeta: + '@typescript-eslint/eslint-plugin': + optional: true typescript: optional: true vitest: @@ -3703,8 +4473,8 @@ packages: '@vitest/pretty-format@3.2.4': resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} - '@vitest/pretty-format@4.1.0': - resolution: {integrity: sha512-3RZLZlh88Ib0J7NQTRATfc/3ZPOnSUn2uDBUoGNn5T36+bALixmzphN26OUD3LRXWkJu4H0s5vvUeqBiw+kS0A==} + '@vitest/pretty-format@4.1.2': + resolution: {integrity: sha512-dwQga8aejqeuB+TvXCMzSQemvV9hNEtDDpgUKDzOmNQayl2OG241PSWeJwKRH3CiC+sESrmoFd49rfnq7T4RnA==} '@vitest/spy@3.2.4': resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} @@ -3712,11 +4482,11 @@ packages: '@vitest/utils@3.2.4': resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} - '@vitest/utils@4.1.0': - resolution: {integrity: sha512-XfPXT6a8TZY3dcGY8EdwsBulFCIw+BeeX0RZn2x/BtiY/75YGh8FeWGG8QISN/WhaqSrE2OrlDgtF8q5uhOTmw==} + '@vitest/utils@4.1.2': + resolution: {integrity: sha512-xw2/TiX82lQHA06cgbqRKFb5lCAy3axQ4H4SoUFhUsg+wztiet+co86IAMDtF6Vm1hc7J6j09oh/rgDn+JdKIQ==} - '@voidzero-dev/vite-plus-core@0.1.13': - resolution: {integrity: sha512-72dAIYgGrrmh4ap5Tbvzo0EYCrmVRoPQjz3NERpZ34CWCjFB8+WAyBkxG631Jz9/qC1TR/ZThjOKbdYXQ5z9Aw==} + '@voidzero-dev/vite-plus-core@0.1.14': + resolution: {integrity: sha512-CCWzdkfW0fo0cQNlIsYp5fOuH2IwKuPZEb2UY2Z8gXcp5pG74A82H2Pthj0heAuvYTAnfT7kEC6zM+RbiBgQbg==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: '@arethetypeswrong/core': ^0.18.1 @@ -3775,43 +4545,57 @@ packages: yaml: optional: true - '@voidzero-dev/vite-plus-darwin-arm64@0.1.13': - resolution: {integrity: sha512-GgQ5dW1VR/Vuc8cRDsdpLMdly2rHiq8ihNKIh1eu8hR85bDjDxE4DSXeadCDMWC0bHTjQiR1HqApzjoPYsVF/w==} + '@voidzero-dev/vite-plus-darwin-arm64@0.1.14': + resolution: {integrity: sha512-q2ESUSbapwsxVRe/KevKATahNRraoX5nti3HT9S3266OHT5sMroBY14jaxTv74ekjQc9E6EPhyLGQWuWQuuBRw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@voidzero-dev/vite-plus-darwin-x64@0.1.13': - resolution: {integrity: sha512-X4ZXbjIhNg5jxEkPVn7kJZEVIvNiOCWztrY67nHD94yqsWLy2Hs7yo+DhrpEQihsnlZ1hRRtwDirdCncvEulUg==} + '@voidzero-dev/vite-plus-darwin-x64@0.1.14': + resolution: {integrity: sha512-UpcDZc9G99E/4HDRoobvYHxMvFOG5uv3RwEcq0HF70u4DsnEMl1z8RaJLeWV7a09LGwj9Q+YWC3Z4INWnTLs8g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@voidzero-dev/vite-plus-linux-arm64-gnu@0.1.13': - resolution: {integrity: sha512-oPtwztuF1cierDWA68beais5mwm6dXsmOOvccn6ZHjNpKXig84LvgIoY4bMazA3Z0SE9nWqxmP0kePiO5SoiuA==} + '@voidzero-dev/vite-plus-linux-arm64-gnu@0.1.14': + resolution: {integrity: sha512-GIjn35RABUEDB9gHD26nRq7T72Te+Qy2+NIzogwEaUE728PvPkatF5gMCeF4sigCoc8c4qxDwsG+A2A2LYGnDg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@voidzero-dev/vite-plus-linux-x64-gnu@0.1.13': - resolution: {integrity: sha512-RgNHwTXrnYjt60K0g083VxOjaJNXHvZXViBQd/oC7RUwGUvxuHkraq/4mWaI69Pffx2KpyykxgCrtmhWq5Tgjg==} + '@voidzero-dev/vite-plus-linux-arm64-musl@0.1.14': + resolution: {integrity: sha512-qo2RToGirG0XCcxZ2AEOuonLM256z6dNbJzDDIo5gWYA+cIKigFQJbkPyr25zsT1tsP2aY0OTxt2038XbVlRkQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@voidzero-dev/vite-plus-linux-x64-gnu@0.1.14': + resolution: {integrity: sha512-BsMWKZfdfGcYLxxLyaePpg6NW54xqzzcfq8sFUwKfwby0kgOKQ4WymUXyBvO9nnBb0ZPsJQrV0sx+Onac/LTaw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@voidzero-dev/vite-plus-test@0.1.13': - resolution: {integrity: sha512-P3n9adJZsaIUGlgbzyT2YvlA1yr2lCYhNjrZsiLAKMVyQzk2D++ptTre3SnYf9j1TQeMP1VonRXGjtZhTf8wHg==} + '@voidzero-dev/vite-plus-linux-x64-musl@0.1.14': + resolution: {integrity: sha512-mOrEpj7ntW9RopGbcOYG/L0pOs0qHzUG4Vz7NXbuf4dbOSlY4JjyoMOIWxjKQORQht02Hzuf8YrMGNwa6AjVSQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@voidzero-dev/vite-plus-test@0.1.14': + resolution: {integrity: sha512-rjF+qpYD+5+THOJZ3gbE3+cxsk5sW7nJ0ODK7y6ZKeS4amREUMedEDYykzKBwR7OZDC/WwE90A0iLWCr6qAXhA==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/ui': 4.1.0 + '@vitest/ui': 4.1.1 happy-dom: '*' jsdom: '*' - vite: ^6.0.0 || ^7.0.0 || ^8.0.0-0 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: '@edge-runtime/vm': optional: true @@ -3826,14 +4610,14 @@ packages: jsdom: optional: true - '@voidzero-dev/vite-plus-win32-arm64-msvc@0.1.13': - resolution: {integrity: sha512-+oygKTgglu0HkA4y9kFs8/BbHFsvShkHuL+8bK++Zek3x2ArKHRjCMgcYUXyj6nYufMIL2ba/Und7aHUK2ZGiQ==} + '@voidzero-dev/vite-plus-win32-arm64-msvc@0.1.14': + resolution: {integrity: sha512-7iC+Ig+8D/zACy0IJf7w/vQ7duTjux9Ttmm3KOBdVWH4dl3JihydA7+SQVMhz71a4WiqJ6nPidoG8D6hUP4MVQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@voidzero-dev/vite-plus-win32-x64-msvc@0.1.13': - resolution: {integrity: sha512-+7zTnX/HqYCaBKmSLHjmCXQBRSSIJ6EFry55+4C0R4AMyayfn9w3LL0/NuVeCNkG69u3FnkRuwkqdWpzxztoHQ==} + '@voidzero-dev/vite-plus-win32-x64-msvc@0.1.14': + resolution: {integrity: sha512-yRJ/8yAYFluNHx0Ej6Kevx65MIeM3wFKklnxosVZRlz2ZRL1Ea1Qh3tWATr3Ipk1ciRxBv8KJgp6zXqjxtZSoQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -3850,20 +4634,20 @@ packages: '@volar/typescript@2.4.28': resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==} - '@vue/compiler-core@3.5.30': - resolution: {integrity: sha512-s3DfdZkcu/qExZ+td75015ljzHc6vE+30cFMGRPROYjqkroYI5NV2X1yAMX9UeyBNWB9MxCfPcsjpLS11nzkkw==} + '@vue/compiler-core@3.5.31': + resolution: {integrity: sha512-k/ueL14aNIEy5Onf0OVzR8kiqF/WThgLdFhxwa4e/KF/0qe38IwIdofoSWBTvvxQOesaz6riAFAUaYjoF9fLLQ==} - '@vue/compiler-dom@3.5.30': - resolution: {integrity: sha512-eCFYESUEVYHhiMuK4SQTldO3RYxyMR/UQL4KdGD1Yrkfdx4m/HYuZ9jSfPdA+nWJY34VWndiYdW/wZXyiPEB9g==} + '@vue/compiler-dom@3.5.31': + resolution: {integrity: sha512-BMY/ozS/xxjYqRFL+tKdRpATJYDTTgWSo0+AJvJNg4ig+Hgb0dOsHPXvloHQ5hmlivUqw1Yt2pPIqp4e0v1GUw==} - '@vue/compiler-sfc@3.5.30': - resolution: {integrity: sha512-LqmFPDn89dtU9vI3wHJnwaV6GfTRD87AjWpTWpyrdVOObVtjIuSeZr181z5C4PmVx/V3j2p+0f7edFKGRMpQ5A==} + '@vue/compiler-sfc@3.5.31': + resolution: {integrity: sha512-M8wpPgR9UJ8MiRGjppvx9uWJfLV7A/T+/rL8s/y3QG3u0c2/YZgff3d6SuimKRIhcYnWg5fTfDMlz2E6seUW8Q==} - '@vue/compiler-ssr@3.5.30': - resolution: {integrity: sha512-NsYK6OMTnx109PSL2IAyf62JP6EUdk4Dmj6AkWcJGBvN0dQoMYtVekAmdqgTtWQgEJo+Okstbf/1p7qZr5H+bA==} + '@vue/compiler-ssr@3.5.31': + resolution: {integrity: sha512-h0xIMxrt/LHOvJKMri+vdYT92BrK3HFLtDqq9Pr/lVVfE4IyKZKvWf0vJFW10Yr6nX02OR4MkJwI0c1HDa1hog==} - '@vue/shared@3.5.30': - resolution: {integrity: sha512-YXgQ7JjaO18NeK2K9VTbDHaFy62WrObMa6XERNfNOkAhD1F1oDSf3ZJ7K6GqabZ0BvSDHajp8qfS5Sa2I9n8uQ==} + '@vue/shared@3.5.31': + resolution: {integrity: sha512-nBxuiuS9Lj5bPkPbWogPUnjxxWpkRniX7e5UBQDWl6Fsf4roq9wwV+cR7ezQ4zXswNvPIlsdj1slcLB7XCsRAw==} '@webassemblyjs/ast@1.14.1': resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} @@ -3942,8 +4726,8 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - agentation@2.3.3: - resolution: {integrity: sha512-AUZgFCdBQ/nAohlFsHByM9S2Dp7ECMNqVjlOke4hv/90v+wTiwrGladEkgWS60RDQp+CJ5p97meeCthYgTFlKQ==} + agentation@3.0.2: + resolution: {integrity: sha512-iGzBxFVTuZEIKzLY6AExSLAQH6i6SwxV4pAu7v7m3X6bInZ7qlZXAwrEqyc4+EfP4gM7z2RXBF6SF4DeH0f2lA==} peerDependencies: react: '>=18.0.0' react-dom: '>=18.0.0' @@ -3953,8 +4737,8 @@ packages: react-dom: optional: true - ahooks@3.9.6: - resolution: {integrity: sha512-Mr7f05swd5SmKlR9SZo5U6M0LsL4ErweLzpdgXjA1JPmnZ78Vr6wzx0jUtvoxrcqGKYnX0Yjc02iEASVxHFPjQ==} + ahooks@3.9.7: + resolution: {integrity: sha512-S0lvzhbdlhK36RFBkGv+RbOM/dbbweym+BIHM/bwwuWVSVN5TuVErHPMWo4w0t1NDYg5KPp2iEf7Y7E5LASYiw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -3982,6 +4766,10 @@ packages: resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} engines: {node: '>=18'} + ansi-regex@4.1.1: + resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==} + engines: {node: '>=6'} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -4034,6 +4822,9 @@ packages: resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} engines: {node: '>= 0.4'} + assertion-error-formatter@3.0.0: + resolution: {integrity: sha512-6YyAVLrEze0kQ7CmJfUgrLHb+Y7XghmL2Ie7ijVa2Y9ynP3LV+VDiwFk62Dn0qtqbmY0BT0ss6p1xxpiF2PYbQ==} + assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -4052,6 +4843,9 @@ packages: async@3.2.6: resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + autoprefixer@10.4.27: resolution: {integrity: sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==} engines: {node: ^10 || ^12 || >=14} @@ -4059,6 +4853,9 @@ packages: peerDependencies: postcss: ^8.1.0 + axios@1.14.0: + resolution: {integrity: sha512-3Y8yrqLSwjuzpXuZ0oIYZ/XGgLwUIBU3uLvbcpb0pidD9ctpShJd43KSlEEkVQg6DS0G9NKyzOvBfUtDKEyHvQ==} + bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} @@ -4080,14 +4877,11 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.10.8: - resolution: {integrity: sha512-PCLz/LXGBsNTErbtB6i5u4eLpHeMfi93aUv5duMmj6caNu6IphS4q6UevDnL36sZQv9lrP11dbPKGMaXPwMKfQ==} + baseline-browser-mapping@2.10.12: + resolution: {integrity: sha512-qyq26DxfY4awP2gIRXhhLWfwzwI+N5Nxk6iQi8EFizIaWIjqicQTE4sLnZZVdeKPRcVNoJOkkpfzoIYuvCKaIQ==} engines: {node: '>=6.0.0'} hasBin: true - bidi-js@1.0.3: - resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} - binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} @@ -4095,8 +4889,8 @@ packages: birecord@0.1.1: resolution: {integrity: sha512-VUpsf/qykW0heRlC8LooCq28Kxn3mAqKohhDG/49rrsQ1dT1CXyj/pgXS+5BSRzFTR/3DyIBOqQOrGyZOh71Aw==} - birpc@2.9.0: - resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==} + birpc@4.0.0: + resolution: {integrity: sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==} bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -4107,8 +4901,8 @@ packages: brace-expansion@2.0.2: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} - brace-expansion@5.0.4: - resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==} + brace-expansion@5.0.5: + resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} engines: {node: 18 || 20 || >=22} braces@3.0.3: @@ -4141,14 +4935,28 @@ packages: resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} engines: {node: '>=18'} + bundle-require@5.1.0: + resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + esbuild: 0.27.2 + bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + cac@7.0.0: resolution: {integrity: sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==} engines: {node: '>=20.19.0'} + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -4160,13 +4968,16 @@ packages: camelize@1.0.1: resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==} - caniuse-lite@1.0.30001780: - resolution: {integrity: sha512-llngX0E7nQci5BPJDqoZSbuZ5Bcs9F5db7EtgfwBerX9XGtkkiO4NwfDDIRzHTTwcYC8vC7bmeUEPGrKlR/TkQ==} + caniuse-lite@1.0.30001781: + resolution: {integrity: sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==} canvas@3.2.2: resolution: {integrity: sha512-duEt4h1HHu9sJZyVKfLRXR6tsKPY7cEELzxSRJkwddOXYvQT3P/+es98SV384JA0zMOZ5s+9gatnGfM6sL4Drg==} engines: {node: ^18.12.0 || >= 20.9.0} + capital-case@1.0.4: + resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==} + ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -4260,6 +5071,9 @@ packages: resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} engines: {node: '>=8'} + class-transformer@0.5.1: + resolution: {integrity: sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==} + class-variance-authority@0.7.1: resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} @@ -4277,6 +5091,10 @@ packages: resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} engines: {node: '>=18'} + cli-table3@0.6.5: + resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} + engines: {node: 10.* || >= 12.*} + cli-truncate@5.2.0: resolution: {integrity: sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==} engines: {node: '>=20'} @@ -4310,12 +5128,24 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + comma-separated-tokens@1.0.8: resolution: {integrity: sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==} comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + commander@14.0.0: + resolution: {integrity: sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==} + engines: {node: '>=20'} + + commander@14.0.2: + resolution: {integrity: sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==} + engines: {node: '>=20'} + commander@14.0.3: resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} engines: {node: '>=20'} @@ -4339,6 +5169,10 @@ packages: resolution: {integrity: sha512-aRDkn3uyIlCFfk5NUA+VdwMmMsh8JGhc4hapfV4yxymHGQ3BVskMQfoXGpCo5IoBuQ9tS5iiVKhCpTcB4pW4qw==} engines: {node: '>= 12.0.0'} + comment-parser@1.4.6: + resolution: {integrity: sha512-ObxuY6vnbWTN6Od72xfwN9DbzC7Y2vv8u1Soi9ahRKL37gb6y1qk6/dgjs+3JWuXJHWvsg3BXIwzd/rkmAwavg==} + engines: {node: '>= 12.0.0'} + compare-versions@6.1.1: resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==} @@ -4348,6 +5182,10 @@ packages: confbox@0.2.4: resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -4399,10 +5237,6 @@ packages: resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} - css-tree@3.2.1: - resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} - 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'} @@ -4581,10 +5415,6 @@ packages: dagre-d3-es@7.0.14: resolution: {integrity: sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==} - data-urls@7.0.0: - resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - dayjs@1.11.20: resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==} @@ -4633,8 +5463,12 @@ packages: defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} - delaunator@5.0.1: - resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} + delaunator@5.1.0: + resolution: {integrity: sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} @@ -4660,6 +5494,10 @@ packages: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + diff@4.0.4: + resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==} + engines: {node: '>=0.3.1'} + dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} @@ -4697,6 +5535,10 @@ packages: resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} engines: {node: '>=12'} + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + echarts-for-react@3.0.6: resolution: {integrity: sha512-4zqLgTGWS3JvkQDXjzkR1k1CHRdpd6by0988TWMJgnvDytegWLbeP/VNZmMa+0VJx2eD7Y632bi2JquXDgiGJg==} peerDependencies: @@ -4706,8 +5548,8 @@ packages: echarts@6.0.0: resolution: {integrity: sha512-Tte/grDQRiETQP4xz3iZWSvoHrkCQtwqd6hs+mifXcjrCuo2iKWbajFObuLJVBlDIJlOzgQPd1hsaKt/3+OMkQ==} - electron-to-chromium@1.5.313: - resolution: {integrity: sha512-QBMrTWEf00GXZmJyx2lbYD45jpI3TUFnNIzJ5BBc8piGUDwMPa1GV6HJWTZVvY/eiN3fSopl7NRbgGp9sZ9LTA==} + electron-to-chromium@1.5.328: + resolution: {integrity: sha512-QNQ5l45DzYytThO21403XN3FvK0hOkWDG8viNf6jqS42msJ8I4tGDSpBCgvDRRPnkffafiwAym2X2eHeGD2V0w==} elkjs@0.11.1: resolution: {integrity: sha512-zxxR9k+rx5ktMwT/FwyLdPCrq7xN6e4VGGHH8hA01vVYKjTFik7nHOxBnAYtrgYUB1RpAiLvA1/U2YraWxyKKg==} @@ -4770,12 +5612,31 @@ packages: error-stack-parser-es@1.0.5: resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} + error-stack-parser@2.1.4: + resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} es-module-lexer@2.0.0: resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + es-toolkit@1.45.1: resolution: {integrity: sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw==} @@ -4815,8 +5676,8 @@ packages: peerDependencies: eslint: '>=6.0.0' - eslint-config-flat-gitignore@2.2.1: - resolution: {integrity: sha512-wA5EqN0era7/7Gt5Botlsfin/UNY0etJSEeBgbUlFLFrBi47rAN//+39fI7fpYcl8RENutlFtvp/zRa/M/pZNg==} + eslint-config-flat-gitignore@2.3.0: + resolution: {integrity: sha512-bg4ZLGgoARg1naWfsINUUb/52Ksw/K22K+T16D38Y8v+/sGwwIYrGvH/JBjOin+RQtxxC9tzNNiy4shnGtGyyQ==} peerDependencies: eslint: ^9.5.0 || ^10.0.0 @@ -4896,8 +5757,8 @@ packages: peerDependencies: eslint: '>=9.0.0' - eslint-plugin-jsdoc@62.8.0: - resolution: {integrity: sha512-hu3r9/6JBmPG6wTcqtYzgZAnjEG2eqRUATfkFscokESg1VDxZM21ZaMire0KjeMwfj+SXvgB4Rvh5LBuesj92w==} + eslint-plugin-jsdoc@62.8.1: + resolution: {integrity: sha512-e9358PdHgvcMF98foNd3L7hVCw70Lt+YcSL7JzlJebB8eT5oRJtW6bHMQKoAwJtw6q0q0w/fRIr2kwnHdFDI6A==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 @@ -4996,11 +5857,11 @@ packages: peerDependencies: eslint: ^8.0.0 || ^9.0.0 || ^10.0.0 - eslint-plugin-storybook@10.3.1: - resolution: {integrity: sha512-zWE8cQTJo2Wuw6I/Ag73rP5rLbaypm5p3G2BV74Y7Lc8NwNclAwNi5u+yl9qBQLW2aSXotDW9fjj3Mx+GeEgfA==} + eslint-plugin-storybook@10.3.3: + resolution: {integrity: sha512-jo8wZvKaJlxxrNvf4hCsROJP3CdlpaLiYewAs5Ww+PJxCrLelIi5XVHWOAgBvvr3H9WDKvUw8xuvqPYqAlpkFg==} peerDependencies: eslint: '>=8' - storybook: ^10.3.1 + storybook: ^10.3.3 eslint-plugin-toml@1.3.1: resolution: {integrity: sha512-1l00fBP03HIt9IPV7ZxBi7x0y0NMdEZmakL1jBD6N/FoKBvfKxPw5S8XkmzBecOnFBTn5Z8sNJtL5vdf9cpRMQ==} @@ -5222,6 +6083,10 @@ packages: fflate@0.7.4: resolution: {integrity: sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==} + figures@3.2.0: + resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} + engines: {node: '>=8'} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -5242,6 +6107,9 @@ packages: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} + fix-dts-default-cjs-exports@1.0.1: + resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} + flat-cache@4.0.1: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} @@ -5249,6 +6117,19 @@ packages: flatted@3.4.2: resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} + follow-redirects@1.15.11: + resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} + format@0.2.2: resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} engines: {node: '>=0.4.x'} @@ -5275,11 +6156,19 @@ packages: fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + functional-red-black-tree@1.0.1: resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} @@ -5294,10 +6183,18 @@ packages: resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} engines: {node: '>=18'} + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + get-nonce@1.0.1: resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} engines: {node: '>=6'} + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + get-stream@5.2.0: resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} engines: {node: '>=8'} @@ -5326,6 +6223,10 @@ packages: resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} engines: {node: 18 || 20 || >=22} + global-dirs@3.0.1: + resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==} + engines: {node: '>=10'} + globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} @@ -5350,6 +6251,10 @@ packages: peerDependencies: csstype: ^3.0.10 + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -5360,10 +6265,22 @@ packages: resolution: {integrity: sha512-Tz23LR9T9jOGVZm2x1EPdXqwA37G/owYMxRwU0E4miurAtFsPMQ1d2Jc2okUaSjZqAFz2oEn3FLXC5a0a+siyA==} engines: {node: '>=20.0.0'} + has-ansi@4.0.1: + resolution: {integrity: sha512-Qr4RtTm30xvEdqUXbSBVWDu+PrTokJOwe/FU+VdfJPk+MXAPoeOzKpRyrDTnZIJwAkQ4oBLTU53nu0HrkF/Z2A==} + engines: {node: '>=8'} + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + hast-util-from-dom@5.0.1: resolution: {integrity: sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==} @@ -5428,13 +6345,13 @@ packages: highlightjs-vue@1.0.0: resolution: {integrity: sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==} - hono@4.12.8: - resolution: {integrity: sha512-VJCEvtrezO1IAR+kqEYnxUOoStaQPGrCmX3j4wDTNOcD1uRPFpGlwQUIW8niPuvHXaTUxeOUl5MMDGrl+tmO9A==} + hono@4.12.9: + resolution: {integrity: sha512-wy3T8Zm2bsEvxKZM5w21VdHDDcwVS1yUFFY6i8UobSsKfFceT7TOwhbhfKsDyx7tYQlmRM5FLpIuYvNFyjctiA==} engines: {node: '>=16.9.0'} - html-encoding-sniffer@6.0.0: - resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + hosted-git-info@9.0.2: + resolution: {integrity: sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==} + engines: {node: ^20.17.0 || >=22.9.0} html-entities@2.6.0: resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==} @@ -5465,10 +6382,10 @@ packages: i18next-resources-to-backend@1.2.1: resolution: {integrity: sha512-okHbVA+HZ7n1/76MsfhPqDou0fptl2dAlhRDu2ideXloRRduzHsqDOznJBef+R3DFZnbvWoBW+KxJ7fnFjd6Yw==} - i18next@25.10.4: - resolution: {integrity: sha512-XsE/6eawy090meuFU0BTY9BtmWr1m9NSwLr0NK7/A04LA58wdAvDsi9WNOJ40Qb1E9NIPbvnVLZEN2fWDd3/3Q==} + i18next@25.10.10: + resolution: {integrity: sha512-cqUW2Z3EkRx7NqSyywjkgCLK7KLCL6IFVFcONG7nVYIJ3ekZ1/N5jUsihHV6Bq37NfhgtczxJcxduELtjTwkuQ==} peerDependencies: - typescript: ^5 + typescript: ^5 || ^6 peerDependenciesMeta: typescript: optional: true @@ -5524,12 +6441,20 @@ packages: resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} engines: {node: '>=12'} + index-to-position@1.2.0: + resolution: {integrity: sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==} + engines: {node: '>=18'} + inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + ini@2.0.0: + resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==} + engines: {node: '>=10'} + inline-style-parser@0.2.7: resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} @@ -5593,25 +6518,38 @@ packages: is-hexadecimal@2.0.1: resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + is-in-ssh@1.0.0: + resolution: {integrity: sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==} + engines: {node: '>=20'} + is-inside-container@1.0.0: resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} engines: {node: '>=14.16'} hasBin: true + is-installed-globally@0.4.0: + resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==} + engines: {node: '>=10'} + is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + is-plain-obj@4.1.0: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} - is-potential-custom-element-name@1.0.1: - resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} - is-reference@3.0.3: resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + is-wsl@3.1.1: resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} engines: {node: '>=16'} @@ -5646,8 +6584,8 @@ packages: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true - jotai@2.18.1: - resolution: {integrity: sha512-e0NOzK+yRFwHo7DOp0DS0Ycq74KMEAObDWFGmfEL28PD9nLqBTt3/Ug7jf9ca72x0gC9LQZG9zH+0ISICmy3iA==} + jotai@2.19.0: + resolution: {integrity: sha512-r2wwxEXP1F2JteDLZEOPoIpAHhV89paKsN5GWVYndPNMMP/uVZDcC+fNj0A8NjKgaPWzdyO8Vp8YcYKe0uCEqQ==} engines: {node: '>=12.20.0'} peerDependencies: '@babel/core': '>=7.0.0' @@ -5664,6 +6602,10 @@ packages: react: optional: true + joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + js-audio-recorder@1.0.7: resolution: {integrity: sha512-JiDODCElVHGrFyjGYwYyNi7zCbKk9va9C77w+zCPMmi4C6ix7zsX2h3ddHugmo4dOTOTCym9++b/wVW9nC0IaA==} @@ -5691,15 +6633,6 @@ packages: resolution: {integrity: sha512-/2uqY7x6bsrpi3i9LVU6J89352C0rpMk0as8trXxCtvd4kPk1ke/Eyif6wqfSLvoNJqcDG9Vk4UsXgygzCt2xA==} engines: {node: '>=20.0.0'} - jsdom@29.0.1: - resolution: {integrity: sha512-z6JOK5gRO7aMybVq/y/MlIpKh8JIi68FBKMUtKkK2KH/wMSRlCxQ682d08LB9fYXplyY/UXG8P4XXTScmdjApg==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24.0.0} - peerDependencies: - canvas: ^3.2.2 - peerDependenciesMeta: - canvas: - optional: true - jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -5739,8 +6672,8 @@ packages: resolution: {integrity: sha512-eQQBjBnsVtGacsG9uJNB8qOr3yA8rga4wAaGG1qRcBzSIvfhERLrWxMAM1hp5fcS6Abo8M4+bUBTekYR0qTPQw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - katex@0.16.40: - resolution: {integrity: sha512-1DJcK/L05k1Y9Gf7wMcyuqFOL6BiY3vY0CFcAM/LPRN04NALxcl6u7lOWNsp3f/bCHWxigzQl6FbR95XJ4R84Q==} + katex@0.16.44: + resolution: {integrity: sha512-EkxoDTk8ufHqHlf9QxGwcxeLkWRR3iOuYfRpfORgYfqc8s13bgb+YtRY59NK5ZpRaCwq1kqA6a5lpX8C/eLphQ==} hasBin: true keyv@4.5.4: @@ -5749,11 +6682,14 @@ packages: khroma@2.1.0: resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==} - knip@6.0.2: - resolution: {integrity: sha512-W17Bo5N9AYn0ZkgWHGBmK/01SrSmr3B6iStr3zudDa2eqi+Kc8VmPjSpTYKDV2Uy/kojrlcH/gS1wypAXfXRRA==} + knip@6.1.0: + resolution: {integrity: sha512-n5eVbJP7HXmwTsiJcELWJe2O1ESxyCTNxJzRTIECDYDTM465qnqk7fL2dv6ae3NUFvFWorZvGlh9mcwxwJ5Xgw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true + knuth-shuffle-seeded@1.0.6: + resolution: {integrity: sha512-9pFH0SplrfyKyojCLxZfMcvkhf5hH0d+UwR9nTVJ/DDQJGuzcXjTwB7TP7sDfehSudlGGaOLblmEWqv04ERVWg==} + kolorist@1.8.0: resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} @@ -5888,6 +6824,10 @@ packages: resolution: {integrity: sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==} engines: {node: '>=20.0.0'} + load-tsconfig@0.2.5: + resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + loader-runner@4.3.1: resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==} engines: {node: '>=6.11.5'} @@ -5906,6 +6846,12 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash.mergewith@4.6.2: + resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==} + + lodash.sortby@4.7.0: + resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} + lodash@4.17.23: resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==} @@ -5923,6 +6869,9 @@ packages: loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + lower-case@2.0.2: + resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + lowlight@1.20.0: resolution: {integrity: sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==} @@ -5968,11 +6917,15 @@ packages: engines: {node: '>= 20'} hasBin: true - marked@17.0.4: - resolution: {integrity: sha512-NOmVMM+KAokHMvjWmC5N/ZOvgmSWuqJB8FoYI019j4ogb/PeRMKoKIjReZ2w3376kkA8dSJIP8uD993Kxc0iRQ==} + marked@17.0.5: + resolution: {integrity: sha512-6hLvc0/JEbRjRgzI6wnT2P1XuM1/RrrDEX0kPt0N7jGm1133g6X7DlxFasUIx+72aKAr904GTxhSLDrd5DIlZg==} engines: {node: '>= 20'} hasBin: true + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + mdast-util-directive@3.1.0: resolution: {integrity: sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==} @@ -6042,9 +6995,6 @@ packages: mdn-data@2.23.0: resolution: {integrity: sha512-786vq1+4079JSeu2XdcDjrhi/Ry7BWtjDl9WtGPWLiIHb2T66GvIVflZTBoSNZ5JqTtJGYEVMuFA/lbQlMOyDQ==} - mdn-data@2.27.1: - resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} - memoize-one@5.2.1: resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} @@ -6184,6 +7134,11 @@ packages: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + mime@3.0.0: + resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} + engines: {node: '>=10.0.0'} + hasBin: true + mime@4.1.0: resolution: {integrity: sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==} engines: {node: '>=16'} @@ -6225,8 +7180,13 @@ packages: mkdirp-classic@0.5.3: resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} - mlly@1.8.1: - resolution: {integrity: sha512-SnL6sNutTwRWWR/vcmCYHSADjiEesp5TGQQ0pXyLhW5IoeibRlF/CbSLailbB3CNqJUk9cVJ9dUDnbD7GrcHBQ==} + mkdirp@3.0.1: + resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} + engines: {node: '>=10'} + hasBin: true + + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} module-alias@2.3.4: resolution: {integrity: sha512-bOclZt8hkpuGgSSoG07PKmvzTizROilUTvLNyrMqvlC9snhs7y7GzjNWAVbISIOlhCP1T14rH1PDAV9iNyBq/w==} @@ -6299,6 +7259,9 @@ packages: sass: optional: true + no-case@3.0.4: + resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + node-abi@3.89.0: resolution: {integrity: sha512-6u9UwL0HlAl21+agMN3YAMXcKByMqwGx+pq+P76vii5f7hTPtKDp08/H9py6DY+cfDw7kQNTGEj/rly3IgbNQA==} engines: {node: '>=10'} @@ -6312,6 +7275,10 @@ packages: node-releases@2.0.36: resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} + normalize-package-data@8.0.0: + resolution: {integrity: sha512-RWk+PI433eESQ7ounYxIp67CYuVsS1uYSonX3kA6ps/3LWfjVQa/ptEg6Y3T6uAMq1mWpX9PQ+qx+QaHpsc7gQ==} + engines: {node: ^20.17.0 || >=22.9.0} + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -6374,6 +7341,10 @@ packages: resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} engines: {node: '>=18'} + open@11.0.0: + resolution: {integrity: sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==} + engines: {node: '>=20'} + openapi-types@12.1.3: resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==} @@ -6381,24 +7352,24 @@ packages: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} - oxc-parser@0.120.0: - resolution: {integrity: sha512-WyPWZlcIm+Fkte63FGfgFB8mAAk33aH9h5N9lphXVOHSXEBFFsmYdOBedVKly363aWABjZdaj/m9lBfEY4wt+w==} + oxc-parser@0.121.0: + resolution: {integrity: sha512-ek9o58+SCv6AV7nchiAcUJy1DNE2CC5WRdBcO0mF+W4oRjNQfPO7b3pLjTHSFECpHkKGOZSQxx3hk8viIL5YCg==} engines: {node: ^20.19.0 || >=22.12.0} oxc-resolver@11.19.1: resolution: {integrity: sha512-qE/CIg/spwrTBFt5aKmwe3ifeDdLfA2NESN30E42X/lII5ClF8V7Wt6WIJhcGZjp0/Q+nQ+9vgxGk//xZNX2hg==} - oxfmt@0.41.0: - resolution: {integrity: sha512-sKLdJZdQ3bw6x9qKiT7+eID4MNEXlDHf5ZacfIircrq6Qwjk0L6t2/JQlZZrVHTXJawK3KaMuBoJnEJPcqCEdg==} + oxfmt@0.42.0: + resolution: {integrity: sha512-QhejGErLSMReNuZ6vxgFHDyGoPbjTRNi6uGHjy0cvIjOQFqD6xmr/T+3L41ixR3NIgzcNiJ6ylQKpvShTgDfqg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - oxlint-tsgolint@0.17.1: - resolution: {integrity: sha512-gJc7hb1ZQFbWjRDYpu1XG+5IRdr1S/Jz/W2ohcpaqIXuDmHU0ujGiM0x05J0nIfwMF3HOEcANi/+j6T0Uecdpg==} + oxlint-tsgolint@0.17.3: + resolution: {integrity: sha512-1eh4bcpOMw0e7+YYVxmhFc2mo/V6hJ2+zfukqf+GprvVn3y94b69M/xNrYLmx5A+VdYe0i/bJ2xOs6Hp/jRmRA==} hasBin: true - oxlint@1.56.0: - resolution: {integrity: sha512-Q+5Mj5PVaH/R6/fhMMFzw4dT+KPB+kQW4kaL8FOIq7tfhlnEVp6+3lcWqFruuTNlUo9srZUW3qH7Id4pskeR6g==} + oxlint@1.57.0: + resolution: {integrity: sha512-DGFsuBX5MFZX9yiDdtKjTrYPq45CZ8Fft6qCltJITYZxfwYjVdGf/6wycGYTACloauwIPxUnYhBVeZbHvleGhw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -6411,6 +7382,10 @@ packages: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} + p-limit@7.3.0: + resolution: {integrity: sha512-7cIXg/Z0M5WZRblrsOla88S4wAK+zOQQWeBYfV3qJuJXMr+LnbYjaadrFaS0JILfEDPVqHyKnZ1Z/1d6J9VVUw==} + engines: {node: '>=20'} + p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} @@ -6418,6 +7393,10 @@ packages: package-manager-detector@1.6.0: resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} + pad-right@0.2.2: + resolution: {integrity: sha512-4cy8M95ioIGolCoMmm2cMntGR1lPLEbOMzOKu8bzjuJP6JpzEMQcDHmh7hHLYGgob+nKe1YHFMaG4V59HQa89g==} + engines: {node: '>=0.10.0'} + pako@0.2.9: resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} @@ -6444,6 +7423,10 @@ packages: parse-imports-exports@0.2.4: resolution: {integrity: sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==} + parse-json@8.3.0: + resolution: {integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==} + engines: {node: '>=18'} + parse-statements@1.0.11: resolution: {integrity: sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==} @@ -6536,6 +7519,16 @@ packages: pkg-types@2.3.0: resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} + playwright-core@1.58.2: + resolution: {integrity: sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.58.2: + resolution: {integrity: sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==} + engines: {node: '>=18'} + hasBin: true + pluralize@8.0.0: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} @@ -6622,6 +7615,10 @@ packages: resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} engines: {node: ^10 || ^12 || >=14} + powershell-utils@0.1.0: + resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==} + engines: {node: '>=20'} + prebuild-install@7.1.3: resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} engines: {node: '>=10'} @@ -6640,15 +7637,26 @@ packages: resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} engines: {node: '>=6'} + progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + property-expr@2.0.6: + resolution: {integrity: sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==} + property-information@5.6.0: resolution: {integrity: sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==} property-information@7.1.0: resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} + pump@3.0.4: resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} @@ -6713,8 +7721,8 @@ packages: react: '>= 16.3.0' react-dom: '>= 16.3.0' - react-easy-crop@5.5.6: - resolution: {integrity: sha512-Jw3/ozs8uXj3NpL511Suc4AHY+mLRO23rUgipXvNYKqezcFSYHxe4QXibBymkOoY6oOtLVMPO2HNPRHYvMPyTw==} + react-easy-crop@5.5.7: + resolution: {integrity: sha512-kYo4NtMeXFQB7h1U+h5yhUkE46WQbQdq7if54uDlbMdZHdRgNehfvaFrXnFw5NR1PNoUOJIfTwLnWmEx/MaZnA==} peerDependencies: react: '>=16.4.0' react-dom: '>=16.4.0' @@ -6733,14 +7741,14 @@ packages: react: '>=16.8.0' react-dom: '>=16.8.0' - react-i18next@16.6.1: - resolution: {integrity: sha512-izjXh+AkBLy3h3xe3sh6Gg1flhFHc3UyzsMftMKYJr2Z7WvAZQIdjjpHypctN41zFoeLdJUNGDgP1+Qich2fYg==} + react-i18next@16.6.6: + resolution: {integrity: sha512-ZgL2HUoW34UKUkOV7uSQFE1CDnRPD+tCR3ywSuWH7u2iapnz86U8Bi3Vrs620qNDzCf1F47NxglCEkchCTDOHw==} peerDependencies: - i18next: '>= 25.6.2' + i18next: '>= 25.10.9' react: '>= 16.8.0' react-dom: '*' react-native: '*' - typescript: ^5 + typescript: ^5 || ^6 peerDependenciesMeta: react-dom: optional: true @@ -6854,6 +7862,14 @@ packages: read-cache@1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + read-package-up@12.0.0: + resolution: {integrity: sha512-Q5hMVBYur/eQNWDdbF4/Wqqr9Bjvtrw2kjGxxBbKLbx8bVCL8gcArjTy8zDUuLGQicftpMuU0riQNcAsbtOVsw==} + engines: {node: '>=20'} + + read-pkg@10.1.0: + resolution: {integrity: sha512-I8g2lArQiP78ll51UeMZojewtYgIRCKCWqZEgOO8c/uefTI+XDXvCSXu3+YNUaTNvZzobrL5+SqHjBrByRRTdg==} + engines: {node: '>=20'} + readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} @@ -6892,6 +7908,9 @@ packages: resolution: {integrity: sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + reflect-metadata@0.2.2: + resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} + refractor@3.6.0: resolution: {integrity: sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==} @@ -6899,6 +7918,9 @@ packages: resolution: {integrity: sha512-sZuz1dYW/ZsfG17WSAG7eS85r5a0dDsvg+7BiiYR5o6lKCAtUrEwdmRmaGF6rwVj3LcmAeYkOWKEPlbPzN3Y3A==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + regexp-match-indices@1.0.2: + resolution: {integrity: sha512-DwZuAkt8NF5mKwGGER1EGh2PRqyvhRhhLviH+R8y8dIuaQROlUfXjt4s9ZTXstIsSkptf06BSvwcEmmfheJJWQ==} + regexp-tree@0.1.27: resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} hasBin: true @@ -6949,6 +7971,10 @@ packages: remend@1.3.0: resolution: {integrity: sha512-iIhggPkhW3hFImKtB10w0dz4EZbs28mV/dmbcYVonWEJ6UGHHpP+bFZnTh6GNWJONg5m+U56JrL+8IxZRdgWjw==} + repeat-string@1.6.1: + resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} + engines: {node: '>=0.10'} + require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} @@ -6967,6 +7993,10 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} @@ -6986,8 +8016,13 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - robust-predicates@3.0.2: - resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + robust-predicates@3.0.3: + resolution: {integrity: sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==} + + rolldown@1.0.0-rc.12: + resolution: {integrity: sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true rollup@4.59.0: resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==} @@ -7029,10 +8064,6 @@ packages: resolution: {integrity: sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==} engines: {node: '>=11.0.0'} - saxes@6.0.0: - resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} - engines: {node: '>=v12.22.7'} - scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} @@ -7048,6 +8079,9 @@ packages: resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==} engines: {node: ^14.0.0 || >=16.0.0} + seed-random@2.2.0: + resolution: {integrity: sha512-34EQV6AAHQGhoc0tn/96a9Fsi6v2xdqe/dMUwljGRaFOzR3EgRmECvD0O8vi8X+/uQ50LGHfkNu/Eue5TPKZkQ==} + semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -7141,20 +8175,29 @@ packages: space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + spdx-exceptions@2.5.0: resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + spdx-expression-parse@4.0.0: resolution: {integrity: sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==} spdx-license-ids@3.0.23: resolution: {integrity: sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==} - srvx@0.11.12: - resolution: {integrity: sha512-AQfrGqntqVPXgP03pvBDN1KyevHC+KmYVqb8vVf4N+aomQqdhaZxjvoVp+AOm4u6x+GgNQY3MVzAUIn+TqwkOA==} + srvx@0.11.13: + resolution: {integrity: sha512-oknN6qduuMPafxKtHucUeG32Q963pjriA5g3/Bl05cwEsUe5VVbIU4qR9LrALHbipSCyBe+VmfDGGydqazDRkw==} engines: {node: '>=20.16.0'} hasBin: true + stackframe@1.3.4: + resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} + state-local@1.0.7: resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==} @@ -7165,8 +8208,8 @@ packages: resolution: {integrity: sha512-9SN0XIjBBXCT6ZXXVnScJN4KP2RyFg6B8sEoFlugVHMANysfaEni4LTWlvUQQ/R0wgZl1Ovt9KBQbzn21kHoZA==} engines: {node: '>=20.19.0'} - storybook@10.3.1: - resolution: {integrity: sha512-i/CA1dUyVcF6cNL3tgPTQ/G6Evh6r3QdATuiiKObrA3QkEKmt3jrY+WeuQA7FCcmHk/vKabeliNrblaff8aY6Q==} + storybook@10.3.3: + resolution: {integrity: sha512-tMoRAts9EVqf+mEMPLC6z1DPyHbcPe+CV1MhLN55IKsl0HxNjvVGK44rVPSePbltPE6vIsn4bdRj6CCUt8SJwQ==} hasBin: true peerDependencies: prettier: ^2 || ^3 @@ -7180,6 +8223,10 @@ packages: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 + string-argv@0.3.1: + resolution: {integrity: sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==} + engines: {node: '>=0.6.19'} + string-argv@0.3.2: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} @@ -7231,6 +8278,9 @@ packages: strip-literal@3.1.0: resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} + structured-clone-es@2.0.0: + resolution: {integrity: sha512-5UuAHmBLXYPCl22xWJrFuGmIhBKQzxISPVz6E7nmTmTcAOpUzlbjKJsRrCE4vADmMQ0dzeCnlWn9XufnAGf76Q==} + style-to-js@1.1.21: resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} @@ -7275,9 +8325,6 @@ packages: engines: {node: '>=14.0.0'} hasBin: true - symbol-tree@3.2.4: - resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - synckit@0.11.12: resolution: {integrity: sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==} engines: {node: ^14.18.0 || >=16.0.0} @@ -7309,10 +8356,6 @@ packages: engines: {node: '>=14.0.0'} hasBin: true - tapable@2.3.0: - resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} - engines: {node: '>=6'} - tapable@2.3.2: resolution: {integrity: sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==} engines: {node: '>=6'} @@ -7360,6 +8403,9 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + tiny-case@1.0.3: + resolution: {integrity: sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==} + tiny-inflate@1.0.3: resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} @@ -7372,6 +8418,9 @@ packages: tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyexec@1.0.4: resolution: {integrity: sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==} engines: {node: '>=18'} @@ -7418,17 +8467,16 @@ packages: resolution: {integrity: sha512-A5F0cM6+mDleacLIEUkmfpkBbnHJFV1d2rprHU2MXNk7mlxHq2zGojA+SRvQD1RoMo9gqjZPWEaKG4v1BQ48lw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} + toposort@2.0.2: + resolution: {integrity: sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==} + totalist@3.0.1: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} - tough-cookie@6.0.1: - resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==} - engines: {node: '>=16'} - - tr46@6.0.0: - resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} - engines: {node: '>=20'} + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true trim-lines@3.0.1: resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} @@ -7436,8 +8484,8 @@ packages: trough@2.2.0: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} - ts-api-utils@2.4.0: - resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==} + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' @@ -7487,6 +8535,25 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsup@8.5.1: + resolution: {integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + '@microsoft/api-extractor': ^7.36.0 + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: '>=4.5.0' + peerDependenciesMeta: + '@microsoft/api-extractor': + optional: true + '@swc/core': + optional: true + postcss: + optional: true + typescript: + optional: true + tsx@4.21.0: resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} engines: {node: '>=18.0.0'} @@ -7502,8 +8569,16 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - type-fest@5.4.4: - resolution: {integrity: sha512-JnTrzGu+zPV3aXIUhnyWJj4z/wigMsdYajGLIYakqyOW1nPllzXEJee0QQbHj+CTIQtXGlAjuK0UY+2xTyjVAw==} + type-fest@2.19.0: + resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} + engines: {node: '>=12.20'} + + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + + type-fest@5.5.0: + resolution: {integrity: sha512-PlBfpQwiUvGViBNX84Yxwjsdhd1TUlXr6zjX7eoirtCPIr08NAmxwa+fcYBTeRQxHo9YC9wwF3m9i700sHma8g==} engines: {node: '>=20'} typescript@5.9.3: @@ -7536,13 +8611,13 @@ packages: resolution: {integrity: sha512-jxytwMHhsbdpBXxLAcuu0fzlQeXCNnWdDyRHpvWsUl8vd98UwYdl9YTyn8/HcpcJPC3pwUveefsa3zTxyD/ERg==} engines: {node: '>=20.18.1'} - undici@7.24.6: - resolution: {integrity: sha512-Xi4agocCbRzt0yYMZGMA6ApD7gvtUFaxm4ZmeacWI4cZxaF6C+8I8QfofC20NAePiB/IcvZmzkJ7XPa471AEtA==} - engines: {node: '>=20.18.1'} - unicode-trie@2.0.0: resolution: {integrity: sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==} + unicorn-magic@0.4.0: + resolution: {integrity: sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==} + engines: {node: '>=20'} + unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} @@ -7591,6 +8666,9 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + upper-case-first@2.0.2: + resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==} + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -7655,6 +8733,9 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + util-arity@1.1.0: + resolution: {integrity: sha512-kkyIsXKwemfSy8ZEoaIz06ApApnWsk5hQO0vLjZS6UkBiGiW++Jsyb8vSBoc0WKlffGoGs5yYy/j5pp8zckrFA==} + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -7666,14 +8747,17 @@ packages: resolution: {integrity: sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==} hasBin: true - valibot@1.3.0: - resolution: {integrity: sha512-SItIaOFnWYho/AcRU5gOtyfkTsuDTC3tRv+jy4/py8xERPnvHdM+ybD1iIqWTATVWG1nZetOfwZKq5upBjSqzw==} + valibot@1.3.1: + resolution: {integrity: sha512-sfdRir/QFM0JaF22hqTroPc5xy4DimuGQVKFrzF1YfGwaS1nJot3Y8VqMdLO2Lg27fMzat2yD3pY5PbAYO39Gg==} peerDependencies: typescript: '>=5' peerDependenciesMeta: typescript: optional: true + validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + vfile-location@5.0.3: resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} @@ -7683,15 +8767,14 @@ packages: vfile@6.0.3: resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} - vinext@https://pkg.pr.new/vinext@b6a2cac: - resolution: {tarball: https://pkg.pr.new/vinext@b6a2cac} - version: 0.0.5 + vinext@0.0.38: + resolution: {integrity: sha512-zlQswirXCApDgAFq1eoO/YbRlavGE+Bnowz5vXoQa2EmbFhYg52+T8SZs1QWdOqkbZMhpLIV/iaWvHtkRv2t4Q==} engines: {node: '>=22'} hasBin: true peerDependencies: '@mdx-js/rollup': ^3.0.0 '@vitejs/plugin-react': ^5.1.4 || ^6.0.0 - '@vitejs/plugin-rsc': ^0.5.19 + '@vitejs/plugin-rsc': ^0.5.21 react: '>=19.2.0' react-dom: '>=19.2.0' react-server-dom-webpack: ^19.2.4 @@ -7704,41 +8787,31 @@ packages: react-server-dom-webpack: optional: true - vite-dev-rpc@1.1.0: - resolution: {integrity: sha512-pKXZlgoXGoE8sEKiKJSng4hI1sQ4wi5YT24FCrwrLt6opmkjlqPPVmiPWWJn8M8byMxRGzp1CrFuqQs4M/Z39A==} - peerDependencies: - vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 || ^7.0.0-0 - - vite-hot-client@2.1.0: - resolution: {integrity: sha512-7SpgZmU7R+dDnSmvXE1mfDtnHLHQSisdySVR7lO8ceAXvM0otZeuQQ6C8LrS5d/aYyP/QZ0hI0L+dIPrm4YlFQ==} - peerDependencies: - vite: ^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 - vite-plugin-commonjs@0.10.4: resolution: {integrity: sha512-eWQuvQKCcx0QYB5e5xfxBNjQKyrjEWZIR9UOkOV6JAgxVhtbZvCOF+FNC2ZijBJ3U3Px04ZMMyyMyFBVWIJ5+g==} vite-plugin-dynamic-import@1.6.0: resolution: {integrity: sha512-TM0sz70wfzTIo9YCxVFwS8OA9lNREsh+0vMHGSkWDTZ7bgd1Yjs5RV8EgB634l/91IsXJReg0xtmuQqP0mf+rg==} - vite-plugin-inspect@11.3.3: - resolution: {integrity: sha512-u2eV5La99oHoYPHE6UvbwgEqKKOQGz86wMg40CCosP6q8BkB6e5xPneZfYagK4ojPJSj5anHCrnvC20DpwVdRA==} + vite-plugin-inspect@12.0.0-beta.1: + resolution: {integrity: sha512-ang8DMcQxr2MJRjdvwabkD0uOPFB5/fP4hldZvAqCl82SABXK1zYLyZKGrauCblR61cvDUavxyiHbtD4zTdw0A==} engines: {node: '>=14'} peerDependencies: '@nuxt/kit': '*' - vite: ^6.0.0 || ^7.0.0-0 + vite: ^8.0.0-0 peerDependenciesMeta: '@nuxt/kit': optional: true - vite-plugin-storybook-nextjs@3.2.3: - resolution: {integrity: sha512-NQvkiZKfbGmk0j3mYeTJnGiucV+VOcryCsm/CoE7rBVRrpVntg5lWj+CbosFwHhGPpWQ3I4HJ3nSRzDq0u74Ug==} + vite-plugin-storybook-nextjs@3.2.4: + resolution: {integrity: sha512-shFOJpGQsWDS1FLm8BR8b6FIQC65pFZ5a0IUFGLiBHAX1eRz0N8TOhUJN4p708zfPBLDXqWzj++ocECe8gSoMg==} peerDependencies: next: ^14.1.0 || ^15.0.0 || ^16.0.0 - storybook: ^0.0.0-0 || ^9.0.0 || ^10.0.0 || ^10.0.0-0 || ^10.1.0-0 || ^10.2.0-0 || ^10.3.0-0 + storybook: ^0.0.0-0 || ^9.0.0 || ^10.0.0 || ^10.0.0-0 || ^10.1.0-0 || ^10.2.0-0 || ^10.3.0-0 || ^10.4.0-0 vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - vite-plus@0.1.13: - resolution: {integrity: sha512-DP87+eRFhYYDdcjm2nr3DOKt0cv6mIXCNXn+zc59YHgR0Wh7uL2E/55mjusJ7ajwcXenpGW+c4KPeoqhQAbhxg==} + vite-plus@0.1.14: + resolution: {integrity: sha512-p4pWlpZZNiEsHxPWNdeIU9iuPix3ydm3ficb0dXPggoyIkdotfXtvn2NPX9KwfiQImU72EVEs4+VYBZYNcUYrw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -7755,6 +8828,49 @@ packages: peerDependencies: vite: '*' + vite@8.0.3: + resolution: {integrity: sha512-B9ifbFudT1TFhfltfaIPgjo9Z3mDynBTJSUYxTjOQruf/zHH+ezCQKcoqO+h7a9Pw9Nm/OtlXAiGT1axBgwqrQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.0 + esbuild: 0.27.2 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: 2.8.3 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + vitefu@1.1.2: resolution: {integrity: sha512-zpKATdUbzbsycPFBN71nS2uzBUQiVnFoOrr2rvqv34S1lcAgMKKkjWleLGeiJlZ8lwCXvtWaRn7R3ZC16SYRuw==} peerDependencies: @@ -7763,8 +8879,8 @@ packages: vite: optional: true - vitest-canvas-mock@1.1.3: - resolution: {integrity: sha512-zlKJR776Qgd+bcACPh0Pq5MG3xWq+CdkACKY/wX4Jyija0BSz8LH3aCCgwFKYFwtm565+050YFEGG9Ki0gE/Hw==} + vitest-canvas-mock@1.1.4: + resolution: {integrity: sha512-4boWHY+STwAxGl1+uwakNNoQky5EjPLC8HuponXNoAscYyT1h/F7RUvTkl4IyF/MiWr3V8Q626je3Iel3eArqA==} peerDependencies: vitest: ^3.0.0 || ^4.0.0 @@ -7798,10 +8914,6 @@ packages: peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - w3c-xmlserializer@5.0.0: - resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} - engines: {node: '>=18'} - walk-up-path@4.0.0: resolution: {integrity: sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==} engines: {node: 20 || >=22} @@ -7816,10 +8928,6 @@ packages: web-vitals@5.1.0: resolution: {integrity: sha512-ArI3kx5jI0atlTtmV0fWU3fjpLmq/nD3Zr1iFFlJLaqa5wLBkUSzINwBPySCX/8jRyjlmy1Volw1kz1g9XE4Jg==} - webidl-conversions@8.0.1: - resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} - engines: {node: '>=20'} - webpack-sources@3.3.4: resolution: {integrity: sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==} engines: {node: '>=10.13.0'} @@ -7850,14 +8958,6 @@ packages: resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} engines: {node: '>=18'} - whatwg-mimetype@5.0.0: - resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} - engines: {node: '>=20'} - - whatwg-url@16.0.1: - resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -7874,18 +8974,6 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@8.19.0: - resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - ws@8.20.0: resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} engines: {node: '>=10.0.0'} @@ -7902,16 +8990,17 @@ packages: resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==} engines: {node: '>=18'} + wsl-utils@0.3.1: + resolution: {integrity: sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==} + engines: {node: '>=20'} + xml-name-validator@4.0.0: resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} engines: {node: '>=12'} - xml-name-validator@5.0.0: - resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} - engines: {node: '>=18'} - - xmlchars@2.2.0: - resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + xmlbuilder@15.1.1: + resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} + engines: {node: '>=8.0'} xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} @@ -7945,9 +9034,16 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + yocto-queue@1.2.2: + resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} + engines: {node: '>=12.20'} + yoga-layout@3.2.1: resolution: {integrity: sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==} + yup@1.7.1: + resolution: {integrity: sha512-GKHFX2nXul2/4Dtfxhozv701jLQHdf6J34YDh2cEkpqoo8le5Mg6/LrdseVLrFarmFygZTlfIhHx/QKfb/QWXw==} + zen-observable@0.10.0: resolution: {integrity: sha512-iI3lT0iojZhKwT5DaFy2Ce42n3yFcLdFyOh01G7H0flMY60P8MJuVFEoJoNwXlmAyQ45GrjL6AcZmmlv8A5rbw==} @@ -8013,27 +9109,27 @@ snapshots: '@alloc/quick-lru@5.2.0': {} - '@amplitude/analytics-browser@2.37.0': + '@amplitude/analytics-browser@2.38.0': dependencies: - '@amplitude/analytics-core': 2.43.0 - '@amplitude/plugin-autocapture-browser': 1.24.1 - '@amplitude/plugin-custom-enrichment-browser': 0.1.0 - '@amplitude/plugin-network-capture-browser': 1.9.9 - '@amplitude/plugin-page-url-enrichment-browser': 0.7.0 - '@amplitude/plugin-page-view-tracking-browser': 2.9.1 - '@amplitude/plugin-web-vitals-browser': 1.1.24 + '@amplitude/analytics-core': 2.44.0 + '@amplitude/plugin-autocapture-browser': 1.25.0 + '@amplitude/plugin-custom-enrichment-browser': 0.1.2 + '@amplitude/plugin-network-capture-browser': 1.9.11 + '@amplitude/plugin-page-url-enrichment-browser': 0.7.3 + '@amplitude/plugin-page-view-tracking-browser': 2.9.4 + '@amplitude/plugin-web-vitals-browser': 1.1.26 tslib: 2.8.1 - '@amplitude/analytics-client-common@2.4.39': + '@amplitude/analytics-client-common@2.4.41': dependencies: '@amplitude/analytics-connector': 1.6.4 - '@amplitude/analytics-core': 2.43.0 + '@amplitude/analytics-core': 2.44.0 '@amplitude/analytics-types': 2.11.1 tslib: 2.8.1 '@amplitude/analytics-connector@1.6.4': {} - '@amplitude/analytics-core@2.43.0': + '@amplitude/analytics-core@2.44.0': dependencies: '@amplitude/analytics-connector': 1.6.4 '@types/zen-observable': 0.8.3 @@ -8047,96 +9143,100 @@ snapshots: dependencies: js-base64: 3.7.8 - '@amplitude/plugin-autocapture-browser@1.24.1': + '@amplitude/plugin-autocapture-browser@1.25.0': dependencies: - '@amplitude/analytics-core': 2.43.0 + '@amplitude/analytics-core': 2.44.0 tslib: 2.8.1 - '@amplitude/plugin-custom-enrichment-browser@0.1.0': + '@amplitude/plugin-custom-enrichment-browser@0.1.2': dependencies: - '@amplitude/analytics-core': 2.43.0 + '@amplitude/analytics-core': 2.44.0 tslib: 2.8.1 - '@amplitude/plugin-network-capture-browser@1.9.9': + '@amplitude/plugin-network-capture-browser@1.9.11': dependencies: - '@amplitude/analytics-core': 2.43.0 + '@amplitude/analytics-core': 2.44.0 tslib: 2.8.1 - '@amplitude/plugin-page-url-enrichment-browser@0.7.0': + '@amplitude/plugin-page-url-enrichment-browser@0.7.3': dependencies: - '@amplitude/analytics-core': 2.43.0 + '@amplitude/analytics-core': 2.44.0 tslib: 2.8.1 - '@amplitude/plugin-page-view-tracking-browser@2.9.1': + '@amplitude/plugin-page-view-tracking-browser@2.9.4': dependencies: - '@amplitude/analytics-core': 2.43.0 + '@amplitude/analytics-core': 2.44.0 tslib: 2.8.1 - '@amplitude/plugin-session-replay-browser@1.27.1(@amplitude/rrweb@2.0.0-alpha.36)(rollup@4.59.0)': + '@amplitude/plugin-session-replay-browser@1.27.5(@amplitude/rrweb@2.0.0-alpha.37)(rollup@4.59.0)': dependencies: - '@amplitude/analytics-client-common': 2.4.39 - '@amplitude/analytics-core': 2.43.0 + '@amplitude/analytics-client-common': 2.4.41 + '@amplitude/analytics-core': 2.44.0 '@amplitude/analytics-types': 2.11.1 - '@amplitude/rrweb-plugin-console-record': 2.0.0-alpha.36(@amplitude/rrweb@2.0.0-alpha.36) + '@amplitude/rrweb-plugin-console-record': 2.0.0-alpha.36(@amplitude/rrweb@2.0.0-alpha.37) '@amplitude/rrweb-record': 2.0.0-alpha.36 - '@amplitude/session-replay-browser': 1.34.1(@amplitude/rrweb@2.0.0-alpha.36)(rollup@4.59.0) + '@amplitude/session-replay-browser': 1.35.0(@amplitude/rrweb@2.0.0-alpha.37)(rollup@4.59.0) idb-keyval: 6.2.2 tslib: 2.8.1 transitivePeerDependencies: - '@amplitude/rrweb' - rollup - '@amplitude/plugin-web-vitals-browser@1.1.24': + '@amplitude/plugin-web-vitals-browser@1.1.26': dependencies: - '@amplitude/analytics-core': 2.43.0 + '@amplitude/analytics-core': 2.44.0 tslib: 2.8.1 web-vitals: 5.1.0 - '@amplitude/rrdom@2.0.0-alpha.36': + '@amplitude/rrdom@2.0.0-alpha.37': dependencies: - '@amplitude/rrweb-snapshot': 2.0.0-alpha.36 + '@amplitude/rrweb-snapshot': 2.0.0-alpha.37 '@amplitude/rrweb-packer@2.0.0-alpha.36': dependencies: - '@amplitude/rrweb-types': 2.0.0-alpha.36 + '@amplitude/rrweb-types': 2.0.0-alpha.37 fflate: 0.4.8 - '@amplitude/rrweb-plugin-console-record@2.0.0-alpha.36(@amplitude/rrweb@2.0.0-alpha.36)': + '@amplitude/rrweb-plugin-console-record@2.0.0-alpha.36(@amplitude/rrweb@2.0.0-alpha.37)': dependencies: - '@amplitude/rrweb': 2.0.0-alpha.36 + '@amplitude/rrweb': 2.0.0-alpha.37 '@amplitude/rrweb-record@2.0.0-alpha.36': dependencies: - '@amplitude/rrweb': 2.0.0-alpha.36 - '@amplitude/rrweb-types': 2.0.0-alpha.36 + '@amplitude/rrweb': 2.0.0-alpha.37 + '@amplitude/rrweb-types': 2.0.0-alpha.37 - '@amplitude/rrweb-snapshot@2.0.0-alpha.36': + '@amplitude/rrweb-snapshot@2.0.0-alpha.37': dependencies: postcss: 8.5.8 '@amplitude/rrweb-types@2.0.0-alpha.36': {} + '@amplitude/rrweb-types@2.0.0-alpha.37': {} + '@amplitude/rrweb-utils@2.0.0-alpha.36': {} - '@amplitude/rrweb@2.0.0-alpha.36': + '@amplitude/rrweb-utils@2.0.0-alpha.37': {} + + '@amplitude/rrweb@2.0.0-alpha.37': dependencies: - '@amplitude/rrdom': 2.0.0-alpha.36 - '@amplitude/rrweb-snapshot': 2.0.0-alpha.36 - '@amplitude/rrweb-types': 2.0.0-alpha.36 - '@amplitude/rrweb-utils': 2.0.0-alpha.36 + '@amplitude/rrdom': 2.0.0-alpha.37 + '@amplitude/rrweb-snapshot': 2.0.0-alpha.37 + '@amplitude/rrweb-types': 2.0.0-alpha.37 + '@amplitude/rrweb-utils': 2.0.0-alpha.37 '@types/css-font-loading-module': 0.0.7 '@xstate/fsm': 1.6.5 base64-arraybuffer: 1.0.2 mitt: 3.0.1 - '@amplitude/session-replay-browser@1.34.1(@amplitude/rrweb@2.0.0-alpha.36)(rollup@4.59.0)': + '@amplitude/session-replay-browser@1.35.0(@amplitude/rrweb@2.0.0-alpha.37)(rollup@4.59.0)': dependencies: - '@amplitude/analytics-client-common': 2.4.39 - '@amplitude/analytics-core': 2.43.0 + '@amplitude/analytics-client-common': 2.4.41 + '@amplitude/analytics-core': 2.44.0 '@amplitude/analytics-types': 2.11.1 '@amplitude/experiment-core': 0.7.2 '@amplitude/rrweb-packer': 2.0.0-alpha.36 - '@amplitude/rrweb-plugin-console-record': 2.0.0-alpha.36(@amplitude/rrweb@2.0.0-alpha.36) + '@amplitude/rrweb-plugin-console-record': 2.0.0-alpha.36(@amplitude/rrweb@2.0.0-alpha.37) '@amplitude/rrweb-record': 2.0.0-alpha.36 '@amplitude/rrweb-types': 2.0.0-alpha.36 '@amplitude/rrweb-utils': 2.0.0-alpha.36 @@ -8150,34 +9250,34 @@ snapshots: '@amplitude/targeting@0.2.0': dependencies: - '@amplitude/analytics-client-common': 2.4.39 - '@amplitude/analytics-core': 2.43.0 + '@amplitude/analytics-client-common': 2.4.41 + '@amplitude/analytics-core': 2.44.0 '@amplitude/analytics-types': 2.11.1 '@amplitude/experiment-core': 0.7.2 idb: 8.0.0 tslib: 2.8.1 - '@antfu/eslint-config@7.7.3(@eslint-react/eslint-plugin@3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(@next/eslint-plugin-next@16.2.1)(@typescript-eslint/rule-tester@8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(@typescript-eslint/typescript-estree@8.57.1(typescript@5.9.3))(@typescript-eslint/utils@8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(@voidzero-dev/vite-plus-test@0.1.13(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(jsdom@29.0.1(canvas@3.2.2))(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(@vue/compiler-sfc@3.5.30)(eslint-plugin-react-hooks@7.0.1(eslint@10.1.0(jiti@1.21.7)))(eslint-plugin-react-refresh@0.5.2(eslint@10.1.0(jiti@1.21.7)))(eslint@10.1.0(jiti@1.21.7))(oxlint@1.56.0(oxlint-tsgolint@0.17.1))(typescript@5.9.3)': + '@antfu/eslint-config@7.7.3(@eslint-react/eslint-plugin@3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(@next/eslint-plugin-next@16.2.1)(@typescript-eslint/rule-tester@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(@typescript-eslint/typescript-estree@8.57.2(typescript@5.9.3))(@typescript-eslint/utils@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(@voidzero-dev/vite-plus-test@0.1.14(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(@vue/compiler-sfc@3.5.31)(eslint-plugin-react-hooks@7.0.1(eslint@10.1.0(jiti@1.21.7)))(eslint-plugin-react-refresh@0.5.2(eslint@10.1.0(jiti@1.21.7)))(eslint@10.1.0(jiti@1.21.7))(oxlint@1.57.0(oxlint-tsgolint@0.17.3))(typescript@5.9.3)': dependencies: '@antfu/install-pkg': 1.1.0 '@clack/prompts': 1.1.0 - '@e18e/eslint-plugin': 0.2.0(eslint@10.1.0(jiti@1.21.7))(oxlint@1.56.0(oxlint-tsgolint@0.17.1)) + '@e18e/eslint-plugin': 0.2.0(eslint@10.1.0(jiti@1.21.7))(oxlint@1.57.0(oxlint-tsgolint@0.17.3)) '@eslint-community/eslint-plugin-eslint-comments': 4.7.1(eslint@10.1.0(jiti@1.21.7)) '@eslint/markdown': 7.5.1 '@stylistic/eslint-plugin': 5.10.0(eslint@10.1.0(jiti@1.21.7)) - '@typescript-eslint/eslint-plugin': 8.57.1(@typescript-eslint/parser@8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/parser': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) - '@vitest/eslint-plugin': 1.6.12(@voidzero-dev/vite-plus-test@0.1.13(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(jsdom@29.0.1(canvas@3.2.2))(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.57.2(@typescript-eslint/parser@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/parser': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@vitest/eslint-plugin': 1.6.13(@typescript-eslint/eslint-plugin@8.57.2(@typescript-eslint/parser@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(@voidzero-dev/vite-plus-test@0.1.14(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) ansis: 4.2.0 cac: 7.0.0 eslint: 10.1.0(jiti@1.21.7) - eslint-config-flat-gitignore: 2.2.1(eslint@10.1.0(jiti@1.21.7)) + eslint-config-flat-gitignore: 2.3.0(eslint@10.1.0(jiti@1.21.7)) eslint-flat-config-utils: 3.0.2 eslint-merge-processors: 2.0.0(eslint@10.1.0(jiti@1.21.7)) eslint-plugin-antfu: 3.2.2(eslint@10.1.0(jiti@1.21.7)) - eslint-plugin-command: 3.5.2(@typescript-eslint/rule-tester@8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(@typescript-eslint/typescript-estree@8.57.1(typescript@5.9.3))(@typescript-eslint/utils@8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.1.0(jiti@1.21.7)) + eslint-plugin-command: 3.5.2(@typescript-eslint/rule-tester@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(@typescript-eslint/typescript-estree@8.57.2(typescript@5.9.3))(@typescript-eslint/utils@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.1.0(jiti@1.21.7)) eslint-plugin-import-lite: 0.5.2(eslint@10.1.0(jiti@1.21.7)) - eslint-plugin-jsdoc: 62.8.0(eslint@10.1.0(jiti@1.21.7)) + eslint-plugin-jsdoc: 62.8.1(eslint@10.1.0(jiti@1.21.7)) eslint-plugin-jsonc: 3.1.2(eslint@10.1.0(jiti@1.21.7)) eslint-plugin-n: 17.24.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) eslint-plugin-no-only-tests: 3.3.0 @@ -8186,10 +9286,10 @@ snapshots: eslint-plugin-regexp: 3.1.0(eslint@10.1.0(jiti@1.21.7)) eslint-plugin-toml: 1.3.1(eslint@10.1.0(jiti@1.21.7)) eslint-plugin-unicorn: 63.0.0(eslint@10.1.0(jiti@1.21.7)) - eslint-plugin-unused-imports: 4.4.1(@typescript-eslint/eslint-plugin@8.57.1(@typescript-eslint/parser@8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.1.0(jiti@1.21.7)) - eslint-plugin-vue: 10.8.0(@stylistic/eslint-plugin@5.10.0(eslint@10.1.0(jiti@1.21.7)))(@typescript-eslint/parser@8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.1.0(jiti@1.21.7))(vue-eslint-parser@10.4.0(eslint@10.1.0(jiti@1.21.7))) + eslint-plugin-unused-imports: 4.4.1(@typescript-eslint/eslint-plugin@8.57.2(@typescript-eslint/parser@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.1.0(jiti@1.21.7)) + eslint-plugin-vue: 10.8.0(@stylistic/eslint-plugin@5.10.0(eslint@10.1.0(jiti@1.21.7)))(@typescript-eslint/parser@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.1.0(jiti@1.21.7))(vue-eslint-parser@10.4.0(eslint@10.1.0(jiti@1.21.7))) eslint-plugin-yml: 3.3.1(eslint@10.1.0(jiti@1.21.7)) - eslint-processor-vue-blocks: 2.0.0(@vue/compiler-sfc@3.5.30)(eslint@10.1.0(jiti@1.21.7)) + eslint-processor-vue-blocks: 2.0.0(@vue/compiler-sfc@3.5.31)(eslint@10.1.0(jiti@1.21.7)) globals: 17.4.0 local-pkg: 1.1.2 parse-gitignore: 2.0.0 @@ -8227,27 +9327,6 @@ snapshots: '@antfu/utils@8.1.1': {} - '@asamuzakjp/css-color@5.1.1': - dependencies: - '@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-color-parser': 4.0.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 - lru-cache: 11.2.7 - optional: true - - '@asamuzakjp/dom-selector@7.0.4': - dependencies: - '@asamuzakjp/nwsapi': 2.3.9 - bidi-js: 1.0.3 - css-tree: 3.2.1 - is-potential-custom-element-name: 1.0.1 - lru-cache: 11.2.7 - optional: true - - '@asamuzakjp/nwsapi@2.3.9': - optional: true - '@babel/code-frame@7.29.0': dependencies: '@babel/helper-validator-identifier': 7.28.5 @@ -8269,7 +9348,7 @@ snapshots: '@babel/types': 7.29.0 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -8341,7 +9420,7 @@ snapshots: '@babel/parser': 7.29.2 '@babel/template': 7.28.6 '@babel/types': 7.29.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -8378,11 +9457,6 @@ snapshots: '@braintree/sanitize-url@7.1.2': {} - '@bramus/specificity@2.4.2': - dependencies: - css-tree: 3.2.1 - optional: true - '@chevrotain/cst-dts-gen@11.1.2': dependencies: '@chevrotain/gast': 11.1.2 @@ -8400,13 +9474,13 @@ snapshots: '@chevrotain/utils@11.1.2': {} - '@chromatic-com/storybook@5.0.2(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': + '@chromatic-com/storybook@5.1.1(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': dependencies: '@neoconfetti/react': 1.0.0 chromatic: 13.3.5 filesize: 10.1.6 jsonfile: 6.2.0 - storybook: 10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook: 10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) strip-ansi: 7.2.0 transitivePeerDependencies: - '@chromatic-com/cypress' @@ -8434,7 +9508,7 @@ snapshots: '@code-inspector/core@1.4.5': dependencies: - '@vue/compiler-dom': 3.5.30 + '@vue/compiler-dom': 3.5.31 chalk: 4.1.2 dotenv: 16.6.1 launch-ide: 1.4.3 @@ -8474,55 +9548,135 @@ snapshots: transitivePeerDependencies: - supports-color - '@csstools/color-helpers@6.0.2': + '@colors/colors@1.5.0': optional: true - '@csstools/css-calc@3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + '@cucumber/ci-environment@13.0.0': {} + + '@cucumber/cucumber-expressions@19.0.0': dependencies: - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 - optional: true + regexp-match-indices: 1.0.2 - '@csstools/css-color-parser@4.0.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + '@cucumber/cucumber@12.7.0': dependencies: - '@csstools/color-helpers': 6.0.2 - '@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 - optional: true + '@cucumber/ci-environment': 13.0.0 + '@cucumber/cucumber-expressions': 19.0.0 + '@cucumber/gherkin': 38.0.0 + '@cucumber/gherkin-streams': 6.0.0(@cucumber/gherkin@38.0.0)(@cucumber/message-streams@4.0.1(@cucumber/messages@32.0.1))(@cucumber/messages@32.0.1) + '@cucumber/gherkin-utils': 11.0.0 + '@cucumber/html-formatter': 23.0.0(@cucumber/messages@32.0.1) + '@cucumber/junit-xml-formatter': 0.9.0(@cucumber/messages@32.0.1) + '@cucumber/message-streams': 4.0.1(@cucumber/messages@32.0.1) + '@cucumber/messages': 32.0.1 + '@cucumber/pretty-formatter': 1.0.1(@cucumber/cucumber@12.7.0)(@cucumber/messages@32.0.1) + '@cucumber/tag-expressions': 9.1.0 + assertion-error-formatter: 3.0.0 + capital-case: 1.0.4 + chalk: 4.1.2 + cli-table3: 0.6.5 + commander: 14.0.3 + debug: 4.4.3(supports-color@8.1.1) + error-stack-parser: 2.1.4 + figures: 3.2.0 + glob: 13.0.6 + has-ansi: 4.0.1 + indent-string: 4.0.0 + is-installed-globally: 0.4.0 + is-stream: 2.0.1 + knuth-shuffle-seeded: 1.0.6 + lodash.merge: 4.6.2 + lodash.mergewith: 4.6.2 + luxon: 3.7.2 + mime: 3.0.0 + mkdirp: 3.0.1 + mz: 2.7.0 + progress: 2.0.3 + read-package-up: 12.0.0 + semver: 7.7.4 + string-argv: 0.3.1 + supports-color: 8.1.1 + type-fest: 4.41.0 + util-arity: 1.1.0 + yaml: 2.8.3 + yup: 1.7.1 - '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': + '@cucumber/gherkin-streams@6.0.0(@cucumber/gherkin@38.0.0)(@cucumber/message-streams@4.0.1(@cucumber/messages@32.0.1))(@cucumber/messages@32.0.1)': dependencies: - '@csstools/css-tokenizer': 4.0.0 - optional: true + '@cucumber/gherkin': 38.0.0 + '@cucumber/message-streams': 4.0.1(@cucumber/messages@32.0.1) + '@cucumber/messages': 32.0.1 + commander: 14.0.0 + source-map-support: 0.5.21 - '@csstools/css-syntax-patches-for-csstree@1.1.2(css-tree@3.2.1)': - optionalDependencies: - css-tree: 3.2.1 - optional: true + '@cucumber/gherkin-utils@11.0.0': + dependencies: + '@cucumber/gherkin': 38.0.0 + '@cucumber/messages': 32.0.1 + '@teppeis/multimaps': 3.0.0 + commander: 14.0.2 + source-map-support: 0.5.21 - '@csstools/css-tokenizer@4.0.0': - optional: true + '@cucumber/gherkin@38.0.0': + dependencies: + '@cucumber/messages': 32.0.1 - '@e18e/eslint-plugin@0.2.0(eslint@10.1.0(jiti@1.21.7))(oxlint@1.56.0(oxlint-tsgolint@0.17.1))': + '@cucumber/html-formatter@23.0.0(@cucumber/messages@32.0.1)': + dependencies: + '@cucumber/messages': 32.0.1 + + '@cucumber/junit-xml-formatter@0.9.0(@cucumber/messages@32.0.1)': + dependencies: + '@cucumber/messages': 32.0.1 + '@cucumber/query': 14.7.0(@cucumber/messages@32.0.1) + '@teppeis/multimaps': 3.0.0 + luxon: 3.7.2 + xmlbuilder: 15.1.1 + + '@cucumber/message-streams@4.0.1(@cucumber/messages@32.0.1)': + dependencies: + '@cucumber/messages': 32.0.1 + + '@cucumber/messages@32.0.1': + dependencies: + class-transformer: 0.5.1 + reflect-metadata: 0.2.2 + + '@cucumber/pretty-formatter@1.0.1(@cucumber/cucumber@12.7.0)(@cucumber/messages@32.0.1)': + dependencies: + '@cucumber/cucumber': 12.7.0 + '@cucumber/messages': 32.0.1 + ansi-styles: 5.2.0 + cli-table3: 0.6.5 + figures: 3.2.0 + ts-dedent: 2.2.0 + + '@cucumber/query@14.7.0(@cucumber/messages@32.0.1)': + dependencies: + '@cucumber/messages': 32.0.1 + '@teppeis/multimaps': 3.0.0 + lodash.sortby: 4.7.0 + + '@cucumber/tag-expressions@9.1.0': {} + + '@e18e/eslint-plugin@0.2.0(eslint@10.1.0(jiti@1.21.7))(oxlint@1.57.0(oxlint-tsgolint@0.17.3))': dependencies: eslint-plugin-depend: 1.5.0(eslint@10.1.0(jiti@1.21.7)) optionalDependencies: eslint: 10.1.0(jiti@1.21.7) - oxlint: 1.56.0(oxlint-tsgolint@0.17.1) + oxlint: 1.57.0(oxlint-tsgolint@0.17.3) '@egoist/tailwindcss-icons@1.9.2(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@iconify/utils': 3.1.0 tailwindcss: 3.4.19(tsx@4.21.0)(yaml@2.8.3) - '@emnapi/core@1.9.0': + '@emnapi/core@1.9.1': dependencies: '@emnapi/wasi-threads': 1.2.0 tslib: 2.8.1 optional: true - '@emnapi/runtime@1.9.0': + '@emnapi/runtime@1.9.1': dependencies: tslib: 2.8.1 optional: true @@ -8537,7 +9691,7 @@ snapshots: '@es-joy/jsdoccomment@0.84.0': dependencies: '@types/estree': 1.0.8 - '@typescript-eslint/types': 8.57.1 + '@typescript-eslint/types': 8.57.2 comment-parser: 1.4.5 esquery: 1.7.0 jsdoc-type-pratt-parser: 7.1.1 @@ -8633,6 +9787,11 @@ snapshots: eslint: 10.1.0(jiti@1.21.7) eslint-visitor-keys: 3.4.3 + '@eslint-community/eslint-utils@4.9.1(eslint@10.1.0(jiti@2.6.1))': + dependencies: + eslint: 10.1.0(jiti@2.6.1) + eslint-visitor-keys: 3.4.3 + '@eslint-community/eslint-utils@4.9.1(eslint@9.27.0(jiti@1.21.7))': dependencies: eslint: 9.27.0(jiti@1.21.7) @@ -8642,9 +9801,9 @@ snapshots: '@eslint-react/ast@3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.57.1 - '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) eslint: 10.1.0(jiti@1.21.7) string-ts: 2.3.1 typescript: 5.9.3 @@ -8656,9 +9815,9 @@ snapshots: '@eslint-react/ast': 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) '@eslint-react/shared': 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) '@eslint-react/var': 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.57.1 - '@typescript-eslint/types': 8.57.1 - '@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.57.2 + '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) eslint: 10.1.0(jiti@1.21.7) ts-pattern: 5.9.0 typescript: 5.9.3 @@ -8668,24 +9827,24 @@ snapshots: '@eslint-react/eslint-plugin@3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3)': dependencies: '@eslint-react/shared': 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.57.1 - '@typescript-eslint/type-utils': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/types': 8.57.1 - '@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.57.2 + '@typescript-eslint/type-utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) eslint: 10.1.0(jiti@1.21.7) eslint-plugin-react-dom: 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) eslint-plugin-react-naming-convention: 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) eslint-plugin-react-rsc: 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) eslint-plugin-react-web-api: 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) eslint-plugin-react-x: 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) - ts-api-utils: 2.4.0(typescript@5.9.3) + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color '@eslint-react/shared@3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3)': dependencies: - '@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) eslint: 10.1.0(jiti@1.21.7) ts-pattern: 5.9.0 typescript: 5.9.3 @@ -8697,9 +9856,9 @@ snapshots: dependencies: '@eslint-react/ast': 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) '@eslint-react/shared': 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.57.1 - '@typescript-eslint/types': 8.57.1 - '@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.57.2 + '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) eslint: 10.1.0(jiti@1.21.7) ts-pattern: 5.9.0 typescript: 5.9.3 @@ -8715,7 +9874,7 @@ snapshots: '@eslint/config-array@0.20.1': dependencies: '@eslint/object-schema': 2.1.7 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) minimatch: 3.1.5 transitivePeerDependencies: - supports-color @@ -8723,7 +9882,7 @@ snapshots: '@eslint/config-array@0.23.3': dependencies: '@eslint/object-schema': 3.0.3 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) minimatch: 10.2.4 transitivePeerDependencies: - supports-color @@ -8758,7 +9917,7 @@ snapshots: '@eslint/eslintrc@3.3.5': dependencies: ajv: 6.14.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) espree: 10.4.0 globals: 14.0.0 ignore: 5.3.2 @@ -8769,6 +9928,10 @@ snapshots: transitivePeerDependencies: - supports-color + '@eslint/js@10.0.1(eslint@10.1.0(jiti@2.6.1))': + optionalDependencies: + eslint: 10.1.0(jiti@2.6.1) + '@eslint/js@9.27.0': {} '@eslint/markdown@7.5.1': @@ -8804,9 +9967,6 @@ snapshots: '@eslint/core': 1.1.1 levn: 0.4.1 - '@exodus/bytes@1.15.0': - optional: true - '@floating-ui/core@1.7.5': dependencies: '@floating-ui/utils': 0.2.11 @@ -8862,9 +10022,9 @@ snapshots: dependencies: react: 19.2.4 - '@hono/node-server@1.19.11(hono@4.12.8)': + '@hono/node-server@1.19.11(hono@4.12.9)': dependencies: - hono: 4.12.8 + hono: 4.12.9 '@humanfs/core@0.19.1': {} @@ -8906,11 +10066,11 @@ snapshots: '@antfu/install-pkg': 1.1.0 '@antfu/utils': 8.1.1 '@iconify/types': 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) globals: 15.15.0 kolorist: 1.8.0 local-pkg: 1.1.2 - mlly: 1.8.1 + mlly: 1.8.2 transitivePeerDependencies: - supports-color @@ -8918,7 +10078,7 @@ snapshots: dependencies: '@antfu/install-pkg': 1.1.0 '@iconify/types': 2.0.0 - mlly: 1.8.1 + mlly: 1.8.2 '@img/colour@1.1.0': {} @@ -9004,7 +10164,7 @@ snapshots: '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.9.0 + '@emnapi/runtime': 1.9.1 optional: true '@img/sharp-win32-arm64@0.34.5': @@ -9020,11 +10180,11 @@ snapshots: dependencies: minipass: 7.1.3 - '@joshwooding/vite-plugin-react-docgen-typescript@0.6.4(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(typescript@5.9.3)': + '@joshwooding/vite-plugin-react-docgen-typescript@0.6.4(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(typescript@5.9.3)': dependencies: glob: 13.0.6 react-docgen-typescript: 2.4.0(typescript@5.9.3) - vite: '@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' + vite: '@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' optionalDependencies: typescript: 5.9.3 @@ -9279,10 +10439,10 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@napi-rs/wasm-runtime@1.1.1': + '@napi-rs/wasm-runtime@1.1.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)': dependencies: - '@emnapi/core': 1.9.0 - '@emnapi/runtime': 1.9.0 + '@emnapi/core': 1.9.1 + '@emnapi/runtime': 1.9.1 '@tybys/wasm-util': 0.10.1 optional: true @@ -9339,139 +10499,146 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 + '@nolyfill/hasown@1.0.44': {} + '@nolyfill/is-core-module@1.0.39': {} '@nolyfill/safer-buffer@1.0.44': {} '@nolyfill/side-channel@1.0.44': {} - '@orpc/client@1.13.9': + '@orpc/client@1.13.13': dependencies: - '@orpc/shared': 1.13.9 - '@orpc/standard-server': 1.13.9 - '@orpc/standard-server-fetch': 1.13.9 - '@orpc/standard-server-peer': 1.13.9 + '@orpc/shared': 1.13.13 + '@orpc/standard-server': 1.13.13 + '@orpc/standard-server-fetch': 1.13.13 + '@orpc/standard-server-peer': 1.13.13 transitivePeerDependencies: - '@opentelemetry/api' - '@orpc/contract@1.13.9': + '@orpc/contract@1.13.13': dependencies: - '@orpc/client': 1.13.9 - '@orpc/shared': 1.13.9 + '@orpc/client': 1.13.13 + '@orpc/shared': 1.13.13 '@standard-schema/spec': 1.1.0 openapi-types: 12.1.3 transitivePeerDependencies: - '@opentelemetry/api' - '@orpc/openapi-client@1.13.9': + '@orpc/openapi-client@1.13.13': dependencies: - '@orpc/client': 1.13.9 - '@orpc/contract': 1.13.9 - '@orpc/shared': 1.13.9 - '@orpc/standard-server': 1.13.9 + '@orpc/client': 1.13.13 + '@orpc/contract': 1.13.13 + '@orpc/shared': 1.13.13 + '@orpc/standard-server': 1.13.13 transitivePeerDependencies: - '@opentelemetry/api' - '@orpc/shared@1.13.9': + '@orpc/shared@1.13.13': dependencies: radash: 12.1.1 - type-fest: 5.4.4 + type-fest: 5.5.0 - '@orpc/standard-server-fetch@1.13.9': + '@orpc/standard-server-fetch@1.13.13': dependencies: - '@orpc/shared': 1.13.9 - '@orpc/standard-server': 1.13.9 + '@orpc/shared': 1.13.13 + '@orpc/standard-server': 1.13.13 transitivePeerDependencies: - '@opentelemetry/api' - '@orpc/standard-server-peer@1.13.9': + '@orpc/standard-server-peer@1.13.13': dependencies: - '@orpc/shared': 1.13.9 - '@orpc/standard-server': 1.13.9 + '@orpc/shared': 1.13.13 + '@orpc/standard-server': 1.13.13 transitivePeerDependencies: - '@opentelemetry/api' - '@orpc/standard-server@1.13.9': + '@orpc/standard-server@1.13.13': dependencies: - '@orpc/shared': 1.13.9 + '@orpc/shared': 1.13.13 transitivePeerDependencies: - '@opentelemetry/api' - '@orpc/tanstack-query@1.13.9(@orpc/client@1.13.9)(@tanstack/query-core@5.95.0)': + '@orpc/tanstack-query@1.13.13(@orpc/client@1.13.13)(@tanstack/query-core@5.95.2)': dependencies: - '@orpc/client': 1.13.9 - '@orpc/shared': 1.13.9 - '@tanstack/query-core': 5.95.0 + '@orpc/client': 1.13.13 + '@orpc/shared': 1.13.13 + '@tanstack/query-core': 5.95.2 transitivePeerDependencies: - '@opentelemetry/api' '@ota-meshi/ast-token-store@0.3.0': {} - '@oxc-parser/binding-android-arm-eabi@0.120.0': + '@oxc-parser/binding-android-arm-eabi@0.121.0': optional: true - '@oxc-parser/binding-android-arm64@0.120.0': + '@oxc-parser/binding-android-arm64@0.121.0': optional: true - '@oxc-parser/binding-darwin-arm64@0.120.0': + '@oxc-parser/binding-darwin-arm64@0.121.0': optional: true - '@oxc-parser/binding-darwin-x64@0.120.0': + '@oxc-parser/binding-darwin-x64@0.121.0': optional: true - '@oxc-parser/binding-freebsd-x64@0.120.0': + '@oxc-parser/binding-freebsd-x64@0.121.0': optional: true - '@oxc-parser/binding-linux-arm-gnueabihf@0.120.0': + '@oxc-parser/binding-linux-arm-gnueabihf@0.121.0': optional: true - '@oxc-parser/binding-linux-arm-musleabihf@0.120.0': + '@oxc-parser/binding-linux-arm-musleabihf@0.121.0': optional: true - '@oxc-parser/binding-linux-arm64-gnu@0.120.0': + '@oxc-parser/binding-linux-arm64-gnu@0.121.0': optional: true - '@oxc-parser/binding-linux-arm64-musl@0.120.0': + '@oxc-parser/binding-linux-arm64-musl@0.121.0': optional: true - '@oxc-parser/binding-linux-ppc64-gnu@0.120.0': + '@oxc-parser/binding-linux-ppc64-gnu@0.121.0': optional: true - '@oxc-parser/binding-linux-riscv64-gnu@0.120.0': + '@oxc-parser/binding-linux-riscv64-gnu@0.121.0': optional: true - '@oxc-parser/binding-linux-riscv64-musl@0.120.0': + '@oxc-parser/binding-linux-riscv64-musl@0.121.0': optional: true - '@oxc-parser/binding-linux-s390x-gnu@0.120.0': + '@oxc-parser/binding-linux-s390x-gnu@0.121.0': optional: true - '@oxc-parser/binding-linux-x64-gnu@0.120.0': + '@oxc-parser/binding-linux-x64-gnu@0.121.0': optional: true - '@oxc-parser/binding-linux-x64-musl@0.120.0': + '@oxc-parser/binding-linux-x64-musl@0.121.0': optional: true - '@oxc-parser/binding-openharmony-arm64@0.120.0': + '@oxc-parser/binding-openharmony-arm64@0.121.0': optional: true - '@oxc-parser/binding-wasm32-wasi@0.120.0': + '@oxc-parser/binding-wasm32-wasi@0.121.0(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)': dependencies: - '@napi-rs/wasm-runtime': 1.1.1 + '@napi-rs/wasm-runtime': 1.1.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' optional: true - '@oxc-parser/binding-win32-arm64-msvc@0.120.0': + '@oxc-parser/binding-win32-arm64-msvc@0.121.0': optional: true - '@oxc-parser/binding-win32-ia32-msvc@0.120.0': + '@oxc-parser/binding-win32-ia32-msvc@0.121.0': optional: true - '@oxc-parser/binding-win32-x64-msvc@0.120.0': + '@oxc-parser/binding-win32-x64-msvc@0.121.0': optional: true - '@oxc-project/runtime@0.120.0': {} + '@oxc-project/runtime@0.121.0': {} - '@oxc-project/types@0.120.0': {} + '@oxc-project/types@0.121.0': {} + + '@oxc-project/types@0.122.0': {} '@oxc-resolver/binding-android-arm-eabi@11.19.1': optional: true @@ -9521,9 +10688,12 @@ snapshots: '@oxc-resolver/binding-openharmony-arm64@11.19.1': optional: true - '@oxc-resolver/binding-wasm32-wasi@11.19.1': + '@oxc-resolver/binding-wasm32-wasi@11.19.1(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)': dependencies: - '@napi-rs/wasm-runtime': 1.1.1 + '@napi-rs/wasm-runtime': 1.1.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' optional: true '@oxc-resolver/binding-win32-arm64-msvc@11.19.1': @@ -9535,136 +10705,136 @@ snapshots: '@oxc-resolver/binding-win32-x64-msvc@11.19.1': optional: true - '@oxfmt/binding-android-arm-eabi@0.41.0': + '@oxfmt/binding-android-arm-eabi@0.42.0': optional: true - '@oxfmt/binding-android-arm64@0.41.0': + '@oxfmt/binding-android-arm64@0.42.0': optional: true - '@oxfmt/binding-darwin-arm64@0.41.0': + '@oxfmt/binding-darwin-arm64@0.42.0': optional: true - '@oxfmt/binding-darwin-x64@0.41.0': + '@oxfmt/binding-darwin-x64@0.42.0': optional: true - '@oxfmt/binding-freebsd-x64@0.41.0': + '@oxfmt/binding-freebsd-x64@0.42.0': optional: true - '@oxfmt/binding-linux-arm-gnueabihf@0.41.0': + '@oxfmt/binding-linux-arm-gnueabihf@0.42.0': optional: true - '@oxfmt/binding-linux-arm-musleabihf@0.41.0': + '@oxfmt/binding-linux-arm-musleabihf@0.42.0': optional: true - '@oxfmt/binding-linux-arm64-gnu@0.41.0': + '@oxfmt/binding-linux-arm64-gnu@0.42.0': optional: true - '@oxfmt/binding-linux-arm64-musl@0.41.0': + '@oxfmt/binding-linux-arm64-musl@0.42.0': optional: true - '@oxfmt/binding-linux-ppc64-gnu@0.41.0': + '@oxfmt/binding-linux-ppc64-gnu@0.42.0': optional: true - '@oxfmt/binding-linux-riscv64-gnu@0.41.0': + '@oxfmt/binding-linux-riscv64-gnu@0.42.0': optional: true - '@oxfmt/binding-linux-riscv64-musl@0.41.0': + '@oxfmt/binding-linux-riscv64-musl@0.42.0': optional: true - '@oxfmt/binding-linux-s390x-gnu@0.41.0': + '@oxfmt/binding-linux-s390x-gnu@0.42.0': optional: true - '@oxfmt/binding-linux-x64-gnu@0.41.0': + '@oxfmt/binding-linux-x64-gnu@0.42.0': optional: true - '@oxfmt/binding-linux-x64-musl@0.41.0': + '@oxfmt/binding-linux-x64-musl@0.42.0': optional: true - '@oxfmt/binding-openharmony-arm64@0.41.0': + '@oxfmt/binding-openharmony-arm64@0.42.0': optional: true - '@oxfmt/binding-win32-arm64-msvc@0.41.0': + '@oxfmt/binding-win32-arm64-msvc@0.42.0': optional: true - '@oxfmt/binding-win32-ia32-msvc@0.41.0': + '@oxfmt/binding-win32-ia32-msvc@0.42.0': optional: true - '@oxfmt/binding-win32-x64-msvc@0.41.0': + '@oxfmt/binding-win32-x64-msvc@0.42.0': optional: true - '@oxlint-tsgolint/darwin-arm64@0.17.1': + '@oxlint-tsgolint/darwin-arm64@0.17.3': optional: true - '@oxlint-tsgolint/darwin-x64@0.17.1': + '@oxlint-tsgolint/darwin-x64@0.17.3': optional: true - '@oxlint-tsgolint/linux-arm64@0.17.1': + '@oxlint-tsgolint/linux-arm64@0.17.3': optional: true - '@oxlint-tsgolint/linux-x64@0.17.1': + '@oxlint-tsgolint/linux-x64@0.17.3': optional: true - '@oxlint-tsgolint/win32-arm64@0.17.1': + '@oxlint-tsgolint/win32-arm64@0.17.3': optional: true - '@oxlint-tsgolint/win32-x64@0.17.1': + '@oxlint-tsgolint/win32-x64@0.17.3': optional: true - '@oxlint/binding-android-arm-eabi@1.56.0': + '@oxlint/binding-android-arm-eabi@1.57.0': optional: true - '@oxlint/binding-android-arm64@1.56.0': + '@oxlint/binding-android-arm64@1.57.0': optional: true - '@oxlint/binding-darwin-arm64@1.56.0': + '@oxlint/binding-darwin-arm64@1.57.0': optional: true - '@oxlint/binding-darwin-x64@1.56.0': + '@oxlint/binding-darwin-x64@1.57.0': optional: true - '@oxlint/binding-freebsd-x64@1.56.0': + '@oxlint/binding-freebsd-x64@1.57.0': optional: true - '@oxlint/binding-linux-arm-gnueabihf@1.56.0': + '@oxlint/binding-linux-arm-gnueabihf@1.57.0': optional: true - '@oxlint/binding-linux-arm-musleabihf@1.56.0': + '@oxlint/binding-linux-arm-musleabihf@1.57.0': optional: true - '@oxlint/binding-linux-arm64-gnu@1.56.0': + '@oxlint/binding-linux-arm64-gnu@1.57.0': optional: true - '@oxlint/binding-linux-arm64-musl@1.56.0': + '@oxlint/binding-linux-arm64-musl@1.57.0': optional: true - '@oxlint/binding-linux-ppc64-gnu@1.56.0': + '@oxlint/binding-linux-ppc64-gnu@1.57.0': optional: true - '@oxlint/binding-linux-riscv64-gnu@1.56.0': + '@oxlint/binding-linux-riscv64-gnu@1.57.0': optional: true - '@oxlint/binding-linux-riscv64-musl@1.56.0': + '@oxlint/binding-linux-riscv64-musl@1.57.0': optional: true - '@oxlint/binding-linux-s390x-gnu@1.56.0': + '@oxlint/binding-linux-s390x-gnu@1.57.0': optional: true - '@oxlint/binding-linux-x64-gnu@1.56.0': + '@oxlint/binding-linux-x64-gnu@1.57.0': optional: true - '@oxlint/binding-linux-x64-musl@1.56.0': + '@oxlint/binding-linux-x64-musl@1.57.0': optional: true - '@oxlint/binding-openharmony-arm64@1.56.0': + '@oxlint/binding-openharmony-arm64@1.57.0': optional: true - '@oxlint/binding-win32-arm64-msvc@1.56.0': + '@oxlint/binding-win32-arm64-msvc@1.57.0': optional: true - '@oxlint/binding-win32-ia32-msvc@1.56.0': + '@oxlint/binding-win32-ia32-msvc@1.57.0': optional: true - '@oxlint/binding-win32-x64-msvc@1.56.0': + '@oxlint/binding-win32-x64-msvc@1.57.0': optional: true '@parcel/watcher-android-arm64@2.5.6': @@ -9730,6 +10900,10 @@ snapshots: '@pkgr/core@0.2.9': {} + '@playwright/test@1.58.2': + dependencies: + playwright: 1.58.2 + '@polka/url@1.0.0-next.29': {} '@preact/signals-core@1.14.0': {} @@ -9902,7 +11076,7 @@ snapshots: '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-types/shared': 3.33.1(react@19.2.4) - '@swc/helpers': 0.5.19 + '@swc/helpers': 0.5.20 clsx: 2.1.1 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) @@ -9913,13 +11087,13 @@ snapshots: '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-stately/flags': 3.1.2 '@react-types/shared': 3.33.1(react@19.2.4) - '@swc/helpers': 0.5.19 + '@swc/helpers': 0.5.20 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) '@react-aria/ssr@3.9.10(react@19.2.4)': dependencies: - '@swc/helpers': 0.5.19 + '@swc/helpers': 0.5.20 react: 19.2.4 '@react-aria/utils@3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': @@ -9928,18 +11102,18 @@ snapshots: '@react-stately/flags': 3.1.2 '@react-stately/utils': 3.11.0(react@19.2.4) '@react-types/shared': 3.33.1(react@19.2.4) - '@swc/helpers': 0.5.19 + '@swc/helpers': 0.5.20 clsx: 2.1.1 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) '@react-stately/flags@3.1.2': dependencies: - '@swc/helpers': 0.5.19 + '@swc/helpers': 0.5.20 '@react-stately/utils@3.11.0(react@19.2.4)': dependencies: - '@swc/helpers': 0.5.19 + '@swc/helpers': 0.5.20 react: 19.2.4 '@react-types/shared@3.33.1(react@19.2.4)': @@ -10032,6 +11206,58 @@ snapshots: '@rgrove/parse-xml@4.2.0': {} + '@rolldown/binding-android-arm64@1.0.0-rc.12': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.0-rc.12': + optional: true + + '@rolldown/binding-darwin-x64@1.0.0-rc.12': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.0-rc.12': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.12': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.0-rc.12(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)': + dependencies: + '@napi-rs/wasm-runtime': 1.1.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.12': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.12': + optional: true + + '@rolldown/pluginutils@1.0.0-rc.12': {} + '@rolldown/pluginutils@1.0.0-rc.5': {} '@rolldown/pluginutils@1.0.0-rc.7': {} @@ -10126,38 +11352,38 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.59.0': optional: true - '@sentry-internal/browser-utils@10.45.0': + '@sentry-internal/browser-utils@10.46.0': dependencies: - '@sentry/core': 10.45.0 + '@sentry/core': 10.46.0 - '@sentry-internal/feedback@10.45.0': + '@sentry-internal/feedback@10.46.0': dependencies: - '@sentry/core': 10.45.0 + '@sentry/core': 10.46.0 - '@sentry-internal/replay-canvas@10.45.0': + '@sentry-internal/replay-canvas@10.46.0': dependencies: - '@sentry-internal/replay': 10.45.0 - '@sentry/core': 10.45.0 + '@sentry-internal/replay': 10.46.0 + '@sentry/core': 10.46.0 - '@sentry-internal/replay@10.45.0': + '@sentry-internal/replay@10.46.0': dependencies: - '@sentry-internal/browser-utils': 10.45.0 - '@sentry/core': 10.45.0 + '@sentry-internal/browser-utils': 10.46.0 + '@sentry/core': 10.46.0 - '@sentry/browser@10.45.0': + '@sentry/browser@10.46.0': dependencies: - '@sentry-internal/browser-utils': 10.45.0 - '@sentry-internal/feedback': 10.45.0 - '@sentry-internal/replay': 10.45.0 - '@sentry-internal/replay-canvas': 10.45.0 - '@sentry/core': 10.45.0 + '@sentry-internal/browser-utils': 10.46.0 + '@sentry-internal/feedback': 10.46.0 + '@sentry-internal/replay': 10.46.0 + '@sentry-internal/replay-canvas': 10.46.0 + '@sentry/core': 10.46.0 - '@sentry/core@10.45.0': {} + '@sentry/core@10.46.0': {} - '@sentry/react@10.45.0(react@19.2.4)': + '@sentry/react@10.46.0(react@19.2.4)': dependencies: - '@sentry/browser': 10.45.0 - '@sentry/core': 10.45.0 + '@sentry/browser': 10.46.0 + '@sentry/core': 10.46.0 react: 19.2.4 '@shuding/opentype.js@1.4.0-beta.0': @@ -10205,15 +11431,15 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@storybook/addon-docs@10.3.1(@types/react@19.2.14)(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(rollup@4.59.0)(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3))': + '@storybook/addon-docs@10.3.3(@types/react@19.2.14)(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(rollup@4.59.0)(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3))': dependencies: '@mdx-js/react': 3.1.1(@types/react@19.2.14)(react@19.2.4) - '@storybook/csf-plugin': 10.3.1(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(rollup@4.59.0)(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3)) + '@storybook/csf-plugin': 10.3.3(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(rollup@4.59.0)(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3)) '@storybook/icons': 2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@storybook/react-dom-shim': 10.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + '@storybook/react-dom-shim': 10.3.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - storybook: 10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook: 10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) ts-dedent: 2.2.0 transitivePeerDependencies: - '@types/react' @@ -10222,41 +11448,41 @@ snapshots: - vite - webpack - '@storybook/addon-links@10.3.1(react@19.2.4)(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': + '@storybook/addon-links@10.3.3(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': dependencies: '@storybook/global': 5.0.0 - storybook: 10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook: 10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) optionalDependencies: react: 19.2.4 - '@storybook/addon-onboarding@10.3.1(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': + '@storybook/addon-onboarding@10.3.3(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': dependencies: - storybook: 10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook: 10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@storybook/addon-themes@10.3.1(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': + '@storybook/addon-themes@10.3.3(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': dependencies: - storybook: 10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook: 10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) ts-dedent: 2.2.0 - '@storybook/builder-vite@10.3.1(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(rollup@4.59.0)(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3))': + '@storybook/builder-vite@10.3.3(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(rollup@4.59.0)(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3))': dependencies: - '@storybook/csf-plugin': 10.3.1(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(rollup@4.59.0)(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3)) - storybook: 10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@storybook/csf-plugin': 10.3.3(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(rollup@4.59.0)(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3)) + storybook: 10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) ts-dedent: 2.2.0 - vite: '@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' + vite: '@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' transitivePeerDependencies: - esbuild - rollup - webpack - '@storybook/csf-plugin@10.3.1(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(rollup@4.59.0)(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3))': + '@storybook/csf-plugin@10.3.3(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(rollup@4.59.0)(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3))': dependencies: - storybook: 10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook: 10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) unplugin: 2.3.11 optionalDependencies: esbuild: 0.27.2 rollup: 4.59.0 - vite: '@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' + vite: '@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' webpack: 5.105.4(esbuild@0.27.2)(uglify-js@3.19.3) '@storybook/global@5.0.0': {} @@ -10266,18 +11492,18 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@storybook/nextjs-vite@10.3.1(@babel/core@7.29.0)(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(next@16.2.1(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.59.0)(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3))': + '@storybook/nextjs-vite@10.3.3(@babel/core@7.29.0)(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(next@16.2.1(@babel/core@7.29.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.59.0)(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3))': dependencies: - '@storybook/builder-vite': 10.3.1(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(rollup@4.59.0)(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3)) - '@storybook/react': 10.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) - '@storybook/react-vite': 10.3.1(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.59.0)(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3)) - next: 16.2.1(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0) + '@storybook/builder-vite': 10.3.3(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(rollup@4.59.0)(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3)) + '@storybook/react': 10.3.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) + '@storybook/react-vite': 10.3.3(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.59.0)(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3)) + next: 16.2.1(@babel/core@7.29.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - storybook: 10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook: 10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.2.4) - vite: '@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' - vite-plugin-storybook-nextjs: 3.2.3(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(next@16.2.1(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0))(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) + vite: '@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' + vite-plugin-storybook-nextjs: 3.2.4(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(next@16.2.1(@babel/core@7.29.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0))(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -10288,27 +11514,27 @@ snapshots: - supports-color - webpack - '@storybook/react-dom-shim@10.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': + '@storybook/react-dom-shim@10.3.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': dependencies: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - storybook: 10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook: 10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@storybook/react-vite@10.3.1(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.59.0)(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3))': + '@storybook/react-vite@10.3.3(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.59.0)(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3))': dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.4(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(typescript@5.9.3) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.4(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(typescript@5.9.3) '@rollup/pluginutils': 5.3.0(rollup@4.59.0) - '@storybook/builder-vite': 10.3.1(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(rollup@4.59.0)(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3)) - '@storybook/react': 10.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) + '@storybook/builder-vite': 10.3.3(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(rollup@4.59.0)(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3)) + '@storybook/react': 10.3.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) empathic: 2.0.0 magic-string: 0.30.21 react: 19.2.4 react-docgen: 8.0.3 react-dom: 19.2.4(react@19.2.4) resolve: 1.22.11 - storybook: 10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook: 10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) tsconfig-paths: 4.2.0 - vite: '@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' + vite: '@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' transitivePeerDependencies: - esbuild - rollup @@ -10316,15 +11542,15 @@ snapshots: - typescript - webpack - '@storybook/react@10.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)': + '@storybook/react@10.3.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)': dependencies: '@storybook/global': 5.0.0 - '@storybook/react-dom-shim': 10.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + '@storybook/react-dom-shim': 10.3.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) react: 19.2.4 react-docgen: 8.0.3 react-docgen-typescript: 2.4.0(typescript@5.9.3) react-dom: 19.2.4(react@19.2.4) - storybook: 10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook: 10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -10332,7 +11558,7 @@ snapshots: '@streamdown/math@1.0.2(react@19.2.4)': dependencies: - katex: 0.16.40 + katex: 0.16.44 react: 19.2.4 rehype-katex: 7.0.1 remark-math: 6.0.0 @@ -10342,7 +11568,7 @@ snapshots: '@stylistic/eslint-plugin@5.10.0(eslint@10.1.0(jiti@1.21.7))': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@10.1.0(jiti@1.21.7)) - '@typescript-eslint/types': 8.57.1 + '@typescript-eslint/types': 8.57.2 eslint: 10.1.0(jiti@1.21.7) eslint-visitor-keys: 4.2.1 espree: 10.4.0 @@ -10355,22 +11581,22 @@ snapshots: dependencies: tslib: 2.8.1 - '@swc/helpers@0.5.19': + '@swc/helpers@0.5.20': dependencies: tslib: 2.8.1 - '@t3-oss/env-core@0.13.11(typescript@5.9.3)(valibot@1.3.0(typescript@5.9.3))(zod@4.3.6)': + '@t3-oss/env-core@0.13.11(typescript@5.9.3)(valibot@1.3.1(typescript@5.9.3))(zod@4.3.6)': optionalDependencies: typescript: 5.9.3 - valibot: 1.3.0(typescript@5.9.3) + valibot: 1.3.1(typescript@5.9.3) zod: 4.3.6 - '@t3-oss/env-nextjs@0.13.11(typescript@5.9.3)(valibot@1.3.0(typescript@5.9.3))(zod@4.3.6)': + '@t3-oss/env-nextjs@0.13.11(typescript@5.9.3)(valibot@1.3.1(typescript@5.9.3))(zod@4.3.6)': dependencies: - '@t3-oss/env-core': 0.13.11(typescript@5.9.3)(valibot@1.3.0(typescript@5.9.3))(zod@4.3.6) + '@t3-oss/env-core': 0.13.11(typescript@5.9.3)(valibot@1.3.1(typescript@5.9.3))(zod@4.3.6) optionalDependencies: typescript: 5.9.3 - valibot: 1.3.0(typescript@5.9.3) + valibot: 1.3.1(typescript@5.9.3) zod: 4.3.6 '@tailwindcss/typography@0.5.19(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.3))': @@ -10422,9 +11648,9 @@ snapshots: - csstype - utf-8-validate - '@tanstack/eslint-plugin-query@5.95.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3)': + '@tanstack/eslint-plugin-query@5.95.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3)': dependencies: - '@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) eslint: 10.1.0(jiti@1.21.7) optionalDependencies: typescript: 5.9.3 @@ -10435,7 +11661,7 @@ snapshots: dependencies: '@tanstack/devtools-event-client': 0.4.3 '@tanstack/pacer-lite': 0.1.1 - '@tanstack/store': 0.9.2 + '@tanstack/store': 0.9.3 '@tanstack/form-devtools@0.2.19(@types/react@19.2.14)(csstype@3.2.3)(react@19.2.4)(solid-js@1.9.11)': dependencies: @@ -10455,9 +11681,9 @@ snapshots: '@tanstack/pacer-lite@0.1.1': {} - '@tanstack/query-core@5.95.0': {} + '@tanstack/query-core@5.95.2': {} - '@tanstack/query-devtools@5.95.0': {} + '@tanstack/query-devtools@5.95.2': {} '@tanstack/react-devtools@0.10.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.11)': dependencies: @@ -10487,25 +11713,25 @@ snapshots: '@tanstack/react-form@1.28.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@tanstack/form-core': 1.28.5 - '@tanstack/react-store': 0.9.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-store': 0.9.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 transitivePeerDependencies: - react-dom - '@tanstack/react-query-devtools@5.95.0(@tanstack/react-query@5.95.0(react@19.2.4))(react@19.2.4)': + '@tanstack/react-query-devtools@5.95.2(@tanstack/react-query@5.95.2(react@19.2.4))(react@19.2.4)': dependencies: - '@tanstack/query-devtools': 5.95.0 - '@tanstack/react-query': 5.95.0(react@19.2.4) + '@tanstack/query-devtools': 5.95.2 + '@tanstack/react-query': 5.95.2(react@19.2.4) react: 19.2.4 - '@tanstack/react-query@5.95.0(react@19.2.4)': + '@tanstack/react-query@5.95.2(react@19.2.4)': dependencies: - '@tanstack/query-core': 5.95.0 + '@tanstack/query-core': 5.95.2 react: 19.2.4 - '@tanstack/react-store@0.9.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@tanstack/react-store@0.9.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@tanstack/store': 0.9.2 + '@tanstack/store': 0.9.3 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) use-sync-external-store: 1.6.0(react@19.2.4) @@ -10516,10 +11742,12 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@tanstack/store@0.9.2': {} + '@tanstack/store@0.9.3': {} '@tanstack/virtual-core@3.13.23': {} + '@teppeis/multimaps@3.0.0': {} + '@testing-library/dom@10.4.1': dependencies: '@babel/code-frame': 7.29.0 @@ -10571,7 +11799,7 @@ snapshots: '@tsslint/compat-eslint@3.0.2(jiti@1.21.7)(typescript@5.9.3)': dependencies: '@tsslint/types': 3.0.2 - '@typescript-eslint/parser': 8.57.1(eslint@9.27.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/parser': 8.57.2(eslint@9.27.0(jiti@1.21.7))(typescript@5.9.3) eslint: 9.27.0(jiti@1.21.7) transitivePeerDependencies: - jiti @@ -10582,7 +11810,7 @@ snapshots: dependencies: '@tsslint/types': 3.0.2 minimatch: 10.2.4 - ts-api-utils: 2.4.0(typescript@5.9.3) + ts-api-utils: 2.5.0(typescript@5.9.3) optionalDependencies: '@tsslint/compat-eslint': 3.0.2(jiti@1.21.7)(typescript@5.9.3) transitivePeerDependencies: @@ -10747,7 +11975,7 @@ snapshots: '@types/d3-transition': 3.0.9 '@types/d3-zoom': 3.0.8 - '@types/debug@4.1.12': + '@types/debug@4.1.13': dependencies: '@types/ms': 2.1.0 @@ -10805,6 +12033,8 @@ snapshots: dependencies: undici-types: 7.18.2 + '@types/normalize-package-data@2.4.4': {} + '@types/papaparse@5.5.2': dependencies: '@types/node': 25.5.0 @@ -10855,60 +12085,88 @@ snapshots: '@types/zen-observable@0.8.3': {} - '@typescript-eslint/eslint-plugin@8.57.1(@typescript-eslint/parser@8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.57.2(@typescript-eslint/parser@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.57.1 - '@typescript-eslint/type-utils': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.57.1 + '@typescript-eslint/parser': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.57.2 + '@typescript-eslint/type-utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.57.2 eslint: 10.1.0(jiti@1.21.7) ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.4.0(typescript@5.9.3) + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.57.2(@typescript-eslint/parser@8.57.2(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3))(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.57.1 - '@typescript-eslint/types': 8.57.1 - '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.57.1 - debug: 4.4.3 + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.57.2(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.57.2 + '@typescript-eslint/type-utils': 8.57.2(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.2(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.57.2 + eslint: 10.1.0(jiti@2.6.1) + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.57.2 + '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.57.2 + debug: 4.4.3(supports-color@8.1.1) eslint: 10.1.0(jiti@1.21.7) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.57.1(eslint@9.27.0(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/parser@8.57.2(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.57.1 - '@typescript-eslint/types': 8.57.1 - '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.57.1 - debug: 4.4.3 + '@typescript-eslint/scope-manager': 8.57.2 + '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.57.2 + debug: 4.4.3(supports-color@8.1.1) + eslint: 10.1.0(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.57.2(eslint@9.27.0(jiti@1.21.7))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.57.2 + '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.57.2 + debug: 4.4.3(supports-color@8.1.1) eslint: 9.27.0(jiti@1.21.7) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.57.1(typescript@5.9.3)': + '@typescript-eslint/project-service@8.57.2(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.57.1(typescript@5.9.3) - '@typescript-eslint/types': 8.57.1 - debug: 4.4.3 + '@typescript-eslint/tsconfig-utils': 8.57.2(typescript@5.9.3) + '@typescript-eslint/types': 8.57.2 + debug: 4.4.3(supports-color@8.1.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/rule-tester@8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/rule-tester@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3)': dependencies: - '@typescript-eslint/parser': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/parser': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) ajv: 6.14.0 eslint: 10.1.0(jiti@1.21.7) json-stable-stringify-without-jsonify: 1.0.1 @@ -10918,90 +12176,113 @@ snapshots: - supports-color - typescript - '@typescript-eslint/scope-manager@8.57.1': + '@typescript-eslint/scope-manager@8.57.2': dependencies: - '@typescript-eslint/types': 8.57.1 - '@typescript-eslint/visitor-keys': 8.57.1 + '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/visitor-keys': 8.57.2 - '@typescript-eslint/tsconfig-utils@8.57.1(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.57.2(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.57.1 - '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) - debug: 4.4.3 + '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + debug: 4.4.3(supports-color@8.1.1) eslint: 10.1.0(jiti@1.21.7) - ts-api-utils: 2.4.0(typescript@5.9.3) + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.57.1': {} - - '@typescript-eslint/typescript-estree@8.57.1(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.57.2(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.57.1(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.57.1(typescript@5.9.3) - '@typescript-eslint/types': 8.57.1 - '@typescript-eslint/visitor-keys': 8.57.1 - debug: 4.4.3 + '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.2(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3) + debug: 4.4.3(supports-color@8.1.1) + eslint: 10.1.0(jiti@2.6.1) + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.57.2': {} + + '@typescript-eslint/typescript-estree@8.57.2(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.57.2(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.57.2(typescript@5.9.3) + '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/visitor-keys': 8.57.2 + debug: 4.4.3(supports-color@8.1.1) minimatch: 10.2.4 semver: 7.7.4 tinyglobby: 0.2.15 - ts-api-utils: 2.4.0(typescript@5.9.3) + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/utils@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@10.1.0(jiti@1.21.7)) - '@typescript-eslint/scope-manager': 8.57.1 - '@typescript-eslint/types': 8.57.1 - '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.57.2 + '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.9.3) eslint: 10.1.0(jiti@1.21.7) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.57.1': + '@typescript-eslint/utils@8.57.2(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.57.1 + '@eslint-community/eslint-utils': 4.9.1(eslint@10.1.0(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.57.2 + '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.9.3) + eslint: 10.1.0(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.57.2': + dependencies: + '@typescript-eslint/types': 8.57.2 eslint-visitor-keys: 5.0.1 - '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260322.1': + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260329.1': optional: true - '@typescript/native-preview-darwin-x64@7.0.0-dev.20260322.1': + '@typescript/native-preview-darwin-x64@7.0.0-dev.20260329.1': optional: true - '@typescript/native-preview-linux-arm64@7.0.0-dev.20260322.1': + '@typescript/native-preview-linux-arm64@7.0.0-dev.20260329.1': optional: true - '@typescript/native-preview-linux-arm@7.0.0-dev.20260322.1': + '@typescript/native-preview-linux-arm@7.0.0-dev.20260329.1': optional: true - '@typescript/native-preview-linux-x64@7.0.0-dev.20260322.1': + '@typescript/native-preview-linux-x64@7.0.0-dev.20260329.1': optional: true - '@typescript/native-preview-win32-arm64@7.0.0-dev.20260322.1': + '@typescript/native-preview-win32-arm64@7.0.0-dev.20260329.1': optional: true - '@typescript/native-preview-win32-x64@7.0.0-dev.20260322.1': + '@typescript/native-preview-win32-x64@7.0.0-dev.20260329.1': optional: true - '@typescript/native-preview@7.0.0-dev.20260322.1': + '@typescript/native-preview@7.0.0-dev.20260329.1': optionalDependencies: - '@typescript/native-preview-darwin-arm64': 7.0.0-dev.20260322.1 - '@typescript/native-preview-darwin-x64': 7.0.0-dev.20260322.1 - '@typescript/native-preview-linux-arm': 7.0.0-dev.20260322.1 - '@typescript/native-preview-linux-arm64': 7.0.0-dev.20260322.1 - '@typescript/native-preview-linux-x64': 7.0.0-dev.20260322.1 - '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260322.1 - '@typescript/native-preview-win32-x64': 7.0.0-dev.20260322.1 + '@typescript/native-preview-darwin-arm64': 7.0.0-dev.20260329.1 + '@typescript/native-preview-darwin-x64': 7.0.0-dev.20260329.1 + '@typescript/native-preview-linux-arm': 7.0.0-dev.20260329.1 + '@typescript/native-preview-linux-arm64': 7.0.0-dev.20260329.1 + '@typescript/native-preview-linux-x64': 7.0.0-dev.20260329.1 + '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260329.1 + '@typescript/native-preview-win32-x64': 7.0.0-dev.20260329.1 '@ungap/structured-clone@1.3.0': {} @@ -11009,34 +12290,56 @@ snapshots: dependencies: unpic: 4.2.2 - '@unpic/react@1.0.2(next@16.2.1(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@unpic/react@1.0.2(next@16.2.1(@babel/core@7.29.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@unpic/core': 1.0.3 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) optionalDependencies: - next: 16.2.1(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0) + next: 16.2.1(@babel/core@7.29.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0) '@upsetjs/venn.js@2.0.0': optionalDependencies: d3-selection: 3.0.0 d3-transition: 3.0.1(d3-selection@3.0.0) - '@valibot/to-json-schema@1.6.0(valibot@1.3.0(typescript@5.9.3))': + '@valibot/to-json-schema@1.6.0(valibot@1.3.1(typescript@5.9.3))': dependencies: - valibot: 1.3.0(typescript@5.9.3) + valibot: 1.3.1(typescript@5.9.3) '@vercel/og@0.8.6': dependencies: '@resvg/resvg-wasm': 2.4.0 satori: 0.16.0 - '@vitejs/plugin-react@6.0.1(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))': + '@vitejs/devtools-kit@0.1.11(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(typescript@5.9.3)(ws@8.20.0)': + dependencies: + '@vitejs/devtools-rpc': 0.1.11(typescript@5.9.3)(ws@8.20.0) + birpc: 4.0.0 + ohash: 2.0.11 + vite: '@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' + transitivePeerDependencies: + - typescript + - ws + + '@vitejs/devtools-rpc@0.1.11(typescript@5.9.3)(ws@8.20.0)': + dependencies: + birpc: 4.0.0 + ohash: 2.0.11 + p-limit: 7.3.0 + structured-clone-es: 2.0.0 + valibot: 1.3.1(typescript@5.9.3) + optionalDependencies: + ws: 8.20.0 + transitivePeerDependencies: + - typescript + + '@vitejs/plugin-react@6.0.1(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.7 - vite: '@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' + vite: '@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' - '@vitejs/plugin-rsc@0.5.21(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(react-dom@19.2.4(react@19.2.4))(react-server-dom-webpack@19.2.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3)))(react@19.2.4)': + '@vitejs/plugin-rsc@0.5.21(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(react-dom@19.2.4(react@19.2.4))(react-server-dom-webpack@19.2.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3)))(react@19.2.4)': dependencies: '@rolldown/pluginutils': 1.0.0-rc.5 es-module-lexer: 2.0.0 @@ -11045,18 +12348,18 @@ snapshots: periscopic: 4.0.2 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - srvx: 0.11.12 + srvx: 0.11.13 strip-literal: 3.1.0 turbo-stream: 3.2.0 - vite: '@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' - vitefu: 1.1.2(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)) + vite: '@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' + vitefu: 1.1.2(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)) optionalDependencies: react-server-dom-webpack: 19.2.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3)) - '@vitest/coverage-v8@4.1.0(@voidzero-dev/vite-plus-test@0.1.13(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(jsdom@29.0.1(canvas@3.2.2))(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))': + '@vitest/coverage-v8@4.1.2(@voidzero-dev/vite-plus-test@0.1.14(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))': dependencies: '@bcoe/v8-coverage': 1.0.2 - '@vitest/utils': 4.1.0 + '@vitest/utils': 4.1.2 ast-v8-to-istanbul: 1.0.0 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 @@ -11065,16 +12368,31 @@ snapshots: obug: 2.1.1 std-env: 4.0.0 tinyrainbow: 3.1.0 - vitest: '@voidzero-dev/vite-plus-test@0.1.13(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(jsdom@29.0.1(canvas@3.2.2))(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' + vitest: '@voidzero-dev/vite-plus-test@0.1.14(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' - '@vitest/eslint-plugin@1.6.12(@voidzero-dev/vite-plus-test@0.1.13(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(jsdom@29.0.1(canvas@3.2.2))(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3)': + '@vitest/coverage-v8@4.1.2(@voidzero-dev/vite-plus-test@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.2)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3))': dependencies: - '@typescript-eslint/scope-manager': 8.57.1 - '@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@bcoe/v8-coverage': 1.0.2 + '@vitest/utils': 4.1.2 + ast-v8-to-istanbul: 1.0.0 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-reports: 3.2.0 + magicast: 0.5.2 + obug: 2.1.1 + std-env: 4.0.0 + tinyrainbow: 3.1.0 + vitest: '@voidzero-dev/vite-plus-test@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.2)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)' + + '@vitest/eslint-plugin@1.6.13(@typescript-eslint/eslint-plugin@8.57.2(@typescript-eslint/parser@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(@voidzero-dev/vite-plus-test@0.1.14(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.57.2 + '@typescript-eslint/utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) eslint: 10.1.0(jiti@1.21.7) optionalDependencies: + '@typescript-eslint/eslint-plugin': 8.57.2(@typescript-eslint/parser@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) typescript: 5.9.3 - vitest: '@voidzero-dev/vite-plus-test@0.1.13(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(jsdom@29.0.1(canvas@3.2.2))(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' + vitest: '@voidzero-dev/vite-plus-test@0.1.14(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' transitivePeerDependencies: - supports-color @@ -11090,7 +12408,7 @@ snapshots: dependencies: tinyrainbow: 2.0.0 - '@vitest/pretty-format@4.1.0': + '@vitest/pretty-format@4.1.2': dependencies: tinyrainbow: 3.1.0 @@ -11104,16 +12422,16 @@ snapshots: loupe: 3.2.1 tinyrainbow: 2.0.0 - '@vitest/utils@4.1.0': + '@vitest/utils@4.1.2': dependencies: - '@vitest/pretty-format': 4.1.0 + '@vitest/pretty-format': 4.1.2 convert-source-map: 2.0.0 tinyrainbow: 3.1.0 - '@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)': + '@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)': dependencies: - '@oxc-project/runtime': 0.120.0 - '@oxc-project/types': 0.120.0 + '@oxc-project/runtime': 0.121.0 + '@oxc-project/types': 0.122.0 lightningcss: 1.32.0 postcss: 8.5.8 optionalDependencies: @@ -11127,23 +12445,46 @@ snapshots: typescript: 5.9.3 yaml: 2.8.3 - '@voidzero-dev/vite-plus-darwin-arm64@0.1.13': + '@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)': + dependencies: + '@oxc-project/runtime': 0.121.0 + '@oxc-project/types': 0.122.0 + lightningcss: 1.32.0 + postcss: 8.5.8 + optionalDependencies: + '@types/node': 25.5.0 + esbuild: 0.27.2 + fsevents: 2.3.3 + jiti: 2.6.1 + sass: 1.98.0 + terser: 5.46.1 + tsx: 4.21.0 + typescript: 5.9.3 + yaml: 2.8.3 + + '@voidzero-dev/vite-plus-darwin-arm64@0.1.14': optional: true - '@voidzero-dev/vite-plus-darwin-x64@0.1.13': + '@voidzero-dev/vite-plus-darwin-x64@0.1.14': optional: true - '@voidzero-dev/vite-plus-linux-arm64-gnu@0.1.13': + '@voidzero-dev/vite-plus-linux-arm64-gnu@0.1.14': optional: true - '@voidzero-dev/vite-plus-linux-x64-gnu@0.1.13': + '@voidzero-dev/vite-plus-linux-arm64-musl@0.1.14': optional: true - '@voidzero-dev/vite-plus-test@0.1.13(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(jsdom@29.0.1(canvas@3.2.2))(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)': + '@voidzero-dev/vite-plus-linux-x64-gnu@0.1.14': + optional: true + + '@voidzero-dev/vite-plus-linux-x64-musl@0.1.14': + optional: true + + '@voidzero-dev/vite-plus-test@0.1.14(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@voidzero-dev/vite-plus-core': 0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + '@voidzero-dev/vite-plus-core': 0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) es-module-lexer: 1.7.0 obug: 2.1.1 pixelmatch: 7.1.0 @@ -11153,12 +12494,11 @@ snapshots: tinybench: 2.9.0 tinyexec: 1.0.4 tinyglobby: 0.2.15 - vite: '@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' - ws: 8.19.0 + vite: '@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' + ws: 8.20.0 optionalDependencies: '@types/node': 25.5.0 happy-dom: 20.8.9 - jsdom: 29.0.1(canvas@3.2.2) transitivePeerDependencies: - '@arethetypeswrong/core' - '@tsdown/css' @@ -11180,10 +12520,50 @@ snapshots: - utf-8-validate - yaml - '@voidzero-dev/vite-plus-win32-arm64-msvc@0.1.13': + '@voidzero-dev/vite-plus-test@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.2)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@voidzero-dev/vite-plus-core': 0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + es-module-lexer: 1.7.0 + obug: 2.1.1 + pixelmatch: 7.1.0 + pngjs: 7.0.0 + sirv: 3.0.2 + std-env: 4.0.0 + tinybench: 2.9.0 + tinyexec: 1.0.4 + tinyglobby: 0.2.15 + vite: 8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.2)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + ws: 8.20.0 + optionalDependencies: + '@types/node': 25.5.0 + happy-dom: 20.8.9 + transitivePeerDependencies: + - '@arethetypeswrong/core' + - '@tsdown/css' + - '@tsdown/exe' + - '@vitejs/devtools' + - bufferutil + - esbuild + - jiti + - less + - publint + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - typescript + - unplugin-unused + - utf-8-validate + - yaml + + '@voidzero-dev/vite-plus-win32-arm64-msvc@0.1.14': optional: true - '@voidzero-dev/vite-plus-win32-x64-msvc@0.1.13': + '@voidzero-dev/vite-plus-win32-x64-msvc@0.1.14': optional: true '@volar/language-core@2.4.28': @@ -11200,37 +12580,37 @@ snapshots: path-browserify: 1.0.1 vscode-uri: 3.1.0 - '@vue/compiler-core@3.5.30': + '@vue/compiler-core@3.5.31': dependencies: '@babel/parser': 7.29.2 - '@vue/shared': 3.5.30 + '@vue/shared': 3.5.31 entities: 7.0.1 estree-walker: 2.0.2 source-map-js: 1.2.1 - '@vue/compiler-dom@3.5.30': + '@vue/compiler-dom@3.5.31': dependencies: - '@vue/compiler-core': 3.5.30 - '@vue/shared': 3.5.30 + '@vue/compiler-core': 3.5.31 + '@vue/shared': 3.5.31 - '@vue/compiler-sfc@3.5.30': + '@vue/compiler-sfc@3.5.31': dependencies: '@babel/parser': 7.29.2 - '@vue/compiler-core': 3.5.30 - '@vue/compiler-dom': 3.5.30 - '@vue/compiler-ssr': 3.5.30 - '@vue/shared': 3.5.30 + '@vue/compiler-core': 3.5.31 + '@vue/compiler-dom': 3.5.31 + '@vue/compiler-ssr': 3.5.31 + '@vue/shared': 3.5.31 estree-walker: 2.0.2 magic-string: 0.30.21 postcss: 8.5.8 source-map-js: 1.2.1 - '@vue/compiler-ssr@3.5.30': + '@vue/compiler-ssr@3.5.31': dependencies: - '@vue/compiler-dom': 3.5.30 - '@vue/shared': 3.5.30 + '@vue/compiler-dom': 3.5.31 + '@vue/shared': 3.5.31 - '@vue/shared@3.5.30': {} + '@vue/shared@3.5.31': {} '@webassemblyjs/ast@1.14.1': dependencies: @@ -11330,12 +12710,12 @@ snapshots: acorn@8.16.0: {} - agentation@2.3.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + agentation@3.0.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4): optionalDependencies: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - ahooks@3.9.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + ahooks@3.9.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: '@babel/runtime': 7.29.2 '@types/js-cookie': 3.0.6 @@ -11377,6 +12757,8 @@ snapshots: dependencies: environment: 1.1.0 + ansi-regex@4.1.1: {} + ansi-regex@5.0.1: {} ansi-regex@6.2.2: {} @@ -11414,6 +12796,12 @@ snapshots: aria-query@5.3.2: {} + assertion-error-formatter@3.0.0: + dependencies: + diff: 4.0.4 + pad-right: 0.2.2 + repeat-string: 1.6.1 + assertion-error@2.0.1: {} ast-types@0.16.1: @@ -11430,15 +12818,25 @@ snapshots: async@3.2.6: {} + asynckit@0.4.0: {} + autoprefixer@10.4.27(postcss@8.5.8): dependencies: browserslist: 4.28.1 - caniuse-lite: 1.0.30001780 + caniuse-lite: 1.0.30001781 fraction.js: 5.3.4 picocolors: 1.1.1 postcss: 8.5.8 postcss-value-parser: 4.2.0 + axios@1.14.0: + dependencies: + follow-redirects: 1.15.11 + form-data: 4.0.5 + proxy-from-env: 2.1.0 + transitivePeerDependencies: + - debug + bail@2.0.2: {} balanced-match@1.0.2: {} @@ -11452,18 +12850,13 @@ snapshots: base64-js@1.5.1: optional: true - baseline-browser-mapping@2.10.8: {} - - bidi-js@1.0.3: - dependencies: - require-from-string: 2.0.2 - optional: true + baseline-browser-mapping@2.10.12: {} binary-extensions@2.3.0: {} birecord@0.1.1: {} - birpc@2.9.0: {} + birpc@4.0.0: {} bl@4.1.0: dependencies: @@ -11478,7 +12871,7 @@ snapshots: dependencies: balanced-match: 1.0.2 - brace-expansion@5.0.4: + brace-expansion@5.0.5: dependencies: balanced-match: 4.0.4 @@ -11488,9 +12881,9 @@ snapshots: browserslist@4.28.1: dependencies: - baseline-browser-mapping: 2.10.8 - caniuse-lite: 1.0.30001780 - electron-to-chromium: 1.5.313 + baseline-browser-mapping: 2.10.12 + caniuse-lite: 1.0.30001781 + electron-to-chromium: 1.5.328 node-releases: 2.0.36 update-browserslist-db: 1.2.3(browserslist@4.28.1) @@ -11512,17 +12905,29 @@ snapshots: dependencies: run-applescript: 7.1.0 + bundle-require@5.1.0(esbuild@0.27.2): + dependencies: + esbuild: 0.27.2 + load-tsconfig: 0.2.5 + bytes@3.1.2: {} + cac@6.7.14: {} + cac@7.0.0: {} + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + callsites@3.1.0: {} camelcase-css@2.0.1: {} camelize@1.0.1: {} - caniuse-lite@1.0.30001780: {} + caniuse-lite@1.0.30001781: {} canvas@3.2.2: dependencies: @@ -11530,6 +12935,12 @@ snapshots: prebuild-install: 7.1.3 optional: true + capital-case@1.0.4: + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + upper-case-first: 2.0.2 + ccount@2.0.1: {} chai@5.3.3: @@ -11632,6 +13043,8 @@ snapshots: ci-info@4.4.0: {} + class-transformer@0.5.1: {} + class-variance-authority@0.7.1: dependencies: clsx: 2.1.1 @@ -11648,6 +13061,12 @@ snapshots: dependencies: restore-cursor: 5.1.0 + cli-table3@0.6.5: + dependencies: + string-width: 8.2.0 + optionalDependencies: + '@colors/colors': 1.5.0 + cli-truncate@5.2.0: dependencies: slice-ansi: 8.0.0 @@ -11691,10 +13110,18 @@ snapshots: colorette@2.0.20: {} + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + comma-separated-tokens@1.0.8: {} comma-separated-tokens@2.0.3: {} + commander@14.0.0: {} + + commander@14.0.2: {} + commander@14.0.3: {} commander@2.20.3: {} @@ -11707,12 +13134,16 @@ snapshots: comment-parser@1.4.5: {} + comment-parser@1.4.6: {} + compare-versions@6.1.1: {} confbox@0.1.8: {} confbox@0.2.4: {} + consola@3.4.2: {} + convert-source-map@2.0.0: {} copy-to-clipboard@3.3.3: @@ -11773,12 +13204,6 @@ snapshots: mdn-data: 2.0.30 source-map-js: 1.2.1 - css-tree@3.2.1: - dependencies: - mdn-data: 2.27.1 - source-map-js: 1.2.1 - optional: true - css-what@6.2.2: {} css.escape@1.5.1: {} @@ -11835,7 +13260,7 @@ snapshots: d3-delaunay@6.0.4: dependencies: - delaunator: 5.0.1 + delaunator: 5.1.0 d3-dispatch@3.0.1: {} @@ -11977,19 +13402,13 @@ snapshots: d3: 7.9.0 lodash-es: 4.17.23 - data-urls@7.0.0: - dependencies: - whatwg-mimetype: 5.0.0 - whatwg-url: 16.0.1 - transitivePeerDependencies: - - '@noble/hashes' - optional: true - dayjs@1.11.20: {} - debug@4.4.3: + debug@4.4.3(supports-color@8.1.1): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 8.1.1 decimal.js@10.6.0: {} @@ -12020,9 +13439,11 @@ snapshots: defu@6.1.4: {} - delaunator@5.0.1: + delaunator@5.1.0: dependencies: - robust-predicates: 3.0.2 + robust-predicates: 3.0.3 + + delayed-stream@1.0.0: {} dequal@2.0.3: {} @@ -12040,6 +13461,8 @@ snapshots: diff-sequences@29.6.3: {} + diff@4.0.4: {} + dlv@1.1.3: {} doctrine@3.0.0: @@ -12078,6 +13501,12 @@ snapshots: dotenv@16.6.1: {} + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + echarts-for-react@3.0.6(echarts@6.0.0)(react@19.2.4): dependencies: echarts: 6.0.0 @@ -12090,7 +13519,7 @@ snapshots: tslib: 2.3.0 zrender: 6.0.0 - electron-to-chromium@1.5.313: {} + electron-to-chromium@1.5.328: {} elkjs@0.11.1: {} @@ -12128,7 +13557,7 @@ snapshots: enhanced-resolve@5.20.1: dependencies: graceful-fs: 4.2.11 - tapable: 2.3.0 + tapable: 2.3.2 entities@4.5.0: {} @@ -12140,10 +13569,29 @@ snapshots: error-stack-parser-es@1.0.5: {} + error-stack-parser@2.1.4: + dependencies: + stackframe: 1.3.4 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + es-module-lexer@1.7.0: {} es-module-lexer@2.0.0: {} + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: '@nolyfill/hasown@1.0.44' + es-toolkit@1.45.1: {} esast-util-from-estree@2.0.0: @@ -12204,7 +13652,7 @@ snapshots: eslint: 10.1.0(jiti@1.21.7) semver: 7.7.4 - eslint-config-flat-gitignore@2.2.1(eslint@10.1.0(jiti@1.21.7)): + eslint-config-flat-gitignore@2.3.0(eslint@10.1.0(jiti@1.21.7)): dependencies: '@eslint/compat': 2.0.3(eslint@10.1.0(jiti@1.21.7)) eslint: 10.1.0(jiti@1.21.7) @@ -12238,30 +13686,30 @@ snapshots: dependencies: eslint: 10.1.0(jiti@1.21.7) - eslint-plugin-better-tailwindcss@4.3.2(eslint@10.1.0(jiti@1.21.7))(oxlint@1.56.0(oxlint-tsgolint@0.17.1))(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.3))(typescript@5.9.3): + eslint-plugin-better-tailwindcss@4.3.2(eslint@10.1.0(jiti@1.21.7))(oxlint@1.57.0(oxlint-tsgolint@0.17.3))(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.3))(typescript@5.9.3): dependencies: '@eslint/css-tree': 3.6.9 - '@valibot/to-json-schema': 1.6.0(valibot@1.3.0(typescript@5.9.3)) + '@valibot/to-json-schema': 1.6.0(valibot@1.3.1(typescript@5.9.3)) enhanced-resolve: 5.20.1 jiti: 2.6.1 synckit: 0.11.12 tailwind-csstree: 0.1.5 tailwindcss: 3.4.19(tsx@4.21.0)(yaml@2.8.3) tsconfig-paths-webpack-plugin: 4.2.0 - valibot: 1.3.0(typescript@5.9.3) + valibot: 1.3.1(typescript@5.9.3) optionalDependencies: eslint: 10.1.0(jiti@1.21.7) - oxlint: 1.56.0(oxlint-tsgolint@0.17.1) + oxlint: 1.57.0(oxlint-tsgolint@0.17.3) transitivePeerDependencies: - '@eslint/css' - typescript - eslint-plugin-command@3.5.2(@typescript-eslint/rule-tester@8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(@typescript-eslint/typescript-estree@8.57.1(typescript@5.9.3))(@typescript-eslint/utils@8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.1.0(jiti@1.21.7)): + eslint-plugin-command@3.5.2(@typescript-eslint/rule-tester@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(@typescript-eslint/typescript-estree@8.57.2(typescript@5.9.3))(@typescript-eslint/utils@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.1.0(jiti@1.21.7)): dependencies: '@es-joy/jsdoccomment': 0.84.0 - '@typescript-eslint/rule-tester': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/rule-tester': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) eslint: 10.1.0(jiti@1.21.7) eslint-plugin-depend@1.5.0(eslint@10.1.0(jiti@1.21.7)): @@ -12286,13 +13734,13 @@ snapshots: dependencies: eslint: 10.1.0(jiti@1.21.7) - eslint-plugin-jsdoc@62.8.0(eslint@10.1.0(jiti@1.21.7)): + eslint-plugin-jsdoc@62.8.1(eslint@10.1.0(jiti@1.21.7)): dependencies: '@es-joy/jsdoccomment': 0.84.0 '@es-joy/resolve.exports': 1.2.0 are-docs-informative: 0.0.2 comment-parser: 1.4.5 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) escape-string-regexp: 4.0.0 eslint: 10.1.0(jiti@1.21.7) espree: 11.2.0 @@ -12358,7 +13806,7 @@ snapshots: eslint-plugin-no-barrel-files@1.2.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3): dependencies: - '@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) transitivePeerDependencies: - eslint - supports-color @@ -12368,7 +13816,7 @@ snapshots: eslint-plugin-perfectionist@5.7.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3): dependencies: - '@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) eslint: 10.1.0(jiti@1.21.7) natural-orderby: 5.0.0 transitivePeerDependencies: @@ -12392,9 +13840,9 @@ snapshots: '@eslint-react/core': 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) '@eslint-react/shared': 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) '@eslint-react/var': 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.57.1 - '@typescript-eslint/types': 8.57.1 - '@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.57.2 + '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) compare-versions: 6.1.1 eslint: 10.1.0(jiti@1.21.7) ts-pattern: 5.9.0 @@ -12419,10 +13867,10 @@ snapshots: '@eslint-react/core': 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) '@eslint-react/shared': 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) '@eslint-react/var': 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.57.1 - '@typescript-eslint/type-utils': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/types': 8.57.1 - '@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.57.2 + '@typescript-eslint/type-utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) compare-versions: 6.1.1 eslint: 10.1.0(jiti@1.21.7) string-ts: 2.3.1 @@ -12440,10 +13888,10 @@ snapshots: '@eslint-react/ast': 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) '@eslint-react/shared': 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) '@eslint-react/var': 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.57.1 - '@typescript-eslint/type-utils': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/types': 8.57.1 - '@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.57.2 + '@typescript-eslint/type-utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) eslint: 10.1.0(jiti@1.21.7) ts-pattern: 5.9.0 typescript: 5.9.3 @@ -12456,9 +13904,9 @@ snapshots: '@eslint-react/core': 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) '@eslint-react/shared': 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) '@eslint-react/var': 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.57.1 - '@typescript-eslint/types': 8.57.1 - '@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.57.2 + '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) birecord: 0.1.1 eslint: 10.1.0(jiti@1.21.7) ts-pattern: 5.9.0 @@ -12472,14 +13920,14 @@ snapshots: '@eslint-react/core': 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) '@eslint-react/shared': 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) '@eslint-react/var': 3.0.0(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.57.1 - '@typescript-eslint/type-utils': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/types': 8.57.1 - '@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.57.2 + '@typescript-eslint/type-utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) compare-versions: 6.1.1 eslint: 10.1.0(jiti@1.21.7) string-ts: 2.3.1 - ts-api-utils: 2.4.0(typescript@5.9.3) + ts-api-utils: 2.5.0(typescript@5.9.3) ts-pattern: 5.9.0 typescript: 5.9.3 transitivePeerDependencies: @@ -12489,7 +13937,7 @@ snapshots: dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@10.1.0(jiti@1.21.7)) '@eslint-community/regexpp': 4.12.2 - comment-parser: 1.4.5 + comment-parser: 1.4.6 eslint: 10.1.0(jiti@1.21.7) jsdoc-type-pratt-parser: 7.1.1 refa: 0.12.1 @@ -12509,14 +13957,14 @@ snapshots: minimatch: 10.2.4 scslre: 0.3.0 semver: 7.7.4 - ts-api-utils: 2.4.0(typescript@5.9.3) + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 - eslint-plugin-storybook@10.3.1(eslint@10.1.0(jiti@1.21.7))(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3): + eslint-plugin-storybook@10.3.3(eslint@10.1.0(jiti@1.21.7))(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3): dependencies: - '@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) eslint: 10.1.0(jiti@1.21.7) - storybook: 10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook: 10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) transitivePeerDependencies: - supports-color - typescript @@ -12526,7 +13974,7 @@ snapshots: '@eslint/core': 1.1.1 '@eslint/plugin-kit': 0.6.1 '@ota-meshi/ast-token-store': 0.3.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) eslint: 10.1.0(jiti@1.21.7) toml-eslint-parser: 1.0.3 transitivePeerDependencies: @@ -12552,13 +14000,13 @@ snapshots: semver: 7.7.4 strip-indent: 4.1.1 - eslint-plugin-unused-imports@4.4.1(@typescript-eslint/eslint-plugin@8.57.1(@typescript-eslint/parser@8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.1.0(jiti@1.21.7)): + eslint-plugin-unused-imports@4.4.1(@typescript-eslint/eslint-plugin@8.57.2(@typescript-eslint/parser@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.1.0(jiti@1.21.7)): dependencies: eslint: 10.1.0(jiti@1.21.7) optionalDependencies: - '@typescript-eslint/eslint-plugin': 8.57.1(@typescript-eslint/parser@8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.57.2(@typescript-eslint/parser@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) - eslint-plugin-vue@10.8.0(@stylistic/eslint-plugin@5.10.0(eslint@10.1.0(jiti@1.21.7)))(@typescript-eslint/parser@8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.1.0(jiti@1.21.7))(vue-eslint-parser@10.4.0(eslint@10.1.0(jiti@1.21.7))): + eslint-plugin-vue@10.8.0(@stylistic/eslint-plugin@5.10.0(eslint@10.1.0(jiti@1.21.7)))(@typescript-eslint/parser@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.1.0(jiti@1.21.7))(vue-eslint-parser@10.4.0(eslint@10.1.0(jiti@1.21.7))): dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@10.1.0(jiti@1.21.7)) eslint: 10.1.0(jiti@1.21.7) @@ -12570,14 +14018,14 @@ snapshots: xml-name-validator: 4.0.0 optionalDependencies: '@stylistic/eslint-plugin': 5.10.0(eslint@10.1.0(jiti@1.21.7)) - '@typescript-eslint/parser': 8.57.1(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/parser': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.9.3) eslint-plugin-yml@3.3.1(eslint@10.1.0(jiti@1.21.7)): dependencies: '@eslint/core': 1.1.1 '@eslint/plugin-kit': 0.6.1 '@ota-meshi/ast-token-store': 0.3.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) diff-sequences: 29.6.3 escape-string-regexp: 5.0.0 eslint: 10.1.0(jiti@1.21.7) @@ -12586,9 +14034,9 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-processor-vue-blocks@2.0.0(@vue/compiler-sfc@3.5.30)(eslint@10.1.0(jiti@1.21.7)): + eslint-processor-vue-blocks@2.0.0(@vue/compiler-sfc@3.5.31)(eslint@10.1.0(jiti@1.21.7)): dependencies: - '@vue/compiler-sfc': 3.5.30 + '@vue/compiler-sfc': 3.5.31 eslint: 10.1.0(jiti@1.21.7) eslint-scope@5.1.1: @@ -12628,7 +14076,7 @@ snapshots: '@types/estree': 1.0.8 ajv: 6.14.0 cross-spawn: 7.0.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) escape-string-regexp: 4.0.0 eslint-scope: 9.1.2 eslint-visitor-keys: 5.0.1 @@ -12651,6 +14099,43 @@ snapshots: transitivePeerDependencies: - supports-color + eslint@10.1.0(jiti@2.6.1): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@10.1.0(jiti@2.6.1)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.23.3 + '@eslint/config-helpers': 0.5.3 + '@eslint/core': 1.1.1 + '@eslint/plugin-kit': 0.6.1 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + ajv: 6.14.0 + cross-spawn: 7.0.6 + debug: 4.4.3(supports-color@8.1.1) + escape-string-regexp: 4.0.0 + eslint-scope: 9.1.2 + eslint-visitor-keys: 5.0.1 + espree: 11.2.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + minimatch: 10.2.4 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.6.1 + transitivePeerDependencies: + - supports-color + eslint@9.27.0(jiti@1.21.7): dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.27.0(jiti@1.21.7)) @@ -12669,7 +14154,7 @@ snapshots: ajv: 6.14.0 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) escape-string-regexp: 4.0.0 eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 @@ -12771,7 +14256,7 @@ snapshots: extract-zip@2.0.1: dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) get-stream: 5.2.0 yauzl: 3.2.1 optionalDependencies: @@ -12827,6 +14312,10 @@ snapshots: fflate@0.7.4: {} + figures@3.2.0: + dependencies: + escape-string-regexp: 1.0.5 + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -12844,6 +14333,12 @@ snapshots: locate-path: 6.0.0 path-exists: 4.0.0 + fix-dts-default-cjs-exports@1.0.1: + dependencies: + magic-string: 0.30.21 + mlly: 1.8.2 + rollup: 4.59.0 + flat-cache@4.0.1: dependencies: flatted: 3.4.2 @@ -12851,6 +14346,16 @@ snapshots: flatted@3.4.2: {} + follow-redirects@1.15.11: {} + + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: '@nolyfill/hasown@1.0.44' + mime-types: 2.1.35 + format@0.2.2: {} formatly@0.3.0: @@ -12871,9 +14376,14 @@ snapshots: fs-constants@1.0.0: optional: true + fsevents@2.3.2: + optional: true + fsevents@2.3.3: optional: true + function-bind@1.1.2: {} + functional-red-black-tree@1.0.1: {} fzf@0.5.2: {} @@ -12882,8 +14392,26 @@ snapshots: get-east-asian-width@1.5.0: {} + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: '@nolyfill/hasown@1.0.44' + math-intrinsics: 1.1.0 + get-nonce@1.0.1: {} + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + get-stream@5.2.0: dependencies: pump: 3.0.4 @@ -12913,6 +14441,10 @@ snapshots: minipass: 7.1.3 path-scurry: 2.0.2 + global-dirs@3.0.1: + dependencies: + ini: 2.0.0 + globals@14.0.0: {} globals@15.15.0: {} @@ -12927,6 +14459,8 @@ snapshots: dependencies: csstype: 3.2.3 + gopd@1.2.0: {} + graceful-fs@4.2.11: {} hachure-fill@0.5.2: {} @@ -12943,8 +14477,18 @@ snapshots: - bufferutil - utf-8-validate + has-ansi@4.0.1: + dependencies: + ansi-regex: 4.1.1 + has-flag@4.0.0: {} + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + hast-util-from-dom@5.0.1: dependencies: '@types/hast': 3.0.4 @@ -13100,14 +14644,11 @@ snapshots: highlightjs-vue@1.0.0: {} - hono@4.12.8: {} + hono@4.12.9: {} - html-encoding-sniffer@6.0.0: + hosted-git-info@9.0.2: dependencies: - '@exodus/bytes': 1.15.0 - transitivePeerDependencies: - - '@noble/hashes' - optional: true + lru-cache: 11.2.7 html-entities@2.6.0: {} @@ -13136,7 +14677,7 @@ snapshots: dependencies: '@babel/runtime': 7.29.2 - i18next@25.10.4(typescript@5.9.3): + i18next@25.10.10(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 optionalDependencies: @@ -13182,12 +14723,16 @@ snapshots: indent-string@5.0.0: {} + index-to-position@1.2.0: {} + inherits@2.0.4: optional: true ini@1.3.8: optional: true + ini@2.0.0: {} + inline-style-parser@0.2.7: {} internmap@1.0.1: {} @@ -13238,21 +14783,29 @@ snapshots: is-hexadecimal@2.0.1: {} + is-in-ssh@1.0.0: {} + is-inside-container@1.0.0: dependencies: is-docker: 3.0.0 + is-installed-globally@0.4.0: + dependencies: + global-dirs: 3.0.1 + is-path-inside: 3.0.3 + is-number@7.0.0: {} - is-plain-obj@4.1.0: {} + is-path-inside@3.0.3: {} - is-potential-custom-element-name@1.0.1: - optional: true + is-plain-obj@4.1.0: {} is-reference@3.0.3: dependencies: '@types/estree': 1.0.8 + is-stream@2.0.1: {} + is-wsl@3.1.1: dependencies: is-inside-container: 1.0.0 @@ -13284,13 +14837,15 @@ snapshots: jiti@2.6.1: {} - jotai@2.18.1(@babel/core@7.29.0)(@babel/template@7.28.6)(@types/react@19.2.14)(react@19.2.4): + jotai@2.19.0(@babel/core@7.29.0)(@babel/template@7.28.6)(@types/react@19.2.14)(react@19.2.4): optionalDependencies: '@babel/core': 7.29.0 '@babel/template': 7.28.6 '@types/react': 19.2.14 react: 19.2.4 + joycon@3.1.1: {} + js-audio-recorder@1.0.7: {} js-base64@3.7.8: {} @@ -13309,35 +14864,6 @@ snapshots: jsdoc-type-pratt-parser@7.1.1: {} - jsdom@29.0.1(canvas@3.2.2): - dependencies: - '@asamuzakjp/css-color': 5.1.1 - '@asamuzakjp/dom-selector': 7.0.4 - '@bramus/specificity': 2.4.2 - '@csstools/css-syntax-patches-for-csstree': 1.1.2(css-tree@3.2.1) - '@exodus/bytes': 1.15.0 - css-tree: 3.2.1 - data-urls: 7.0.0 - decimal.js: 10.6.0 - html-encoding-sniffer: 6.0.0 - is-potential-custom-element-name: 1.0.1 - lru-cache: 11.2.7 - parse5: 8.0.0 - saxes: 6.0.0 - symbol-tree: 3.2.4 - tough-cookie: 6.0.1 - undici: 7.24.6 - w3c-xmlserializer: 5.0.0 - webidl-conversions: 8.0.1 - whatwg-mimetype: 5.0.0 - whatwg-url: 16.0.1 - xml-name-validator: 5.0.0 - optionalDependencies: - canvas: 3.2.2 - transitivePeerDependencies: - - '@noble/hashes' - optional: true - jsesc@3.1.0: {} json-buffer@3.0.1: {} @@ -13368,7 +14894,7 @@ snapshots: jsx-ast-utils-x@0.1.0: {} - katex@0.16.40: + katex@0.16.44: dependencies: commander: 8.3.0 @@ -13378,7 +14904,7 @@ snapshots: khroma@2.1.0: {} - knip@6.0.2: + knip@6.1.0(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1): dependencies: '@nodelib/fs.walk': 1.2.8 fast-glob: 3.3.3 @@ -13386,8 +14912,8 @@ snapshots: get-tsconfig: 4.13.7 jiti: 2.6.1 minimist: 1.2.8 - oxc-parser: 0.120.0 - oxc-resolver: 11.19.1 + oxc-parser: 0.121.0(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1) + oxc-resolver: 11.19.1(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1) picocolors: 1.1.1 picomatch: 4.0.4 smol-toml: 1.6.1 @@ -13395,6 +14921,13 @@ snapshots: unbash: 2.2.0 yaml: 2.8.3 zod: 4.3.6 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + + knuth-shuffle-seeded@1.0.6: + dependencies: + seed-random: 2.2.0 kolorist@1.8.0: {} @@ -13513,11 +15046,13 @@ snapshots: rfdc: 1.4.1 wrap-ansi: 9.0.2 + load-tsconfig@0.2.5: {} + loader-runner@4.3.1: {} local-pkg@1.1.2: dependencies: - mlly: 1.8.1 + mlly: 1.8.2 pkg-types: 2.3.0 quansync: 0.2.11 @@ -13529,6 +15064,10 @@ snapshots: lodash.merge@4.6.2: {} + lodash.mergewith@4.6.2: {} + + lodash.sortby@4.7.0: {} + lodash@4.17.23: {} log-update@6.1.0: @@ -13547,6 +15086,10 @@ snapshots: loupe@3.2.1: {} + lower-case@2.0.2: + dependencies: + tslib: 2.8.1 + lowlight@1.20.0: dependencies: fault: 1.0.4 @@ -13584,7 +15127,9 @@ snapshots: marked@16.4.2: {} - marked@17.0.4: {} + marked@17.0.5: {} + + math-intrinsics@1.1.0: {} mdast-util-directive@3.1.0: dependencies: @@ -13797,9 +15342,6 @@ snapshots: mdn-data@2.23.0: {} - mdn-data@2.27.1: - optional: true - memoize-one@5.2.1: {} merge-stream@2.0.0: {} @@ -13821,7 +15363,7 @@ snapshots: dagre-d3-es: 7.0.14 dayjs: 1.11.20 dompurify: 3.3.2 - katex: 0.16.40 + katex: 0.16.44 khroma: 2.1.0 lodash-es: 4.17.23 marked: 16.4.2 @@ -13928,7 +15470,7 @@ snapshots: dependencies: '@types/katex': 0.16.8 devlop: 1.1.0 - katex: 0.16.40 + katex: 0.16.44 micromark-factory-space: 2.0.1 micromark-util-character: 2.1.1 micromark-util-symbol: 2.0.1 @@ -14101,8 +15643,8 @@ snapshots: micromark@4.0.2: dependencies: - '@types/debug': 4.1.12 - debug: 4.4.3 + '@types/debug': 4.1.13 + debug: 4.4.3(supports-color@8.1.1) decode-named-character-reference: 1.3.0 devlop: 1.1.0 micromark-core-commonmark: 2.0.3 @@ -14132,6 +15674,8 @@ snapshots: dependencies: mime-db: 1.52.0 + mime@3.0.0: {} + mime@4.1.0: {} mimic-function@5.0.1: {} @@ -14143,7 +15687,7 @@ snapshots: minimatch@10.2.4: dependencies: - brace-expansion: 5.0.4 + brace-expansion: 5.0.5 minimatch@3.1.5: dependencies: @@ -14162,7 +15706,9 @@ snapshots: mkdirp-classic@0.5.3: optional: true - mlly@1.8.1: + mkdirp@3.0.1: {} + + mlly@1.8.2: dependencies: acorn: 8.16.0 pathe: 2.0.3 @@ -14210,12 +15756,12 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - next@16.2.1(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0): + next@16.2.1(@babel/core@7.29.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0): dependencies: '@next/env': 16.2.1 '@swc/helpers': 0.5.15 - baseline-browser-mapping: 2.10.8 - caniuse-lite: 1.0.30001780 + baseline-browser-mapping: 2.10.12 + caniuse-lite: 1.0.30001781 postcss: 8.4.31 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) @@ -14229,12 +15775,18 @@ snapshots: '@next/swc-linux-x64-musl': 16.2.1 '@next/swc-win32-arm64-msvc': 16.2.1 '@next/swc-win32-x64-msvc': 16.2.1 + '@playwright/test': 1.58.2 sass: 1.98.0 sharp: 0.34.5 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros + no-case@3.0.4: + dependencies: + lower-case: 2.0.2 + tslib: 2.8.1 + node-abi@3.89.0: dependencies: semver: 7.7.4 @@ -14247,6 +15799,12 @@ snapshots: node-releases@2.0.36: {} + normalize-package-data@8.0.0: + dependencies: + hosted-git-info: 9.0.2 + semver: 7.7.4 + validate-npm-package-license: 3.0.4 + normalize-path@3.0.0: {} normalize-wheel@1.0.1: {} @@ -14255,12 +15813,12 @@ snapshots: dependencies: boolbase: 1.0.0 - nuqs@2.8.9(next@16.2.1(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0))(react@19.2.4): + nuqs@2.8.9(next@16.2.1(@babel/core@7.29.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0))(react@19.2.4): dependencies: '@standard-schema/spec': 1.0.0 react: 19.2.4 optionalDependencies: - next: 16.2.1(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0) + next: 16.2.1(@babel/core@7.29.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0) object-assign@4.1.1: {} @@ -14293,6 +15851,15 @@ snapshots: is-inside-container: 1.0.0 wsl-utils: 0.1.0 + open@11.0.0: + dependencies: + default-browser: 5.5.0 + define-lazy-prop: 3.0.0 + is-in-ssh: 1.0.0 + is-inside-container: 1.0.0 + powershell-utils: 0.1.0 + wsl-utils: 0.3.1 + openapi-types@12.1.3: {} optionator@0.9.4: @@ -14304,32 +15871,35 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 - oxc-parser@0.120.0: + oxc-parser@0.121.0(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1): dependencies: - '@oxc-project/types': 0.120.0 + '@oxc-project/types': 0.121.0 optionalDependencies: - '@oxc-parser/binding-android-arm-eabi': 0.120.0 - '@oxc-parser/binding-android-arm64': 0.120.0 - '@oxc-parser/binding-darwin-arm64': 0.120.0 - '@oxc-parser/binding-darwin-x64': 0.120.0 - '@oxc-parser/binding-freebsd-x64': 0.120.0 - '@oxc-parser/binding-linux-arm-gnueabihf': 0.120.0 - '@oxc-parser/binding-linux-arm-musleabihf': 0.120.0 - '@oxc-parser/binding-linux-arm64-gnu': 0.120.0 - '@oxc-parser/binding-linux-arm64-musl': 0.120.0 - '@oxc-parser/binding-linux-ppc64-gnu': 0.120.0 - '@oxc-parser/binding-linux-riscv64-gnu': 0.120.0 - '@oxc-parser/binding-linux-riscv64-musl': 0.120.0 - '@oxc-parser/binding-linux-s390x-gnu': 0.120.0 - '@oxc-parser/binding-linux-x64-gnu': 0.120.0 - '@oxc-parser/binding-linux-x64-musl': 0.120.0 - '@oxc-parser/binding-openharmony-arm64': 0.120.0 - '@oxc-parser/binding-wasm32-wasi': 0.120.0 - '@oxc-parser/binding-win32-arm64-msvc': 0.120.0 - '@oxc-parser/binding-win32-ia32-msvc': 0.120.0 - '@oxc-parser/binding-win32-x64-msvc': 0.120.0 + '@oxc-parser/binding-android-arm-eabi': 0.121.0 + '@oxc-parser/binding-android-arm64': 0.121.0 + '@oxc-parser/binding-darwin-arm64': 0.121.0 + '@oxc-parser/binding-darwin-x64': 0.121.0 + '@oxc-parser/binding-freebsd-x64': 0.121.0 + '@oxc-parser/binding-linux-arm-gnueabihf': 0.121.0 + '@oxc-parser/binding-linux-arm-musleabihf': 0.121.0 + '@oxc-parser/binding-linux-arm64-gnu': 0.121.0 + '@oxc-parser/binding-linux-arm64-musl': 0.121.0 + '@oxc-parser/binding-linux-ppc64-gnu': 0.121.0 + '@oxc-parser/binding-linux-riscv64-gnu': 0.121.0 + '@oxc-parser/binding-linux-riscv64-musl': 0.121.0 + '@oxc-parser/binding-linux-s390x-gnu': 0.121.0 + '@oxc-parser/binding-linux-x64-gnu': 0.121.0 + '@oxc-parser/binding-linux-x64-musl': 0.121.0 + '@oxc-parser/binding-openharmony-arm64': 0.121.0 + '@oxc-parser/binding-wasm32-wasi': 0.121.0(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1) + '@oxc-parser/binding-win32-arm64-msvc': 0.121.0 + '@oxc-parser/binding-win32-ia32-msvc': 0.121.0 + '@oxc-parser/binding-win32-x64-msvc': 0.121.0 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' - oxc-resolver@11.19.1: + oxc-resolver@11.19.1(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1): optionalDependencies: '@oxc-resolver/binding-android-arm-eabi': 11.19.1 '@oxc-resolver/binding-android-arm64': 11.19.1 @@ -14347,77 +15917,88 @@ snapshots: '@oxc-resolver/binding-linux-x64-gnu': 11.19.1 '@oxc-resolver/binding-linux-x64-musl': 11.19.1 '@oxc-resolver/binding-openharmony-arm64': 11.19.1 - '@oxc-resolver/binding-wasm32-wasi': 11.19.1 + '@oxc-resolver/binding-wasm32-wasi': 11.19.1(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1) '@oxc-resolver/binding-win32-arm64-msvc': 11.19.1 '@oxc-resolver/binding-win32-ia32-msvc': 11.19.1 '@oxc-resolver/binding-win32-x64-msvc': 11.19.1 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' - oxfmt@0.41.0: + oxfmt@0.42.0: dependencies: tinypool: 2.1.0 optionalDependencies: - '@oxfmt/binding-android-arm-eabi': 0.41.0 - '@oxfmt/binding-android-arm64': 0.41.0 - '@oxfmt/binding-darwin-arm64': 0.41.0 - '@oxfmt/binding-darwin-x64': 0.41.0 - '@oxfmt/binding-freebsd-x64': 0.41.0 - '@oxfmt/binding-linux-arm-gnueabihf': 0.41.0 - '@oxfmt/binding-linux-arm-musleabihf': 0.41.0 - '@oxfmt/binding-linux-arm64-gnu': 0.41.0 - '@oxfmt/binding-linux-arm64-musl': 0.41.0 - '@oxfmt/binding-linux-ppc64-gnu': 0.41.0 - '@oxfmt/binding-linux-riscv64-gnu': 0.41.0 - '@oxfmt/binding-linux-riscv64-musl': 0.41.0 - '@oxfmt/binding-linux-s390x-gnu': 0.41.0 - '@oxfmt/binding-linux-x64-gnu': 0.41.0 - '@oxfmt/binding-linux-x64-musl': 0.41.0 - '@oxfmt/binding-openharmony-arm64': 0.41.0 - '@oxfmt/binding-win32-arm64-msvc': 0.41.0 - '@oxfmt/binding-win32-ia32-msvc': 0.41.0 - '@oxfmt/binding-win32-x64-msvc': 0.41.0 + '@oxfmt/binding-android-arm-eabi': 0.42.0 + '@oxfmt/binding-android-arm64': 0.42.0 + '@oxfmt/binding-darwin-arm64': 0.42.0 + '@oxfmt/binding-darwin-x64': 0.42.0 + '@oxfmt/binding-freebsd-x64': 0.42.0 + '@oxfmt/binding-linux-arm-gnueabihf': 0.42.0 + '@oxfmt/binding-linux-arm-musleabihf': 0.42.0 + '@oxfmt/binding-linux-arm64-gnu': 0.42.0 + '@oxfmt/binding-linux-arm64-musl': 0.42.0 + '@oxfmt/binding-linux-ppc64-gnu': 0.42.0 + '@oxfmt/binding-linux-riscv64-gnu': 0.42.0 + '@oxfmt/binding-linux-riscv64-musl': 0.42.0 + '@oxfmt/binding-linux-s390x-gnu': 0.42.0 + '@oxfmt/binding-linux-x64-gnu': 0.42.0 + '@oxfmt/binding-linux-x64-musl': 0.42.0 + '@oxfmt/binding-openharmony-arm64': 0.42.0 + '@oxfmt/binding-win32-arm64-msvc': 0.42.0 + '@oxfmt/binding-win32-ia32-msvc': 0.42.0 + '@oxfmt/binding-win32-x64-msvc': 0.42.0 - oxlint-tsgolint@0.17.1: + oxlint-tsgolint@0.17.3: optionalDependencies: - '@oxlint-tsgolint/darwin-arm64': 0.17.1 - '@oxlint-tsgolint/darwin-x64': 0.17.1 - '@oxlint-tsgolint/linux-arm64': 0.17.1 - '@oxlint-tsgolint/linux-x64': 0.17.1 - '@oxlint-tsgolint/win32-arm64': 0.17.1 - '@oxlint-tsgolint/win32-x64': 0.17.1 + '@oxlint-tsgolint/darwin-arm64': 0.17.3 + '@oxlint-tsgolint/darwin-x64': 0.17.3 + '@oxlint-tsgolint/linux-arm64': 0.17.3 + '@oxlint-tsgolint/linux-x64': 0.17.3 + '@oxlint-tsgolint/win32-arm64': 0.17.3 + '@oxlint-tsgolint/win32-x64': 0.17.3 - oxlint@1.56.0(oxlint-tsgolint@0.17.1): + oxlint@1.57.0(oxlint-tsgolint@0.17.3): optionalDependencies: - '@oxlint/binding-android-arm-eabi': 1.56.0 - '@oxlint/binding-android-arm64': 1.56.0 - '@oxlint/binding-darwin-arm64': 1.56.0 - '@oxlint/binding-darwin-x64': 1.56.0 - '@oxlint/binding-freebsd-x64': 1.56.0 - '@oxlint/binding-linux-arm-gnueabihf': 1.56.0 - '@oxlint/binding-linux-arm-musleabihf': 1.56.0 - '@oxlint/binding-linux-arm64-gnu': 1.56.0 - '@oxlint/binding-linux-arm64-musl': 1.56.0 - '@oxlint/binding-linux-ppc64-gnu': 1.56.0 - '@oxlint/binding-linux-riscv64-gnu': 1.56.0 - '@oxlint/binding-linux-riscv64-musl': 1.56.0 - '@oxlint/binding-linux-s390x-gnu': 1.56.0 - '@oxlint/binding-linux-x64-gnu': 1.56.0 - '@oxlint/binding-linux-x64-musl': 1.56.0 - '@oxlint/binding-openharmony-arm64': 1.56.0 - '@oxlint/binding-win32-arm64-msvc': 1.56.0 - '@oxlint/binding-win32-ia32-msvc': 1.56.0 - '@oxlint/binding-win32-x64-msvc': 1.56.0 - oxlint-tsgolint: 0.17.1 + '@oxlint/binding-android-arm-eabi': 1.57.0 + '@oxlint/binding-android-arm64': 1.57.0 + '@oxlint/binding-darwin-arm64': 1.57.0 + '@oxlint/binding-darwin-x64': 1.57.0 + '@oxlint/binding-freebsd-x64': 1.57.0 + '@oxlint/binding-linux-arm-gnueabihf': 1.57.0 + '@oxlint/binding-linux-arm-musleabihf': 1.57.0 + '@oxlint/binding-linux-arm64-gnu': 1.57.0 + '@oxlint/binding-linux-arm64-musl': 1.57.0 + '@oxlint/binding-linux-ppc64-gnu': 1.57.0 + '@oxlint/binding-linux-riscv64-gnu': 1.57.0 + '@oxlint/binding-linux-riscv64-musl': 1.57.0 + '@oxlint/binding-linux-s390x-gnu': 1.57.0 + '@oxlint/binding-linux-x64-gnu': 1.57.0 + '@oxlint/binding-linux-x64-musl': 1.57.0 + '@oxlint/binding-openharmony-arm64': 1.57.0 + '@oxlint/binding-win32-arm64-msvc': 1.57.0 + '@oxlint/binding-win32-ia32-msvc': 1.57.0 + '@oxlint/binding-win32-x64-msvc': 1.57.0 + oxlint-tsgolint: 0.17.3 p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 + p-limit@7.3.0: + dependencies: + yocto-queue: 1.2.2 + p-locate@5.0.0: dependencies: p-limit: 3.1.0 package-manager-detector@1.6.0: {} + pad-right@0.2.2: + dependencies: + repeat-string: 1.6.1 + pako@0.2.9: {} papaparse@5.5.3: {} @@ -14456,6 +16037,12 @@ snapshots: dependencies: parse-statements: 1.0.11 + parse-json@8.3.0: + dependencies: + '@babel/code-frame': 7.29.0 + index-to-position: 1.2.0 + type-fest: 4.41.0 + parse-statements@1.0.11: {} parse5-htmlparser2-tree-adapter@7.1.0: @@ -14531,7 +16118,7 @@ snapshots: pkg-types@1.3.1: dependencies: confbox: 0.1.8 - mlly: 1.8.1 + mlly: 1.8.2 pathe: 2.0.3 pkg-types@2.3.0: @@ -14540,6 +16127,14 @@ snapshots: exsolve: 1.0.8 pathe: 2.0.3 + playwright-core@1.58.2: {} + + playwright@1.58.2: + dependencies: + playwright-core: 1.58.2 + optionalDependencies: + fsevents: 2.3.2 + pluralize@8.0.0: {} pngjs@7.0.0: {} @@ -14558,7 +16153,7 @@ snapshots: portfinder@1.0.38: dependencies: async: 3.2.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -14587,6 +16182,15 @@ snapshots: tsx: 4.21.0 yaml: 2.8.3 + postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(yaml@2.8.3): + dependencies: + lilconfig: 3.1.3 + optionalDependencies: + jiti: 2.6.1 + postcss: 8.5.8 + tsx: 4.21.0 + yaml: 2.8.3 + postcss-nested@6.2.0(postcss@8.5.8): dependencies: postcss: 8.5.8 @@ -14621,6 +16225,8 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + powershell-utils@0.1.0: {} + prebuild-install@7.1.3: dependencies: detect-libc: 2.1.2 @@ -14647,18 +16253,24 @@ snapshots: prismjs@1.30.0: {} + progress@2.0.3: {} + prop-types@15.8.1: dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 react-is: 16.13.1 + property-expr@2.0.6: {} + property-information@5.6.0: dependencies: xtend: 4.0.2 property-information@7.1.0: {} + proxy-from-env@2.1.0: {} + pump@3.0.4: dependencies: end-of-stream: 1.4.5 @@ -14731,7 +16343,7 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - react-easy-crop@5.5.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + react-easy-crop@5.5.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: normalize-wheel: 1.0.1 react: 19.2.4 @@ -14749,11 +16361,11 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - react-i18next@16.6.1(i18next@25.10.4(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3): + react-i18next@16.6.6(i18next@25.10.10(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 html-parse-stringify: 3.0.1 - i18next: 25.10.4(typescript@5.9.3) + i18next: 25.10.10(typescript@5.9.3) react: 19.2.4 use-sync-external-store: 1.6.0(react@19.2.4) optionalDependencies: @@ -14881,6 +16493,20 @@ snapshots: dependencies: pify: 2.3.0 + read-package-up@12.0.0: + dependencies: + find-up-simple: 1.0.1 + read-pkg: 10.1.0 + type-fest: 5.5.0 + + read-pkg@10.1.0: + dependencies: + '@types/normalize-package-data': 2.4.4 + normalize-package-data: 8.0.0 + parse-json: 8.3.0 + type-fest: 5.5.0 + unicorn-magic: 0.4.0 + readable-stream@3.6.2: dependencies: inherits: 2.0.4 @@ -14940,6 +16566,8 @@ snapshots: dependencies: '@eslint-community/regexpp': 4.12.2 + reflect-metadata@0.2.2: {} + refractor@3.6.0: dependencies: hastscript: 6.0.0 @@ -14951,6 +16579,10 @@ snapshots: '@eslint-community/regexpp': 4.12.2 refa: 0.12.1 + regexp-match-indices@1.0.2: + dependencies: + regexp-tree: 0.1.27 + regexp-tree@0.1.27: {} regjsparser@0.13.0: @@ -14967,7 +16599,7 @@ snapshots: '@types/katex': 0.16.8 hast-util-from-html-isomorphic: 2.0.0 hast-util-to-text: 4.0.2 - katex: 0.16.40 + katex: 0.16.44 unist-util-visit-parents: 6.0.2 vfile: 6.0.3 @@ -15057,6 +16689,8 @@ snapshots: remend@1.3.0: {} + repeat-string@1.6.1: {} + require-from-string@2.0.2: {} reselect@5.1.1: {} @@ -15067,6 +16701,8 @@ snapshots: resolve-from@4.0.0: {} + resolve-from@5.0.0: {} + resolve-pkg-maps@1.0.0: {} resolve@1.22.11: @@ -15084,7 +16720,31 @@ snapshots: rfdc@1.4.1: {} - robust-predicates@3.0.2: {} + robust-predicates@3.0.3: {} + + rolldown@1.0.0-rc.12(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1): + dependencies: + '@oxc-project/types': 0.122.0 + '@rolldown/pluginutils': 1.0.0-rc.12 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-rc.12 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.12 + '@rolldown/binding-darwin-x64': 1.0.0-rc.12 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.12 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.12 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.12 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.12 + '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.12 + '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.12 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.12 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.12 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.12 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.12(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1) + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.12 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.12 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' rollup@4.59.0: dependencies: @@ -15163,11 +16823,6 @@ snapshots: sax@1.6.0: {} - saxes@6.0.0: - dependencies: - xmlchars: 2.2.0 - optional: true - scheduler@0.27.0: {} schema-utils@4.3.3: @@ -15185,6 +16840,8 @@ snapshots: refa: 0.12.1 regexp-ast-analysis: 0.7.1 + seed-random@2.2.0: {} + semver@6.3.1: {} semver@7.7.4: {} @@ -15291,8 +16948,18 @@ snapshots: space-separated-tokens@2.0.2: {} + spdx-correct@3.2.0: + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.23 + spdx-exceptions@2.5.0: {} + spdx-expression-parse@3.0.1: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.23 + spdx-expression-parse@4.0.0: dependencies: spdx-exceptions: 2.5.0 @@ -15300,7 +16967,9 @@ snapshots: spdx-license-ids@3.0.23: {} - srvx@0.11.12: {} + srvx@0.11.13: {} + + stackframe@1.3.4: {} state-local@1.0.7: {} @@ -15308,7 +16977,7 @@ snapshots: std-semver@1.0.8: {} - storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: '@storybook/global': 5.0.0 '@storybook/icons': 2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -15321,7 +16990,7 @@ snapshots: recast: 0.23.11 semver: 7.7.4 use-sync-external-store: 1.6.0(react@19.2.4) - ws: 8.19.0 + ws: 8.20.0 transitivePeerDependencies: - '@testing-library/dom' - bufferutil @@ -15334,7 +17003,7 @@ snapshots: clsx: 2.1.1 hast-util-to-jsx-runtime: 2.3.6 html-url-attributes: 3.0.1 - marked: 17.0.4 + marked: 17.0.5 mermaid: 11.13.0 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) @@ -15352,6 +17021,8 @@ snapshots: transitivePeerDependencies: - supports-color + string-argv@0.3.1: {} + string-argv@0.3.2: {} string-ts@2.3.1: {} @@ -15396,6 +17067,8 @@ snapshots: dependencies: js-tokens: 9.0.1 + structured-clone-es@2.0.0: {} + style-to-js@1.1.21: dependencies: style-to-object: 1.0.14 @@ -15443,9 +17116,6 @@ snapshots: picocolors: 1.1.1 sax: 1.6.0 - symbol-tree@3.2.4: - optional: true - synckit@0.11.12: dependencies: '@pkgr/core': 0.2.9 @@ -15488,8 +17158,6 @@ snapshots: - tsx - yaml - tapable@2.3.0: {} - tapable@2.3.2: {} tar-fs@2.1.4: @@ -15559,6 +17227,8 @@ snapshots: dependencies: any-promise: 1.3.0 + tiny-case@1.0.3: {} + tiny-inflate@1.0.3: {} tiny-invariant@1.2.0: {} @@ -15567,6 +17237,8 @@ snapshots: tinybench@2.9.0: {} + tinyexec@0.3.2: {} + tinyexec@1.0.4: {} tinyglobby@0.2.15: @@ -15603,23 +17275,17 @@ snapshots: dependencies: eslint-visitor-keys: 5.0.1 + toposort@2.0.2: {} + totalist@3.0.1: {} - tough-cookie@6.0.1: - dependencies: - tldts: 7.0.27 - optional: true - - tr46@6.0.0: - dependencies: - punycode: 2.3.1 - optional: true + tree-kill@1.2.2: {} trim-lines@3.0.1: {} trough@2.2.0: {} - ts-api-utils@2.4.0(typescript@5.9.3): + ts-api-utils@2.5.0(typescript@5.9.3): dependencies: typescript: 5.9.3 @@ -15644,7 +17310,7 @@ snapshots: dependencies: chalk: 4.1.2 enhanced-resolve: 5.20.1 - tapable: 2.3.0 + tapable: 2.3.2 tsconfig-paths: 4.2.0 tsconfig-paths@4.2.0: @@ -15659,6 +17325,34 @@ snapshots: tslib@2.8.1: {} + tsup@8.5.1(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3): + dependencies: + bundle-require: 5.1.0(esbuild@0.27.2) + cac: 6.7.14 + chokidar: 4.0.3 + consola: 3.4.2 + debug: 4.4.3(supports-color@8.1.1) + esbuild: 0.27.2 + fix-dts-default-cjs-exports: 1.0.1 + joycon: 3.1.1 + picocolors: 1.1.1 + postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(yaml@2.8.3) + resolve-from: 5.0.0 + rollup: 4.59.0 + source-map: 0.7.6 + sucrase: 3.35.1 + tinyexec: 0.3.2 + tinyglobby: 0.2.15 + tree-kill: 1.2.2 + optionalDependencies: + postcss: 8.5.8 + typescript: 5.9.3 + transitivePeerDependencies: + - jiti + - supports-color + - tsx + - yaml + tsx@4.21.0: dependencies: esbuild: 0.27.2 @@ -15677,7 +17371,11 @@ snapshots: dependencies: prelude-ls: 1.2.1 - type-fest@5.4.4: + type-fest@2.19.0: {} + + type-fest@4.41.0: {} + + type-fest@5.5.0: dependencies: tagged-tag: 1.0.0 @@ -15706,14 +17404,13 @@ snapshots: undici@7.24.0: {} - undici@7.24.6: - optional: true - unicode-trie@2.0.0: dependencies: pako: 0.2.9 tiny-inflate: 1.0.3 + unicorn-magic@0.4.0: {} + unified@11.0.5: dependencies: '@types/unist': 3.0.3 @@ -15783,6 +17480,10 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 + upper-case-first@2.0.2: + dependencies: + tslib: 2.8.1 + uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -15832,16 +17533,23 @@ snapshots: dependencies: react: 19.2.4 + util-arity@1.1.0: {} + util-deprecate@1.0.2: {} uuid@11.1.0: {} uuid@13.0.0: {} - valibot@1.3.0(typescript@5.9.3): + valibot@1.3.1(typescript@5.9.3): optionalDependencies: typescript: 5.9.3 + validate-npm-package-license@3.0.4: + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + vfile-location@5.0.3: dependencies: '@types/unist': 3.0.3 @@ -15857,37 +17565,27 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vinext@https://pkg.pr.new/vinext@b6a2cac(33c71b051bfc49f90bf5d8b6a8976975): + vinext@0.0.38(f5786d681f520e26604259e094ebaa46): dependencies: - '@unpic/react': 1.0.2(next@16.2.1(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@unpic/react': 1.0.2(next@16.2.1(@babel/core@7.29.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@vercel/og': 0.8.6 - '@vitejs/plugin-react': 6.0.1(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)) + '@vitejs/plugin-react': 6.0.1(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)) magic-string: 0.30.21 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) rsc-html-stream: 0.0.7 - vite: '@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' + vite: '@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' vite-plugin-commonjs: 0.10.4 - vite-tsconfig-paths: 6.1.1(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(typescript@5.9.3) + vite-tsconfig-paths: 6.1.1(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(typescript@5.9.3) optionalDependencies: '@mdx-js/rollup': 3.1.1(rollup@4.59.0) - '@vitejs/plugin-rsc': 0.5.21(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(react-dom@19.2.4(react@19.2.4))(react-server-dom-webpack@19.2.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3)))(react@19.2.4) + '@vitejs/plugin-rsc': 0.5.21(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(react-dom@19.2.4(react@19.2.4))(react-server-dom-webpack@19.2.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3)))(react@19.2.4) react-server-dom-webpack: 19.2.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(webpack@5.105.4(esbuild@0.27.2)(uglify-js@3.19.3)) transitivePeerDependencies: - next - supports-color - typescript - vite-dev-rpc@1.1.0(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)): - dependencies: - birpc: 2.9.0 - vite: '@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' - vite-hot-client: 2.1.0(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)) - - vite-hot-client@2.1.0(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)): - dependencies: - vite: '@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' - vite-plugin-commonjs@0.10.4: dependencies: acorn: 8.16.0 @@ -15901,54 +17599,57 @@ snapshots: fast-glob: 3.3.3 magic-string: 0.30.21 - vite-plugin-inspect@11.3.3(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)): + vite-plugin-inspect@12.0.0-beta.1(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(typescript@5.9.3)(ws@8.20.0): dependencies: + '@vitejs/devtools-kit': 0.1.11(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(typescript@5.9.3)(ws@8.20.0) ansis: 4.2.0 - debug: 4.4.3 error-stack-parser-es: 1.0.5 + obug: 2.1.1 ohash: 2.0.11 - open: 10.2.0 + open: 11.0.0 perfect-debounce: 2.1.0 sirv: 3.0.2 unplugin-utils: 0.3.1 - vite: '@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' - vite-dev-rpc: 1.1.0(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)) + vite: '@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' transitivePeerDependencies: - - supports-color + - typescript + - ws - vite-plugin-storybook-nextjs@3.2.3(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(next@16.2.1(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0))(storybook@10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3): + vite-plugin-storybook-nextjs@3.2.4(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(next@16.2.1(@babel/core@7.29.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0))(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3): dependencies: '@next/env': 16.0.0 image-size: 2.0.2 magic-string: 0.30.21 module-alias: 2.3.4 - next: 16.2.1(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0) - storybook: 10.3.1(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + next: 16.2.1(@babel/core@7.29.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.98.0) + storybook: 10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) ts-dedent: 2.2.0 - vite: '@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' - vite-tsconfig-paths: 5.1.4(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(typescript@5.9.3) + vite: '@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' + vite-tsconfig-paths: 5.1.4(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(typescript@5.9.3) transitivePeerDependencies: - supports-color - typescript - vite-plus@0.1.13(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(jsdom@29.0.1(canvas@3.2.2))(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3): + vite-plus@0.1.14(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3): dependencies: - '@oxc-project/types': 0.120.0 - '@voidzero-dev/vite-plus-core': 0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) - '@voidzero-dev/vite-plus-test': 0.1.13(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(jsdom@29.0.1(canvas@3.2.2))(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + '@oxc-project/types': 0.122.0 + '@voidzero-dev/vite-plus-core': 0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + '@voidzero-dev/vite-plus-test': 0.1.14(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) cac: 7.0.0 cross-spawn: 7.0.6 - oxfmt: 0.41.0 - oxlint: 1.56.0(oxlint-tsgolint@0.17.1) - oxlint-tsgolint: 0.17.1 + oxfmt: 0.42.0 + oxlint: 1.57.0(oxlint-tsgolint@0.17.3) + oxlint-tsgolint: 0.17.3 picocolors: 1.1.1 optionalDependencies: - '@voidzero-dev/vite-plus-darwin-arm64': 0.1.13 - '@voidzero-dev/vite-plus-darwin-x64': 0.1.13 - '@voidzero-dev/vite-plus-linux-arm64-gnu': 0.1.13 - '@voidzero-dev/vite-plus-linux-x64-gnu': 0.1.13 - '@voidzero-dev/vite-plus-win32-arm64-msvc': 0.1.13 - '@voidzero-dev/vite-plus-win32-x64-msvc': 0.1.13 + '@voidzero-dev/vite-plus-darwin-arm64': 0.1.14 + '@voidzero-dev/vite-plus-darwin-x64': 0.1.14 + '@voidzero-dev/vite-plus-linux-arm64-gnu': 0.1.14 + '@voidzero-dev/vite-plus-linux-arm64-musl': 0.1.14 + '@voidzero-dev/vite-plus-linux-x64-gnu': 0.1.14 + '@voidzero-dev/vite-plus-linux-x64-musl': 0.1.14 + '@voidzero-dev/vite-plus-win32-arm64-msvc': 0.1.14 + '@voidzero-dev/vite-plus-win32-x64-msvc': 0.1.14 transitivePeerDependencies: - '@arethetypeswrong/core' - '@edge-runtime/vm' @@ -15977,36 +17678,104 @@ snapshots: - vite - yaml - vite-tsconfig-paths@5.1.4(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(typescript@5.9.3): + vite-plus@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.2)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3): dependencies: - debug: 4.4.3 + '@oxc-project/types': 0.122.0 + '@voidzero-dev/vite-plus-core': 0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + '@voidzero-dev/vite-plus-test': 0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.2)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) + cac: 7.0.0 + cross-spawn: 7.0.6 + oxfmt: 0.42.0 + oxlint: 1.57.0(oxlint-tsgolint@0.17.3) + oxlint-tsgolint: 0.17.3 + picocolors: 1.1.1 + optionalDependencies: + '@voidzero-dev/vite-plus-darwin-arm64': 0.1.14 + '@voidzero-dev/vite-plus-darwin-x64': 0.1.14 + '@voidzero-dev/vite-plus-linux-arm64-gnu': 0.1.14 + '@voidzero-dev/vite-plus-linux-arm64-musl': 0.1.14 + '@voidzero-dev/vite-plus-linux-x64-gnu': 0.1.14 + '@voidzero-dev/vite-plus-linux-x64-musl': 0.1.14 + '@voidzero-dev/vite-plus-win32-arm64-msvc': 0.1.14 + '@voidzero-dev/vite-plus-win32-x64-msvc': 0.1.14 + transitivePeerDependencies: + - '@arethetypeswrong/core' + - '@edge-runtime/vm' + - '@opentelemetry/api' + - '@tsdown/css' + - '@tsdown/exe' + - '@types/node' + - '@vitejs/devtools' + - '@vitest/ui' + - bufferutil + - esbuild + - happy-dom + - jiti + - jsdom + - less + - publint + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - typescript + - unplugin-unused + - utf-8-validate + - vite + - yaml + + vite-tsconfig-paths@5.1.4(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(typescript@5.9.3): + dependencies: + debug: 4.4.3(supports-color@8.1.1) globrex: 0.1.2 tsconfck: 3.1.6(typescript@5.9.3) optionalDependencies: - vite: '@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' + vite: '@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' transitivePeerDependencies: - supports-color - typescript - vite-tsconfig-paths@6.1.1(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(typescript@5.9.3): + vite-tsconfig-paths@6.1.1(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(typescript@5.9.3): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) globrex: 0.1.2 tsconfck: 3.1.6(typescript@5.9.3) - vite: '@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' + vite: '@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' transitivePeerDependencies: - supports-color - typescript - vitefu@1.1.2(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)): + vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.2)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.8 + rolldown: 1.0.0-rc.12(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1) + tinyglobby: 0.2.15 optionalDependencies: - vite: '@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' + '@types/node': 25.5.0 + esbuild: 0.27.2 + fsevents: 2.3.3 + jiti: 2.6.1 + sass: 1.98.0 + terser: 5.46.1 + tsx: 4.21.0 + yaml: 2.8.3 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' - vitest-canvas-mock@1.1.3(@voidzero-dev/vite-plus-test@0.1.13(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(jsdom@29.0.1(canvas@3.2.2))(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)): + vitefu@1.1.2(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)): + optionalDependencies: + vite: '@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' + + vitest-canvas-mock@1.1.4(@voidzero-dev/vite-plus-test@0.1.14(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)): dependencies: cssfontparser: 1.2.1 moo-color: 1.0.3 - vitest: '@voidzero-dev/vite-plus-test@0.1.13(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.13(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(jsdom@29.0.1(canvas@3.2.2))(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' + vitest: '@voidzero-dev/vite-plus-test@0.1.14(@types/node@25.5.0)(@voidzero-dev/vite-plus-core@0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@1.21.7)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)' void-elements@3.1.0: {} @@ -16029,7 +17798,7 @@ snapshots: vue-eslint-parser@10.4.0(eslint@10.1.0(jiti@1.21.7)): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) eslint: 10.1.0(jiti@1.21.7) eslint-scope: 9.1.2 eslint-visitor-keys: 5.0.1 @@ -16039,11 +17808,6 @@ snapshots: transitivePeerDependencies: - supports-color - w3c-xmlserializer@5.0.0: - dependencies: - xml-name-validator: 5.0.0 - optional: true - walk-up-path@4.0.0: {} watchpack@2.5.1: @@ -16055,9 +17819,6 @@ snapshots: web-vitals@5.1.0: {} - webidl-conversions@8.0.1: - optional: true - webpack-sources@3.3.4: {} webpack-virtual-modules@0.6.2: {} @@ -16102,18 +17863,6 @@ snapshots: whatwg-mimetype@4.0.0: {} - whatwg-mimetype@5.0.0: - optional: true - - whatwg-url@16.0.1: - dependencies: - '@exodus/bytes': 1.15.0 - tr46: 6.0.0 - webidl-conversions: 8.0.1 - transitivePeerDependencies: - - '@noble/hashes' - optional: true - which@2.0.2: dependencies: isexe: 2.0.0 @@ -16128,21 +17877,20 @@ snapshots: wrappy@1.0.2: {} - ws@8.19.0: {} - ws@8.20.0: {} wsl-utils@0.1.0: dependencies: is-wsl: 3.1.1 + wsl-utils@0.3.1: + dependencies: + is-wsl: 3.1.1 + powershell-utils: 0.1.0 + xml-name-validator@4.0.0: {} - xml-name-validator@5.0.0: - optional: true - - xmlchars@2.2.0: - optional: true + xmlbuilder@15.1.1: {} xtend@4.0.2: {} @@ -16168,8 +17916,17 @@ snapshots: yocto-queue@0.1.0: {} + yocto-queue@1.2.2: {} + yoga-layout@3.2.1: {} + yup@1.7.1: + dependencies: + property-expr: 2.0.6 + tiny-case: 1.0.3 + toposort: 2.0.2 + type-fest: 2.19.0 + zen-observable@0.10.0: {} zimmerframe@1.1.4: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000000..dece6f3f4f --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,257 @@ +packages: + - web + - e2e + - sdks/nodejs-client +overrides: + "@lexical/code": npm:lexical-code-no-prism@0.41.0 + "@monaco-editor/loader": 1.7.0 + "@nolyfill/safe-buffer": npm:safe-buffer@^5.2.1 + array-includes: npm:@nolyfill/array-includes@^1.0.44 + array.prototype.findlast: npm:@nolyfill/array.prototype.findlast@^1.0.44 + array.prototype.findlastindex: npm:@nolyfill/array.prototype.findlastindex@^1.0.44 + array.prototype.flat: npm:@nolyfill/array.prototype.flat@^1.0.44 + array.prototype.flatmap: npm:@nolyfill/array.prototype.flatmap@^1.0.44 + array.prototype.tosorted: npm:@nolyfill/array.prototype.tosorted@^1.0.44 + assert: npm:@nolyfill/assert@^1.0.26 + brace-expansion@<2.0.2: 2.0.2 + canvas: ^3.2.2 + devalue@<5.3.2: 5.3.2 + dompurify@>=3.1.3 <=3.3.1: 3.3.2 + es-iterator-helpers: npm:@nolyfill/es-iterator-helpers@^1.0.21 + esbuild@<0.27.2: 0.27.2 + flatted@<=3.4.1: 3.4.2 + glob@>=10.2.0 <10.5.0: 11.1.0 + hasown: npm:@nolyfill/hasown@^1.0.44 + is-arguments: npm:@nolyfill/is-arguments@^1.0.44 + is-core-module: npm:@nolyfill/is-core-module@^1.0.39 + is-generator-function: npm:@nolyfill/is-generator-function@^1.0.44 + is-typed-array: npm:@nolyfill/is-typed-array@^1.0.44 + isarray: npm:@nolyfill/isarray@^1.0.44 + object.assign: npm:@nolyfill/object.assign@^1.0.44 + object.entries: npm:@nolyfill/object.entries@^1.0.44 + object.fromentries: npm:@nolyfill/object.fromentries@^1.0.44 + object.groupby: npm:@nolyfill/object.groupby@^1.0.44 + object.values: npm:@nolyfill/object.values@^1.0.44 + pbkdf2: ~3.1.5 + pbkdf2@<3.1.3: 3.1.3 + picomatch@<2.3.2: 2.3.2 + picomatch@>=4.0.0 <4.0.4: 4.0.4 + prismjs: ~1.30 + prismjs@<1.30.0: 1.30.0 + rollup@>=4.0.0 <4.59.0: 4.59.0 + safe-buffer: ^5.2.1 + safe-regex-test: npm:@nolyfill/safe-regex-test@^1.0.44 + safer-buffer: npm:@nolyfill/safer-buffer@^1.0.44 + side-channel: npm:@nolyfill/side-channel@^1.0.44 + smol-toml@<1.6.1: 1.6.1 + solid-js: 1.9.11 + string-width: ~8.2.0 + string.prototype.includes: npm:@nolyfill/string.prototype.includes@^1.0.44 + string.prototype.matchall: npm:@nolyfill/string.prototype.matchall@^1.0.44 + string.prototype.repeat: npm:@nolyfill/string.prototype.repeat@^1.0.44 + string.prototype.trimend: npm:@nolyfill/string.prototype.trimend@^1.0.44 + svgo@>=3.0.0 <3.3.3: 3.3.3 + tar@<=7.5.10: 7.5.11 + typed-array-buffer: npm:@nolyfill/typed-array-buffer@^1.0.44 + undici@>=7.0.0 <7.24.0: 7.24.0 + vite: npm:@voidzero-dev/vite-plus-core@0.1.14 + vitest: npm:@voidzero-dev/vite-plus-test@0.1.14 + which-typed-array: npm:@nolyfill/which-typed-array@^1.0.44 + yaml@>=2.0.0 <2.8.3: 2.8.3 + yauzl@<3.2.1: 3.2.1 +ignoredBuiltDependencies: + - canvas + - core-js-pure +onlyBuiltDependencies: + - "@parcel/watcher" + - esbuild + - sharp +catalog: + "@amplitude/analytics-browser": 2.38.0 + "@amplitude/plugin-session-replay-browser": 1.27.5 + "@antfu/eslint-config": 7.7.3 + "@base-ui/react": 1.3.0 + "@chromatic-com/storybook": 5.1.1 + "@cucumber/cucumber": 12.7.0 + "@egoist/tailwindcss-icons": 1.9.2 + "@emoji-mart/data": 1.2.1 + "@eslint-react/eslint-plugin": 3.0.0 + "@eslint/js": ^10.0.1 + "@floating-ui/react": 0.27.19 + "@formatjs/intl-localematcher": 0.8.2 + "@headlessui/react": 2.2.9 + "@heroicons/react": 2.2.0 + "@hono/node-server": 1.19.11 + "@iconify-json/heroicons": 1.2.3 + "@iconify-json/ri": 1.2.10 + "@lexical/code": 0.42.0 + "@lexical/link": 0.42.0 + "@lexical/list": 0.42.0 + "@lexical/react": 0.42.0 + "@lexical/selection": 0.42.0 + "@lexical/text": 0.42.0 + "@lexical/utils": 0.42.0 + "@mdx-js/loader": 3.1.1 + "@mdx-js/react": 3.1.1 + "@mdx-js/rollup": 3.1.1 + "@monaco-editor/react": 4.7.0 + "@next/eslint-plugin-next": 16.2.1 + "@next/mdx": 16.2.1 + "@orpc/client": 1.13.13 + "@orpc/contract": 1.13.13 + "@orpc/openapi-client": 1.13.13 + "@orpc/tanstack-query": 1.13.13 + "@playwright/test": 1.58.2 + "@remixicon/react": 4.9.0 + "@rgrove/parse-xml": 4.2.0 + "@sentry/react": 10.46.0 + "@storybook/addon-docs": 10.3.3 + "@storybook/addon-links": 10.3.3 + "@storybook/addon-onboarding": 10.3.3 + "@storybook/addon-themes": 10.3.3 + "@storybook/nextjs-vite": 10.3.3 + "@storybook/react": 10.3.3 + "@streamdown/math": 1.0.2 + "@svgdotjs/svg.js": 3.2.5 + "@t3-oss/env-nextjs": 0.13.11 + "@tailwindcss/typography": 0.5.19 + "@tanstack/eslint-plugin-query": 5.95.2 + "@tanstack/react-devtools": 0.10.0 + "@tanstack/react-form": 1.28.5 + "@tanstack/react-form-devtools": 0.2.19 + "@tanstack/react-query": 5.95.2 + "@tanstack/react-query-devtools": 5.95.2 + "@testing-library/dom": 10.4.1 + "@testing-library/jest-dom": 6.9.1 + "@testing-library/react": 16.3.2 + "@testing-library/user-event": 14.6.1 + "@tsslint/cli": 3.0.2 + "@tsslint/compat-eslint": 3.0.2 + "@tsslint/config": 3.0.2 + "@types/js-cookie": 3.0.6 + "@types/js-yaml": 4.0.9 + "@types/negotiator": 0.6.4 + "@types/node": 25.5.0 + "@types/postcss-js": 4.1.0 + "@types/qs": 6.15.0 + "@types/react": 19.2.14 + "@types/react-dom": 19.2.3 + "@types/react-syntax-highlighter": 15.5.13 + "@types/react-window": 1.8.8 + "@types/sortablejs": 1.15.9 + "@typescript-eslint/eslint-plugin": ^8.57.2 + "@typescript-eslint/parser": 8.57.2 + "@typescript/native-preview": 7.0.0-dev.20260329.1 + "@vitejs/plugin-react": 6.0.1 + "@vitejs/plugin-rsc": 0.5.21 + "@vitest/coverage-v8": 4.1.2 + abcjs: 6.6.2 + agentation: 3.0.2 + ahooks: 3.9.7 + autoprefixer: 10.4.27 + axios: ^1.14.0 + class-variance-authority: 0.7.1 + clsx: 2.1.1 + cmdk: 1.1.1 + code-inspector-plugin: 1.4.5 + copy-to-clipboard: 3.3.3 + cron-parser: 5.5.0 + dayjs: 1.11.20 + decimal.js: 10.6.0 + dompurify: 3.3.3 + echarts: 6.0.0 + echarts-for-react: 3.0.6 + elkjs: 0.11.1 + embla-carousel-autoplay: 8.6.0 + embla-carousel-react: 8.6.0 + emoji-mart: 5.6.0 + es-toolkit: 1.45.1 + eslint: 10.1.0 + eslint-markdown: 0.6.0 + eslint-plugin-better-tailwindcss: 4.3.2 + eslint-plugin-hyoban: 0.14.1 + eslint-plugin-markdown-preferences: 0.40.3 + eslint-plugin-no-barrel-files: 1.2.2 + eslint-plugin-react-hooks: 7.0.1 + eslint-plugin-react-refresh: 0.5.2 + eslint-plugin-sonarjs: 4.0.2 + eslint-plugin-storybook: 10.3.3 + fast-deep-equal: 3.1.3 + foxact: 0.3.0 + happy-dom: 20.8.9 + hono: 4.12.9 + html-entities: 2.6.0 + html-to-image: 1.11.13 + husky: 9.1.7 + i18next: 25.10.10 + i18next-resources-to-backend: 1.2.1 + iconify-import-svg: 0.1.2 + immer: 11.1.4 + jotai: 2.19.0 + js-audio-recorder: 1.0.7 + js-cookie: 3.0.5 + js-yaml: 4.1.1 + jsonschema: 1.5.0 + katex: 0.16.44 + knip: 6.1.0 + ky: 1.14.3 + lamejs: 1.2.1 + lexical: 0.42.0 + lint-staged: 16.4.0 + mermaid: 11.13.0 + mime: 4.1.0 + mitt: 3.0.1 + negotiator: 1.0.0 + next: 16.2.1 + next-themes: 0.4.6 + nuqs: 2.8.9 + pinyin-pro: 3.28.0 + postcss: 8.5.8 + postcss-js: 5.1.0 + qrcode.react: 4.2.0 + qs: 6.15.0 + react: 19.2.4 + react-18-input-autosize: 3.0.0 + react-dom: 19.2.4 + react-easy-crop: 5.5.7 + react-hotkeys-hook: 5.2.4 + react-i18next: 16.6.6 + react-multi-email: 1.0.25 + react-papaparse: 4.4.0 + react-pdf-highlighter: 8.0.0-rc.0 + react-server-dom-webpack: 19.2.4 + react-sortablejs: 6.1.4 + react-syntax-highlighter: 15.6.6 + react-textarea-autosize: 8.5.9 + react-window: 1.8.11 + reactflow: 11.11.4 + remark-breaks: 4.0.0 + remark-directive: 4.0.0 + sass: 1.98.0 + scheduler: 0.27.0 + sharp: 0.34.5 + sortablejs: 1.15.7 + std-semver: 1.0.8 + storybook: 10.3.3 + streamdown: 2.5.0 + string-ts: 2.3.1 + tailwind-merge: 2.6.1 + tailwindcss: 3.4.19 + taze: 19.10.0 + tldts: 7.0.27 + tsup: ^8.5.1 + tsx: 4.21.0 + typescript: 5.9.3 + uglify-js: 3.19.3 + unist-util-visit: 5.1.0 + use-context-selector: 2.0.0 + uuid: 13.0.0 + vinext: 0.0.38 + vite: npm:@voidzero-dev/vite-plus-core@0.1.14 + vite-plugin-inspect: 12.0.0-beta.1 + vite-plus: 0.1.14 + vitest: npm:@voidzero-dev/vite-plus-test@0.1.14 + vitest-canvas-mock: 1.1.4 + zod: 4.3.6 + zundo: 2.3.0 + zustand: 5.0.12 diff --git a/sdks/nodejs-client/README.md b/sdks/nodejs-client/README.md index f8c2803c08..7051bbc788 100644 --- a/sdks/nodejs-client/README.md +++ b/sdks/nodejs-client/README.md @@ -100,6 +100,10 @@ Notes: - Chat/completion require a stable `user` identifier in the request payload. - For streaming responses, iterate the returned AsyncIterable. Use `stream.toText()` to collect text. +## Maintainers + +This package is published from the repository workspace. Install dependencies from the repository root with `pnpm install`, then use `./scripts/publish.sh` for dry runs and publishing so `catalog:` dependencies are resolved before release. + ## License This SDK is released under the MIT License. diff --git a/sdks/nodejs-client/package.json b/sdks/nodejs-client/package.json index 7168d33c24..63fa6799b1 100644 --- a/sdks/nodejs-client/package.json +++ b/sdks/nodejs-client/package.json @@ -54,24 +54,17 @@ "publish:npm": "./scripts/publish.sh" }, "dependencies": { - "axios": "^1.13.6" + "axios": "catalog:" }, "devDependencies": { - "@eslint/js": "^10.0.1", - "@types/node": "^25.4.0", - "@typescript-eslint/eslint-plugin": "^8.57.0", - "@typescript-eslint/parser": "^8.57.0", - "@vitest/coverage-v8": "4.0.18", - "eslint": "^10.0.3", - "tsup": "^8.5.1", - "typescript": "^5.9.3", - "vitest": "^4.0.18" - }, - "pnpm": { - "overrides": { - "flatted@<=3.4.1": "3.4.2", - "picomatch@>=4.0.0 <4.0.4": "4.0.4", - "rollup@>=4.0.0 <4.59.0": "4.59.0" - } + "@eslint/js": "catalog:", + "@types/node": "catalog:", + "@typescript-eslint/eslint-plugin": "catalog:", + "@typescript-eslint/parser": "catalog:", + "@vitest/coverage-v8": "catalog:", + "eslint": "catalog:", + "tsup": "catalog:", + "typescript": "catalog:", + "vitest": "catalog:" } } diff --git a/sdks/nodejs-client/pnpm-lock.yaml b/sdks/nodejs-client/pnpm-lock.yaml deleted file mode 100644 index 30d3cf61ee..0000000000 --- a/sdks/nodejs-client/pnpm-lock.yaml +++ /dev/null @@ -1,2255 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -overrides: - flatted@<=3.4.1: 3.4.2 - picomatch@>=4.0.0 <4.0.4: 4.0.4 - rollup@>=4.0.0 <4.59.0: 4.59.0 - -importers: - - .: - dependencies: - axios: - specifier: ^1.13.6 - version: 1.13.6 - devDependencies: - '@eslint/js': - specifier: ^10.0.1 - version: 10.0.1(eslint@10.0.3) - '@types/node': - specifier: ^25.4.0 - version: 25.4.0 - '@typescript-eslint/eslint-plugin': - specifier: ^8.57.0 - version: 8.57.0(@typescript-eslint/parser@8.57.0(eslint@10.0.3)(typescript@5.9.3))(eslint@10.0.3)(typescript@5.9.3) - '@typescript-eslint/parser': - specifier: ^8.57.0 - version: 8.57.0(eslint@10.0.3)(typescript@5.9.3) - '@vitest/coverage-v8': - specifier: 4.0.18 - version: 4.0.18(vitest@4.0.18(@types/node@25.4.0)) - eslint: - specifier: ^10.0.3 - version: 10.0.3 - tsup: - specifier: ^8.5.1 - version: 8.5.1(postcss@8.5.8)(typescript@5.9.3) - typescript: - specifier: ^5.9.3 - version: 5.9.3 - vitest: - specifier: ^4.0.18 - version: 4.0.18(@types/node@25.4.0) - -packages: - - '@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/parser@7.29.0': - resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/types@7.29.0': - resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} - engines: {node: '>=6.9.0'} - - '@bcoe/v8-coverage@1.0.2': - resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} - engines: {node: '>=18'} - - '@esbuild/aix-ppc64@0.27.3': - resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.27.3': - resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.27.3': - resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.27.3': - resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.27.3': - resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.27.3': - resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.27.3': - resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.27.3': - resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.27.3': - resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.27.3': - resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.27.3': - resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.27.3': - resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.27.3': - resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.27.3': - resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.27.3': - resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.27.3': - resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.27.3': - resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-arm64@0.27.3': - resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.27.3': - resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.27.3': - resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.27.3': - resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openharmony-arm64@0.27.3': - resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - - '@esbuild/sunos-x64@0.27.3': - resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.27.3': - resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.27.3': - resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.27.3': - resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - - '@eslint-community/eslint-utils@4.9.1': - resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - - '@eslint-community/regexpp@4.12.2': - resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - '@eslint/config-array@0.23.3': - resolution: {integrity: sha512-j+eEWmB6YYLwcNOdlwQ6L2OsptI/LO6lNBuLIqe5R7RetD658HLoF+Mn7LzYmAWWNNzdC6cqP+L6r8ujeYXWLw==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - '@eslint/config-helpers@0.5.3': - resolution: {integrity: sha512-lzGN0onllOZCGroKJmRwY6QcEHxbjBw1gwB8SgRSqK8YbbtEXMvKynsXc3553ckIEBxsbMBU7oOZXKIPGZNeZw==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - '@eslint/core@1.1.1': - resolution: {integrity: sha512-QUPblTtE51/7/Zhfv8BDwO0qkkzQL7P/aWWbqcf4xWLEYn1oKjdO0gglQBB4GAsu7u6wjijbCmzsUTy6mnk6oQ==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - '@eslint/js@10.0.1': - resolution: {integrity: sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - peerDependencies: - eslint: ^10.0.0 - peerDependenciesMeta: - eslint: - optional: true - - '@eslint/object-schema@3.0.3': - resolution: {integrity: sha512-iM869Pugn9Nsxbh/YHRqYiqd23AmIbxJOcpUMOuWCVNdoQJ5ZtwL6h3t0bcZzJUlC3Dq9jCFCESBZnX0GTv7iQ==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - '@eslint/plugin-kit@0.6.1': - resolution: {integrity: sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - '@humanfs/core@0.19.1': - resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} - engines: {node: '>=18.18.0'} - - '@humanfs/node@0.16.7': - resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} - engines: {node: '>=18.18.0'} - - '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - - '@humanwhocodes/retry@0.4.3': - resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} - engines: {node: '>=18.18'} - - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - - '@jridgewell/trace-mapping@0.3.31': - resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - - '@rollup/rollup-android-arm-eabi@4.59.0': - resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.59.0': - resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-darwin-arm64@4.59.0': - resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.59.0': - resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-freebsd-arm64@4.59.0': - resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.59.0': - resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==} - cpu: [x64] - os: [freebsd] - - '@rollup/rollup-linux-arm-gnueabihf@4.59.0': - resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm-musleabihf@4.59.0': - resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm64-gnu@4.59.0': - resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-arm64-musl@4.59.0': - resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-loong64-gnu@4.59.0': - resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-loong64-musl@4.59.0': - resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-ppc64-gnu@4.59.0': - resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-ppc64-musl@4.59.0': - resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-riscv64-gnu@4.59.0': - resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-riscv64-musl@4.59.0': - resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.59.0': - resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==} - cpu: [s390x] - os: [linux] - - '@rollup/rollup-linux-x64-gnu@4.59.0': - resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-linux-x64-musl@4.59.0': - resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-openbsd-x64@4.59.0': - resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==} - cpu: [x64] - os: [openbsd] - - '@rollup/rollup-openharmony-arm64@4.59.0': - resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==} - cpu: [arm64] - os: [openharmony] - - '@rollup/rollup-win32-arm64-msvc@4.59.0': - resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.59.0': - resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-gnu@4.59.0': - resolution: {integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==} - cpu: [x64] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.59.0': - resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==} - cpu: [x64] - os: [win32] - - '@standard-schema/spec@1.1.0': - resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - - '@types/chai@5.2.3': - resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} - - '@types/deep-eql@4.0.2': - resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} - - '@types/esrecurse@4.3.1': - resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} - - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - - '@types/node@25.4.0': - resolution: {integrity: sha512-9wLpoeWuBlcbBpOY3XmzSTG3oscB6xjBEEtn+pYXTfhyXhIxC5FsBer2KTopBlvKEiW9l13po9fq+SJY/5lkhw==} - - '@typescript-eslint/eslint-plugin@8.57.0': - resolution: {integrity: sha512-qeu4rTHR3/IaFORbD16gmjq9+rEs9fGKdX0kF6BKSfi+gCuG3RCKLlSBYzn/bGsY9Tj7KE/DAQStbp8AHJGHEQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@typescript-eslint/parser': ^8.57.0 - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/parser@8.57.0': - resolution: {integrity: sha512-XZzOmihLIr8AD1b9hL9ccNMzEMWt/dE2u7NyTY9jJG6YNiNthaD5XtUHVF2uCXZ15ng+z2hT3MVuxnUYhq6k1g==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/project-service@8.57.0': - resolution: {integrity: sha512-pR+dK0BlxCLxtWfaKQWtYr7MhKmzqZxuii+ZjuFlZlIGRZm22HnXFqa2eY+90MUz8/i80YJmzFGDUsi8dMOV5w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/scope-manager@8.57.0': - resolution: {integrity: sha512-nvExQqAHF01lUM66MskSaZulpPL5pgy5hI5RfrxviLgzZVffB5yYzw27uK/ft8QnKXI2X0LBrHJFr1TaZtAibw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/tsconfig-utils@8.57.0': - resolution: {integrity: sha512-LtXRihc5ytjJIQEH+xqjB0+YgsV4/tW35XKX3GTZHpWtcC8SPkT/d4tqdf1cKtesryHm2bgp6l555NYcT2NLvA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/type-utils@8.57.0': - resolution: {integrity: sha512-yjgh7gmDcJ1+TcEg8x3uWQmn8ifvSupnPfjP21twPKrDP/pTHlEQgmKcitzF/rzPSmv7QjJ90vRpN4U+zoUjwQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/types@8.57.0': - resolution: {integrity: sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/typescript-estree@8.57.0': - resolution: {integrity: sha512-m7faHcyVg0BT3VdYTlX8GdJEM7COexXxS6KqGopxdtkQRvBanK377QDHr4W/vIPAR+ah9+B/RclSW5ldVniO1Q==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/utils@8.57.0': - resolution: {integrity: sha512-5iIHvpD3CZe06riAsbNxxreP+MuYgVUsV0n4bwLH//VJmgtt54sQeY2GszntJ4BjYCpMzrfVh2SBnUQTtys2lQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/visitor-keys@8.57.0': - resolution: {integrity: sha512-zm6xx8UT/Xy2oSr2ZXD0pZo7Jx2XsCoID2IUh9YSTFRu7z+WdwYTRk6LhUftm1crwqbuoF6I8zAFeCMw0YjwDg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@vitest/coverage-v8@4.0.18': - resolution: {integrity: sha512-7i+N2i0+ME+2JFZhfuz7Tg/FqKtilHjGyGvoHYQ6iLV0zahbsJ9sljC9OcFcPDbhYKCet+sG8SsVqlyGvPflZg==} - peerDependencies: - '@vitest/browser': 4.0.18 - vitest: 4.0.18 - peerDependenciesMeta: - '@vitest/browser': - optional: true - - '@vitest/expect@4.0.18': - resolution: {integrity: sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==} - - '@vitest/mocker@4.0.18': - resolution: {integrity: sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==} - peerDependencies: - msw: ^2.4.9 - vite: ^6.0.0 || ^7.0.0-0 - peerDependenciesMeta: - msw: - optional: true - vite: - optional: true - - '@vitest/pretty-format@4.0.18': - resolution: {integrity: sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==} - - '@vitest/runner@4.0.18': - resolution: {integrity: sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==} - - '@vitest/snapshot@4.0.18': - resolution: {integrity: sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==} - - '@vitest/spy@4.0.18': - resolution: {integrity: sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==} - - '@vitest/utils@4.0.18': - resolution: {integrity: sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==} - - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - - acorn@8.16.0: - resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} - engines: {node: '>=0.4.0'} - hasBin: true - - ajv@6.14.0: - resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} - - any-promise@1.3.0: - resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - - assertion-error@2.0.1: - resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} - engines: {node: '>=12'} - - ast-v8-to-istanbul@0.3.12: - resolution: {integrity: sha512-BRRC8VRZY2R4Z4lFIL35MwNXmwVqBityvOIwETtsCSwvjl0IdgFsy9NhdaA6j74nUdtJJlIypeRhpDam19Wq3g==} - - asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - - axios@1.13.6: - resolution: {integrity: sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==} - - balanced-match@4.0.4: - resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} - engines: {node: 18 || 20 || >=22} - - brace-expansion@5.0.4: - resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==} - engines: {node: 18 || 20 || >=22} - - bundle-require@5.1.0: - resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - peerDependencies: - esbuild: '>=0.18' - - cac@6.7.14: - resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} - engines: {node: '>=8'} - - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - - chai@6.2.2: - resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} - engines: {node: '>=18'} - - chokidar@4.0.3: - resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} - engines: {node: '>= 14.16.0'} - - combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - - commander@4.1.1: - resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} - engines: {node: '>= 6'} - - confbox@0.1.8: - resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} - - consola@3.4.2: - resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} - engines: {node: ^14.18.0 || >=16.10.0} - - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - - delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - es-module-lexer@1.7.0: - resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - - es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} - engines: {node: '>= 0.4'} - - esbuild@0.27.3: - resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} - engines: {node: '>=18'} - hasBin: true - - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - - eslint-scope@9.1.2: - resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-visitor-keys@5.0.1: - resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - eslint@10.0.3: - resolution: {integrity: sha512-COV33RzXZkqhG9P2rZCFl9ZmJ7WL+gQSCRzE7RhkbclbQPtLAWReL7ysA0Sh4c8Im2U9ynybdR56PV0XcKvqaQ==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - hasBin: true - peerDependencies: - jiti: '*' - peerDependenciesMeta: - jiti: - optional: true - - espree@11.2.0: - resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - esquery@1.7.0: - resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} - engines: {node: '>=0.10'} - - esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - - estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - - estree-walker@3.0.3: - resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - - expect-type@1.3.0: - resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} - engines: {node: '>=12.0.0'} - - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - - fdir@6.5.0: - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: 4.0.4 - peerDependenciesMeta: - picomatch: - optional: true - - file-entry-cache@8.0.0: - resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} - engines: {node: '>=16.0.0'} - - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - - fix-dts-default-cjs-exports@1.0.1: - resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} - - flat-cache@4.0.1: - resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} - engines: {node: '>=16'} - - flatted@3.4.2: - resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} - - follow-redirects@1.15.11: - resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - - form-data@4.0.5: - resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} - engines: {node: '>= 6'} - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - - html-escaper@2.0.2: - resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} - - ignore@7.0.5: - resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} - engines: {node: '>= 4'} - - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - istanbul-lib-coverage@3.2.2: - resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} - engines: {node: '>=8'} - - istanbul-lib-report@3.0.1: - resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} - engines: {node: '>=10'} - - istanbul-reports@3.2.0: - resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} - engines: {node: '>=8'} - - joycon@3.1.1: - resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} - engines: {node: '>=10'} - - js-tokens@10.0.0: - resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} - - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - - json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} - - lilconfig@3.1.3: - resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} - engines: {node: '>=14'} - - lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - - load-tsconfig@0.2.5: - resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - - magic-string@0.30.21: - resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - - magicast@0.5.2: - resolution: {integrity: sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==} - - make-dir@4.0.0: - resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} - engines: {node: '>=10'} - - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - - mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - - mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - - minimatch@10.2.4: - resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} - engines: {node: 18 || 20 || >=22} - - mlly@1.8.1: - resolution: {integrity: sha512-SnL6sNutTwRWWR/vcmCYHSADjiEesp5TGQQ0pXyLhW5IoeibRlF/CbSLailbB3CNqJUk9cVJ9dUDnbD7GrcHBQ==} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - mz@2.7.0: - resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - - obug@2.1.1: - resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} - - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} - - p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - - p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - pathe@2.0.3: - resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - picomatch@4.0.4: - resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} - engines: {node: '>=12'} - - pirates@4.0.7: - resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} - engines: {node: '>= 6'} - - pkg-types@1.3.1: - resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} - - postcss-load-config@6.0.1: - resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} - engines: {node: '>= 18'} - peerDependencies: - jiti: '>=1.21.0' - postcss: '>=8.0.9' - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - jiti: - optional: true - postcss: - optional: true - tsx: - optional: true - yaml: - optional: true - - postcss@8.5.8: - resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} - engines: {node: ^10 || ^12 || >=14} - - prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - - proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - readdirp@4.1.2: - resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} - engines: {node: '>= 14.18.0'} - - resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} - - rollup@4.59.0: - resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - semver@7.7.4: - resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} - engines: {node: '>=10'} - hasBin: true - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - source-map@0.7.6: - resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} - engines: {node: '>= 12'} - - stackback@0.0.2: - resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - - std-env@3.10.0: - resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} - - sucrase@3.35.1: - resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} - engines: {node: '>=16 || 14 >=14.17'} - hasBin: true - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - - thenify-all@1.6.0: - resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} - engines: {node: '>=0.8'} - - thenify@3.3.1: - resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} - - tinybench@2.9.0: - resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - - tinyexec@0.3.2: - resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - - tinyexec@1.0.2: - resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} - engines: {node: '>=18'} - - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} - engines: {node: '>=12.0.0'} - - tinyrainbow@3.0.3: - resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} - engines: {node: '>=14.0.0'} - - tree-kill@1.2.2: - resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} - hasBin: true - - ts-api-utils@2.4.0: - resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==} - engines: {node: '>=18.12'} - peerDependencies: - typescript: '>=4.8.4' - - ts-interface-checker@0.1.13: - resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - - tsup@8.5.1: - resolution: {integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==} - engines: {node: '>=18'} - hasBin: true - peerDependencies: - '@microsoft/api-extractor': ^7.36.0 - '@swc/core': ^1 - postcss: ^8.4.12 - typescript: '>=4.5.0' - peerDependenciesMeta: - '@microsoft/api-extractor': - optional: true - '@swc/core': - optional: true - postcss: - optional: true - typescript: - optional: true - - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} - hasBin: true - - ufo@1.6.3: - resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} - - undici-types@7.18.2: - resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} - - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - - vite@7.3.1: - resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - jiti: '>=1.21.0' - less: ^4.0.0 - lightningcss: ^1.21.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - - vitest@4.0.18: - resolution: {integrity: sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==} - engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@opentelemetry/api': ^1.9.0 - '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.0.18 - '@vitest/browser-preview': 4.0.18 - '@vitest/browser-webdriverio': 4.0.18 - '@vitest/ui': 4.0.18 - happy-dom: '*' - jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@opentelemetry/api': - optional: true - '@types/node': - optional: true - '@vitest/browser-playwright': - optional: true - '@vitest/browser-preview': - optional: true - '@vitest/browser-webdriverio': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - why-is-node-running@2.3.0: - resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} - engines: {node: '>=8'} - hasBin: true - - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - -snapshots: - - '@babel/helper-string-parser@7.27.1': {} - - '@babel/helper-validator-identifier@7.28.5': {} - - '@babel/parser@7.29.0': - dependencies: - '@babel/types': 7.29.0 - - '@babel/types@7.29.0': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - - '@bcoe/v8-coverage@1.0.2': {} - - '@esbuild/aix-ppc64@0.27.3': - optional: true - - '@esbuild/android-arm64@0.27.3': - optional: true - - '@esbuild/android-arm@0.27.3': - optional: true - - '@esbuild/android-x64@0.27.3': - optional: true - - '@esbuild/darwin-arm64@0.27.3': - optional: true - - '@esbuild/darwin-x64@0.27.3': - optional: true - - '@esbuild/freebsd-arm64@0.27.3': - optional: true - - '@esbuild/freebsd-x64@0.27.3': - optional: true - - '@esbuild/linux-arm64@0.27.3': - optional: true - - '@esbuild/linux-arm@0.27.3': - optional: true - - '@esbuild/linux-ia32@0.27.3': - optional: true - - '@esbuild/linux-loong64@0.27.3': - optional: true - - '@esbuild/linux-mips64el@0.27.3': - optional: true - - '@esbuild/linux-ppc64@0.27.3': - optional: true - - '@esbuild/linux-riscv64@0.27.3': - optional: true - - '@esbuild/linux-s390x@0.27.3': - optional: true - - '@esbuild/linux-x64@0.27.3': - optional: true - - '@esbuild/netbsd-arm64@0.27.3': - optional: true - - '@esbuild/netbsd-x64@0.27.3': - optional: true - - '@esbuild/openbsd-arm64@0.27.3': - optional: true - - '@esbuild/openbsd-x64@0.27.3': - optional: true - - '@esbuild/openharmony-arm64@0.27.3': - optional: true - - '@esbuild/sunos-x64@0.27.3': - optional: true - - '@esbuild/win32-arm64@0.27.3': - optional: true - - '@esbuild/win32-ia32@0.27.3': - optional: true - - '@esbuild/win32-x64@0.27.3': - optional: true - - '@eslint-community/eslint-utils@4.9.1(eslint@10.0.3)': - dependencies: - eslint: 10.0.3 - eslint-visitor-keys: 3.4.3 - - '@eslint-community/regexpp@4.12.2': {} - - '@eslint/config-array@0.23.3': - dependencies: - '@eslint/object-schema': 3.0.3 - debug: 4.4.3 - minimatch: 10.2.4 - transitivePeerDependencies: - - supports-color - - '@eslint/config-helpers@0.5.3': - dependencies: - '@eslint/core': 1.1.1 - - '@eslint/core@1.1.1': - dependencies: - '@types/json-schema': 7.0.15 - - '@eslint/js@10.0.1(eslint@10.0.3)': - optionalDependencies: - eslint: 10.0.3 - - '@eslint/object-schema@3.0.3': {} - - '@eslint/plugin-kit@0.6.1': - dependencies: - '@eslint/core': 1.1.1 - levn: 0.4.1 - - '@humanfs/core@0.19.1': {} - - '@humanfs/node@0.16.7': - dependencies: - '@humanfs/core': 0.19.1 - '@humanwhocodes/retry': 0.4.3 - - '@humanwhocodes/module-importer@1.0.1': {} - - '@humanwhocodes/retry@0.4.3': {} - - '@jridgewell/gen-mapping@0.3.13': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/sourcemap-codec@1.5.5': {} - - '@jridgewell/trace-mapping@0.3.31': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - - '@rollup/rollup-android-arm-eabi@4.59.0': - optional: true - - '@rollup/rollup-android-arm64@4.59.0': - optional: true - - '@rollup/rollup-darwin-arm64@4.59.0': - optional: true - - '@rollup/rollup-darwin-x64@4.59.0': - optional: true - - '@rollup/rollup-freebsd-arm64@4.59.0': - optional: true - - '@rollup/rollup-freebsd-x64@4.59.0': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.59.0': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.59.0': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.59.0': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.59.0': - optional: true - - '@rollup/rollup-linux-loong64-gnu@4.59.0': - optional: true - - '@rollup/rollup-linux-loong64-musl@4.59.0': - optional: true - - '@rollup/rollup-linux-ppc64-gnu@4.59.0': - optional: true - - '@rollup/rollup-linux-ppc64-musl@4.59.0': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.59.0': - optional: true - - '@rollup/rollup-linux-riscv64-musl@4.59.0': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.59.0': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.59.0': - optional: true - - '@rollup/rollup-linux-x64-musl@4.59.0': - optional: true - - '@rollup/rollup-openbsd-x64@4.59.0': - optional: true - - '@rollup/rollup-openharmony-arm64@4.59.0': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.59.0': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.59.0': - optional: true - - '@rollup/rollup-win32-x64-gnu@4.59.0': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.59.0': - optional: true - - '@standard-schema/spec@1.1.0': {} - - '@types/chai@5.2.3': - dependencies: - '@types/deep-eql': 4.0.2 - assertion-error: 2.0.1 - - '@types/deep-eql@4.0.2': {} - - '@types/esrecurse@4.3.1': {} - - '@types/estree@1.0.8': {} - - '@types/json-schema@7.0.15': {} - - '@types/node@25.4.0': - dependencies: - undici-types: 7.18.2 - - '@typescript-eslint/eslint-plugin@8.57.0(@typescript-eslint/parser@8.57.0(eslint@10.0.3)(typescript@5.9.3))(eslint@10.0.3)(typescript@5.9.3)': - dependencies: - '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.57.0(eslint@10.0.3)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.57.0 - '@typescript-eslint/type-utils': 8.57.0(eslint@10.0.3)(typescript@5.9.3) - '@typescript-eslint/utils': 8.57.0(eslint@10.0.3)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.57.0 - eslint: 10.0.3 - ignore: 7.0.5 - natural-compare: 1.4.0 - ts-api-utils: 2.4.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/parser@8.57.0(eslint@10.0.3)(typescript@5.9.3)': - dependencies: - '@typescript-eslint/scope-manager': 8.57.0 - '@typescript-eslint/types': 8.57.0 - '@typescript-eslint/typescript-estree': 8.57.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.57.0 - debug: 4.4.3 - eslint: 10.0.3 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/project-service@8.57.0(typescript@5.9.3)': - dependencies: - '@typescript-eslint/tsconfig-utils': 8.57.0(typescript@5.9.3) - '@typescript-eslint/types': 8.57.0 - debug: 4.4.3 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/scope-manager@8.57.0': - dependencies: - '@typescript-eslint/types': 8.57.0 - '@typescript-eslint/visitor-keys': 8.57.0 - - '@typescript-eslint/tsconfig-utils@8.57.0(typescript@5.9.3)': - dependencies: - typescript: 5.9.3 - - '@typescript-eslint/type-utils@8.57.0(eslint@10.0.3)(typescript@5.9.3)': - dependencies: - '@typescript-eslint/types': 8.57.0 - '@typescript-eslint/typescript-estree': 8.57.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.57.0(eslint@10.0.3)(typescript@5.9.3) - debug: 4.4.3 - eslint: 10.0.3 - ts-api-utils: 2.4.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/types@8.57.0': {} - - '@typescript-eslint/typescript-estree@8.57.0(typescript@5.9.3)': - dependencies: - '@typescript-eslint/project-service': 8.57.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.57.0(typescript@5.9.3) - '@typescript-eslint/types': 8.57.0 - '@typescript-eslint/visitor-keys': 8.57.0 - debug: 4.4.3 - minimatch: 10.2.4 - semver: 7.7.4 - tinyglobby: 0.2.15 - ts-api-utils: 2.4.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@8.57.0(eslint@10.0.3)(typescript@5.9.3)': - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.3) - '@typescript-eslint/scope-manager': 8.57.0 - '@typescript-eslint/types': 8.57.0 - '@typescript-eslint/typescript-estree': 8.57.0(typescript@5.9.3) - eslint: 10.0.3 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/visitor-keys@8.57.0': - dependencies: - '@typescript-eslint/types': 8.57.0 - eslint-visitor-keys: 5.0.1 - - '@vitest/coverage-v8@4.0.18(vitest@4.0.18(@types/node@25.4.0))': - dependencies: - '@bcoe/v8-coverage': 1.0.2 - '@vitest/utils': 4.0.18 - ast-v8-to-istanbul: 0.3.12 - istanbul-lib-coverage: 3.2.2 - istanbul-lib-report: 3.0.1 - istanbul-reports: 3.2.0 - magicast: 0.5.2 - obug: 2.1.1 - std-env: 3.10.0 - tinyrainbow: 3.0.3 - vitest: 4.0.18(@types/node@25.4.0) - - '@vitest/expect@4.0.18': - dependencies: - '@standard-schema/spec': 1.1.0 - '@types/chai': 5.2.3 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 - chai: 6.2.2 - tinyrainbow: 3.0.3 - - '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@25.4.0))': - dependencies: - '@vitest/spy': 4.0.18 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 7.3.1(@types/node@25.4.0) - - '@vitest/pretty-format@4.0.18': - dependencies: - tinyrainbow: 3.0.3 - - '@vitest/runner@4.0.18': - dependencies: - '@vitest/utils': 4.0.18 - pathe: 2.0.3 - - '@vitest/snapshot@4.0.18': - dependencies: - '@vitest/pretty-format': 4.0.18 - magic-string: 0.30.21 - pathe: 2.0.3 - - '@vitest/spy@4.0.18': {} - - '@vitest/utils@4.0.18': - dependencies: - '@vitest/pretty-format': 4.0.18 - tinyrainbow: 3.0.3 - - acorn-jsx@5.3.2(acorn@8.16.0): - dependencies: - acorn: 8.16.0 - - acorn@8.16.0: {} - - ajv@6.14.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - - any-promise@1.3.0: {} - - assertion-error@2.0.1: {} - - ast-v8-to-istanbul@0.3.12: - dependencies: - '@jridgewell/trace-mapping': 0.3.31 - estree-walker: 3.0.3 - js-tokens: 10.0.0 - - asynckit@0.4.0: {} - - axios@1.13.6: - dependencies: - follow-redirects: 1.15.11 - form-data: 4.0.5 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - - balanced-match@4.0.4: {} - - brace-expansion@5.0.4: - dependencies: - balanced-match: 4.0.4 - - bundle-require@5.1.0(esbuild@0.27.3): - dependencies: - esbuild: 0.27.3 - load-tsconfig: 0.2.5 - - cac@6.7.14: {} - - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - chai@6.2.2: {} - - chokidar@4.0.3: - dependencies: - readdirp: 4.1.2 - - combined-stream@1.0.8: - dependencies: - delayed-stream: 1.0.0 - - commander@4.1.1: {} - - confbox@0.1.8: {} - - consola@3.4.2: {} - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - debug@4.4.3: - dependencies: - ms: 2.1.3 - - deep-is@0.1.4: {} - - delayed-stream@1.0.0: {} - - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - - es-module-lexer@1.7.0: {} - - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 - - es-set-tostringtag@2.1.0: - dependencies: - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - - esbuild@0.27.3: - optionalDependencies: - '@esbuild/aix-ppc64': 0.27.3 - '@esbuild/android-arm': 0.27.3 - '@esbuild/android-arm64': 0.27.3 - '@esbuild/android-x64': 0.27.3 - '@esbuild/darwin-arm64': 0.27.3 - '@esbuild/darwin-x64': 0.27.3 - '@esbuild/freebsd-arm64': 0.27.3 - '@esbuild/freebsd-x64': 0.27.3 - '@esbuild/linux-arm': 0.27.3 - '@esbuild/linux-arm64': 0.27.3 - '@esbuild/linux-ia32': 0.27.3 - '@esbuild/linux-loong64': 0.27.3 - '@esbuild/linux-mips64el': 0.27.3 - '@esbuild/linux-ppc64': 0.27.3 - '@esbuild/linux-riscv64': 0.27.3 - '@esbuild/linux-s390x': 0.27.3 - '@esbuild/linux-x64': 0.27.3 - '@esbuild/netbsd-arm64': 0.27.3 - '@esbuild/netbsd-x64': 0.27.3 - '@esbuild/openbsd-arm64': 0.27.3 - '@esbuild/openbsd-x64': 0.27.3 - '@esbuild/openharmony-arm64': 0.27.3 - '@esbuild/sunos-x64': 0.27.3 - '@esbuild/win32-arm64': 0.27.3 - '@esbuild/win32-ia32': 0.27.3 - '@esbuild/win32-x64': 0.27.3 - - escape-string-regexp@4.0.0: {} - - eslint-scope@9.1.2: - dependencies: - '@types/esrecurse': 4.3.1 - '@types/estree': 1.0.8 - esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-visitor-keys@3.4.3: {} - - eslint-visitor-keys@5.0.1: {} - - eslint@10.0.3: - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.3) - '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.23.3 - '@eslint/config-helpers': 0.5.3 - '@eslint/core': 1.1.1 - '@eslint/plugin-kit': 0.6.1 - '@humanfs/node': 0.16.7 - '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.8 - ajv: 6.14.0 - cross-spawn: 7.0.6 - debug: 4.4.3 - escape-string-regexp: 4.0.0 - eslint-scope: 9.1.2 - eslint-visitor-keys: 5.0.1 - espree: 11.2.0 - esquery: 1.7.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 - find-up: 5.0.0 - glob-parent: 6.0.2 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - json-stable-stringify-without-jsonify: 1.0.1 - minimatch: 10.2.4 - natural-compare: 1.4.0 - optionator: 0.9.4 - transitivePeerDependencies: - - supports-color - - espree@11.2.0: - dependencies: - acorn: 8.16.0 - acorn-jsx: 5.3.2(acorn@8.16.0) - eslint-visitor-keys: 5.0.1 - - esquery@1.7.0: - dependencies: - estraverse: 5.3.0 - - esrecurse@4.3.0: - dependencies: - estraverse: 5.3.0 - - estraverse@5.3.0: {} - - estree-walker@3.0.3: - dependencies: - '@types/estree': 1.0.8 - - esutils@2.0.3: {} - - expect-type@1.3.0: {} - - fast-deep-equal@3.1.3: {} - - fast-json-stable-stringify@2.1.0: {} - - fast-levenshtein@2.0.6: {} - - fdir@6.5.0(picomatch@4.0.4): - optionalDependencies: - picomatch: 4.0.4 - - file-entry-cache@8.0.0: - dependencies: - flat-cache: 4.0.1 - - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - fix-dts-default-cjs-exports@1.0.1: - dependencies: - magic-string: 0.30.21 - mlly: 1.8.1 - rollup: 4.59.0 - - flat-cache@4.0.1: - dependencies: - flatted: 3.4.2 - keyv: 4.5.4 - - flatted@3.4.2: {} - - follow-redirects@1.15.11: {} - - form-data@4.0.5: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - hasown: 2.0.2 - mime-types: 2.1.35 - - fsevents@2.3.3: - optional: true - - function-bind@1.1.2: {} - - get-intrinsic@1.3.0: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - - glob-parent@6.0.2: - dependencies: - is-glob: 4.0.3 - - gopd@1.2.0: {} - - has-flag@4.0.0: {} - - has-symbols@1.1.0: {} - - has-tostringtag@1.0.2: - dependencies: - has-symbols: 1.1.0 - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - html-escaper@2.0.2: {} - - ignore@5.3.2: {} - - ignore@7.0.5: {} - - imurmurhash@0.1.4: {} - - is-extglob@2.1.1: {} - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - isexe@2.0.0: {} - - istanbul-lib-coverage@3.2.2: {} - - istanbul-lib-report@3.0.1: - dependencies: - istanbul-lib-coverage: 3.2.2 - make-dir: 4.0.0 - supports-color: 7.2.0 - - istanbul-reports@3.2.0: - dependencies: - html-escaper: 2.0.2 - istanbul-lib-report: 3.0.1 - - joycon@3.1.1: {} - - js-tokens@10.0.0: {} - - json-buffer@3.0.1: {} - - json-schema-traverse@0.4.1: {} - - json-stable-stringify-without-jsonify@1.0.1: {} - - keyv@4.5.4: - dependencies: - json-buffer: 3.0.1 - - levn@0.4.1: - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - - lilconfig@3.1.3: {} - - lines-and-columns@1.2.4: {} - - load-tsconfig@0.2.5: {} - - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 - - magic-string@0.30.21: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - - magicast@0.5.2: - dependencies: - '@babel/parser': 7.29.0 - '@babel/types': 7.29.0 - source-map-js: 1.2.1 - - make-dir@4.0.0: - dependencies: - semver: 7.7.4 - - math-intrinsics@1.1.0: {} - - mime-db@1.52.0: {} - - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - - minimatch@10.2.4: - dependencies: - brace-expansion: 5.0.4 - - mlly@1.8.1: - dependencies: - acorn: 8.16.0 - pathe: 2.0.3 - pkg-types: 1.3.1 - ufo: 1.6.3 - - ms@2.1.3: {} - - mz@2.7.0: - dependencies: - any-promise: 1.3.0 - object-assign: 4.1.1 - thenify-all: 1.6.0 - - nanoid@3.3.11: {} - - natural-compare@1.4.0: {} - - object-assign@4.1.1: {} - - obug@2.1.1: {} - - optionator@0.9.4: - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 - - p-limit@3.1.0: - dependencies: - yocto-queue: 0.1.0 - - p-locate@5.0.0: - dependencies: - p-limit: 3.1.0 - - path-exists@4.0.0: {} - - path-key@3.1.1: {} - - pathe@2.0.3: {} - - picocolors@1.1.1: {} - - picomatch@4.0.4: {} - - pirates@4.0.7: {} - - pkg-types@1.3.1: - dependencies: - confbox: 0.1.8 - mlly: 1.8.1 - pathe: 2.0.3 - - postcss-load-config@6.0.1(postcss@8.5.8): - dependencies: - lilconfig: 3.1.3 - optionalDependencies: - postcss: 8.5.8 - - postcss@8.5.8: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - prelude-ls@1.2.1: {} - - proxy-from-env@1.1.0: {} - - punycode@2.3.1: {} - - readdirp@4.1.2: {} - - resolve-from@5.0.0: {} - - rollup@4.59.0: - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.59.0 - '@rollup/rollup-android-arm64': 4.59.0 - '@rollup/rollup-darwin-arm64': 4.59.0 - '@rollup/rollup-darwin-x64': 4.59.0 - '@rollup/rollup-freebsd-arm64': 4.59.0 - '@rollup/rollup-freebsd-x64': 4.59.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.59.0 - '@rollup/rollup-linux-arm-musleabihf': 4.59.0 - '@rollup/rollup-linux-arm64-gnu': 4.59.0 - '@rollup/rollup-linux-arm64-musl': 4.59.0 - '@rollup/rollup-linux-loong64-gnu': 4.59.0 - '@rollup/rollup-linux-loong64-musl': 4.59.0 - '@rollup/rollup-linux-ppc64-gnu': 4.59.0 - '@rollup/rollup-linux-ppc64-musl': 4.59.0 - '@rollup/rollup-linux-riscv64-gnu': 4.59.0 - '@rollup/rollup-linux-riscv64-musl': 4.59.0 - '@rollup/rollup-linux-s390x-gnu': 4.59.0 - '@rollup/rollup-linux-x64-gnu': 4.59.0 - '@rollup/rollup-linux-x64-musl': 4.59.0 - '@rollup/rollup-openbsd-x64': 4.59.0 - '@rollup/rollup-openharmony-arm64': 4.59.0 - '@rollup/rollup-win32-arm64-msvc': 4.59.0 - '@rollup/rollup-win32-ia32-msvc': 4.59.0 - '@rollup/rollup-win32-x64-gnu': 4.59.0 - '@rollup/rollup-win32-x64-msvc': 4.59.0 - fsevents: 2.3.3 - - semver@7.7.4: {} - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - siginfo@2.0.0: {} - - source-map-js@1.2.1: {} - - source-map@0.7.6: {} - - stackback@0.0.2: {} - - std-env@3.10.0: {} - - sucrase@3.35.1: - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - commander: 4.1.1 - lines-and-columns: 1.2.4 - mz: 2.7.0 - pirates: 4.0.7 - tinyglobby: 0.2.15 - ts-interface-checker: 0.1.13 - - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - - thenify-all@1.6.0: - dependencies: - thenify: 3.3.1 - - thenify@3.3.1: - dependencies: - any-promise: 1.3.0 - - tinybench@2.9.0: {} - - tinyexec@0.3.2: {} - - tinyexec@1.0.2: {} - - tinyglobby@0.2.15: - dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 - - tinyrainbow@3.0.3: {} - - tree-kill@1.2.2: {} - - ts-api-utils@2.4.0(typescript@5.9.3): - dependencies: - typescript: 5.9.3 - - ts-interface-checker@0.1.13: {} - - tsup@8.5.1(postcss@8.5.8)(typescript@5.9.3): - dependencies: - bundle-require: 5.1.0(esbuild@0.27.3) - cac: 6.7.14 - chokidar: 4.0.3 - consola: 3.4.2 - debug: 4.4.3 - esbuild: 0.27.3 - fix-dts-default-cjs-exports: 1.0.1 - joycon: 3.1.1 - picocolors: 1.1.1 - postcss-load-config: 6.0.1(postcss@8.5.8) - resolve-from: 5.0.0 - rollup: 4.59.0 - source-map: 0.7.6 - sucrase: 3.35.1 - tinyexec: 0.3.2 - tinyglobby: 0.2.15 - tree-kill: 1.2.2 - optionalDependencies: - postcss: 8.5.8 - typescript: 5.9.3 - transitivePeerDependencies: - - jiti - - supports-color - - tsx - - yaml - - type-check@0.4.0: - dependencies: - prelude-ls: 1.2.1 - - typescript@5.9.3: {} - - ufo@1.6.3: {} - - undici-types@7.18.2: {} - - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - - vite@7.3.1(@types/node@25.4.0): - dependencies: - esbuild: 0.27.3 - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 - postcss: 8.5.8 - rollup: 4.59.0 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 25.4.0 - fsevents: 2.3.3 - - vitest@4.0.18(@types/node@25.4.0): - dependencies: - '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@25.4.0)) - '@vitest/pretty-format': 4.0.18 - '@vitest/runner': 4.0.18 - '@vitest/snapshot': 4.0.18 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 - es-module-lexer: 1.7.0 - expect-type: 1.3.0 - magic-string: 0.30.21 - obug: 2.1.1 - pathe: 2.0.3 - picomatch: 4.0.4 - std-env: 3.10.0 - tinybench: 2.9.0 - tinyexec: 1.0.2 - tinyglobby: 0.2.15 - tinyrainbow: 3.0.3 - vite: 7.3.1(@types/node@25.4.0) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 25.4.0 - transitivePeerDependencies: - - jiti - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - yaml - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - why-is-node-running@2.3.0: - dependencies: - siginfo: 2.0.0 - stackback: 0.0.2 - - word-wrap@1.2.5: {} - - yocto-queue@0.1.0: {} diff --git a/sdks/nodejs-client/pnpm-workspace.yaml b/sdks/nodejs-client/pnpm-workspace.yaml deleted file mode 100644 index efc037aa84..0000000000 --- a/sdks/nodejs-client/pnpm-workspace.yaml +++ /dev/null @@ -1,2 +0,0 @@ -onlyBuiltDependencies: - - esbuild diff --git a/sdks/nodejs-client/scripts/publish.sh b/sdks/nodejs-client/scripts/publish.sh index 043cac046d..5f8e73f8c0 100755 --- a/sdks/nodejs-client/scripts/publish.sh +++ b/sdks/nodejs-client/scripts/publish.sh @@ -5,10 +5,12 @@ # A beautiful and reliable script to publish the SDK to npm # # Usage: -# ./scripts/publish.sh # Normal publish +# ./scripts/publish.sh # Normal publish # ./scripts/publish.sh --dry-run # Test without publishing # ./scripts/publish.sh --skip-tests # Skip tests (not recommended) # +# This script requires pnpm because the workspace uses catalog: dependencies. +# set -euo pipefail @@ -62,11 +64,27 @@ divider() { echo -e "${DIM}─────────────────────────────────────────────────────────────────${NC}" } +run_npm() { + env \ + -u npm_config_npm_globalconfig \ + -u NPM_CONFIG_NPM_GLOBALCONFIG \ + -u npm_config_verify_deps_before_run \ + -u NPM_CONFIG_VERIFY_DEPS_BEFORE_RUN \ + -u npm_config__jsr_registry \ + -u NPM_CONFIG__JSR_REGISTRY \ + -u npm_config_catalog \ + -u NPM_CONFIG_CATALOG \ + -u npm_config_overrides \ + -u NPM_CONFIG_OVERRIDES \ + npm "$@" +} + # ============================================================================ # Configuration # ============================================================================ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +REPO_ROOT="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null || (cd "$SCRIPT_DIR/../../.." && pwd))" DRY_RUN=false SKIP_TESTS=false @@ -123,23 +141,23 @@ main() { error "npm is not installed" exit 1 fi - NPM_VERSION=$(npm -v) + NPM_VERSION=$(run_npm -v) success "npm: v$NPM_VERSION" - # Check pnpm (optional, for local dev) - if command -v pnpm &> /dev/null; then - PNPM_VERSION=$(pnpm -v) - success "pnpm: v$PNPM_VERSION" - else - info "pnpm not found (optional)" + if ! command -v pnpm &> /dev/null; then + error "pnpm is required because this workspace publishes catalog: dependencies" + info "Install pnpm with Corepack: corepack enable" + exit 1 fi + PNPM_VERSION=$(pnpm -v) + success "pnpm: v$PNPM_VERSION" # Check npm login status - if ! npm whoami &> /dev/null; then + if ! run_npm whoami &> /dev/null; then error "Not logged in to npm. Run 'npm login' first." exit 1 fi - NPM_USER=$(npm whoami) + NPM_USER=$(run_npm whoami) success "Logged in as: ${BOLD}$NPM_USER${NC}" # ======================================================================== @@ -154,11 +172,11 @@ main() { success "Version: ${BOLD}$PACKAGE_VERSION${NC}" # Check if version already exists on npm - if npm view "$PACKAGE_NAME@$PACKAGE_VERSION" version &> /dev/null; then + if run_npm view "$PACKAGE_NAME@$PACKAGE_VERSION" version &> /dev/null; then error "Version $PACKAGE_VERSION already exists on npm!" echo "" info "Current published versions:" - npm view "$PACKAGE_NAME" versions --json 2>/dev/null | tail -5 + run_npm view "$PACKAGE_NAME" versions --json 2>/dev/null | tail -5 echo "" warning "Please update the version in package.json before publishing." exit 1 @@ -170,11 +188,7 @@ main() { # ======================================================================== step "Step 3/6: Installing dependencies..." - if command -v pnpm &> /dev/null; then - pnpm install --frozen-lockfile 2>/dev/null || pnpm install - else - npm ci 2>/dev/null || npm install - fi + pnpm --dir "$REPO_ROOT" install --frozen-lockfile 2>/dev/null || pnpm --dir "$REPO_ROOT" install success "Dependencies installed" # ======================================================================== @@ -185,11 +199,7 @@ main() { if [[ "$SKIP_TESTS" == true ]]; then warning "Skipping tests (--skip-tests flag)" else - if command -v pnpm &> /dev/null; then - pnpm test - else - npm test - fi + pnpm test success "All tests passed" fi @@ -201,11 +211,7 @@ main() { # Clean previous build rm -rf dist - if command -v pnpm &> /dev/null; then - pnpm run build - else - npm run build - fi + pnpm run build success "Build completed" # Verify build output @@ -223,15 +229,32 @@ main() { # Step 6: Publish # ======================================================================== step "Step 6/6: Publishing to npm..." - + + PACK_DIR="$(mktemp -d)" + trap 'rm -rf "$PACK_DIR"' EXIT + + pnpm pack --pack-destination "$PACK_DIR" >/dev/null + PACKAGE_TARBALL="$(find "$PACK_DIR" -maxdepth 1 -name '*.tgz' | head -n 1)" + + if [[ -z "$PACKAGE_TARBALL" ]]; then + error "Pack failed - no tarball generated" + exit 1 + fi + + if tar -xOf "$PACKAGE_TARBALL" package/package.json | grep -q '"catalog:'; then + error "Packed manifest still contains catalog: references" + exit 1 + fi + divider echo -e "${CYAN}Package contents:${NC}" - npm pack --dry-run 2>&1 | head -30 + tar -tzf "$PACKAGE_TARBALL" | head -30 divider if [[ "$DRY_RUN" == true ]]; then warning "DRY-RUN: Skipping actual publish" echo "" + info "Packed artifact: $PACKAGE_TARBALL" info "To publish for real, run without --dry-run flag" else echo "" @@ -239,7 +262,7 @@ main() { echo -e "${DIM}Press Enter to continue, or Ctrl+C to cancel...${NC}" read -r - npm publish --access public + pnpm publish --access public --no-git-checks echo "" success "🎉 Successfully published ${BOLD}$PACKAGE_NAME@$PACKAGE_VERSION${NC} to npm!" diff --git a/web/taze.config.js b/taze.config.js similarity index 95% rename from web/taze.config.js rename to taze.config.js index 7ffd76f94e..d21756e207 100644 --- a/web/taze.config.js +++ b/taze.config.js @@ -10,6 +10,7 @@ export default defineConfig({ // We can not upgrade these yet 'tailwind-merge', 'tailwindcss', + 'typescript', ], write: true, diff --git a/web/.dockerignore b/web/.dockerignore deleted file mode 100644 index 91437a2259..0000000000 --- a/web/.dockerignore +++ /dev/null @@ -1,32 +0,0 @@ -.env -.env.* - -# Logs -logs -*.log* - -# node -node_modules -dist -build -coverage -.husky -.next -.pnpm-store - -# vscode -.vscode - -# webstorm -.idea -*.iml -*.iws -*.ipr - - -# Jetbrains -.idea - -# git -.git -.gitignore \ No newline at end of file diff --git a/web/Dockerfile b/web/Dockerfile index b54bae706c..75024db4f3 100644 --- a/web/Dockerfile +++ b/web/Dockerfile @@ -19,21 +19,27 @@ ENV NEXT_PUBLIC_BASE_PATH="$NEXT_PUBLIC_BASE_PATH" # install packages FROM base AS packages -WORKDIR /app/web +WORKDIR /app -COPY package.json pnpm-lock.yaml /app/web/ +COPY package.json pnpm-lock.yaml pnpm-workspace.yaml /app/ +COPY web/package.json /app/web/ +COPY e2e/package.json /app/e2e/ +COPY sdks/nodejs-client/package.json /app/sdks/nodejs-client/ # Use packageManager from package.json RUN corepack install -RUN pnpm install --frozen-lockfile +# Install only the web workspace to keep image builds from pulling in +# unrelated workspace dependencies such as e2e tooling. +RUN pnpm install --filter ./web... --frozen-lockfile # build resources FROM base AS builder -WORKDIR /app/web -COPY --from=packages /app/web/ . +WORKDIR /app +COPY --from=packages /app/ . COPY . . +WORKDIR /app/web ENV NODE_OPTIONS="--max-old-space-size=4096" RUN pnpm build @@ -64,13 +70,13 @@ RUN addgroup -S -g ${dify_uid} dify && \ chown -R dify:dify /app -WORKDIR /app/web +WORKDIR /app -COPY --from=builder --chown=dify:dify /app/web/public ./public +COPY --from=builder --chown=dify:dify /app/web/public ./web/public COPY --from=builder --chown=dify:dify /app/web/.next/standalone ./ -COPY --from=builder --chown=dify:dify /app/web/.next/static ./.next/static +COPY --from=builder --chown=dify:dify /app/web/.next/static ./web/.next/static -COPY --chown=dify:dify --chmod=755 docker/entrypoint.sh ./entrypoint.sh +COPY --chown=dify:dify --chmod=755 web/docker/entrypoint.sh ./entrypoint.sh ARG COMMIT_SHA ENV COMMIT_SHA=${COMMIT_SHA} diff --git a/web/Dockerfile.dockerignore b/web/Dockerfile.dockerignore new file mode 100644 index 0000000000..9801003d89 --- /dev/null +++ b/web/Dockerfile.dockerignore @@ -0,0 +1,34 @@ +** +!package.json +!pnpm-lock.yaml +!pnpm-workspace.yaml +!.nvmrc +!web/ +!web/** +!e2e/ +!e2e/package.json +!sdks/ +!sdks/nodejs-client/ +!sdks/nodejs-client/package.json + +.git +node_modules +.pnpm-store +web/.env +web/.env.* +web/logs +web/*.log* +web/node_modules +web/dist +web/build +web/coverage +web/.husky +web/.next +web/.pnpm-store +web/.vscode +web/.idea +web/*.iml +web/*.iws +web/*.ipr +e2e/node_modules +sdks/nodejs-client/node_modules diff --git a/web/README.md b/web/README.md index 14ca856875..2d69a94dbd 100644 --- a/web/README.md +++ b/web/README.md @@ -24,18 +24,24 @@ For example, use `vp install` instead of `pnpm install` and `vp test` instead of > > Learn more: [Corepack] +Run the following commands from the repository root. + First, install the dependencies: ```bash pnpm install ``` +> [!NOTE] +> JavaScript dependencies are managed by the workspace files at the repository root: `package.json`, `pnpm-lock.yaml`, `pnpm-workspace.yaml`, and `.nvmrc`. +> Install dependencies from the repository root, then run frontend scripts from `web/`. + Then, configure the environment variables. -Create a file named `.env.local` in the current directory and copy the contents from `.env.example`. +Create `web/.env.local` and copy the contents from `web/.env.example`. Modify the values of these environment variables according to your requirements: ```bash -cp .env.example .env.local +cp web/.env.example web/.env.local ``` > [!IMPORTANT] @@ -46,16 +52,16 @@ cp .env.example .env.local Finally, run the development server: ```bash -pnpm run dev +pnpm -C web run dev # or if you are using vinext which provides a better development experience -pnpm run dev:vinext +pnpm -C web run dev:vinext # (optional) start the dev proxy server so that you can use online API in development -pnpm run dev:proxy +pnpm -C web run dev:proxy ``` Open with your browser to see the result. -You can start editing the file under folder `app`. +You can start editing the files under `web/app`. The page auto-updates as you edit the file. ## Deploy @@ -65,19 +71,25 @@ The page auto-updates as you edit the file. First, build the app for production: ```bash -pnpm run build +pnpm -C web run build ``` Then, start the server: ```bash -pnpm run start +pnpm -C web run start +``` + +If you build the Docker image manually, use the repository root as the build context: + +```bash +docker build -f web/Dockerfile -t dify-web . ``` If you want to customize the host and port: ```bash -pnpm run start --port=3001 --host=0.0.0.0 +pnpm -C web run start --port=3001 --host=0.0.0.0 ``` ## Storybook @@ -87,7 +99,7 @@ This project uses [Storybook] for UI component development. To start the storybook server, run: ```bash -pnpm storybook +pnpm -C web storybook ``` Open with your browser to see the result. @@ -112,7 +124,7 @@ We use [Vitest] and [React Testing Library] for Unit Testing. Run test: ```bash -pnpm test +pnpm -C web test ``` > [!NOTE] diff --git a/web/app/components/app/configuration/config/config-audio.spec.tsx b/web/app/components/app/configuration/config/config-audio.spec.tsx index a3e5c7c149..cad0b40b95 100644 --- a/web/app/components/app/configuration/config/config-audio.spec.tsx +++ b/web/app/components/app/configuration/config/config-audio.spec.tsx @@ -1,4 +1,3 @@ -import type { Mock } from 'vitest' import type { FeatureStoreState } from '@/app/components/base/features/store' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' @@ -28,7 +27,7 @@ type SetupOptions = { } let mockFeatureStoreState: FeatureStoreState -let mockSetFeatures: Mock +let mockSetFeatures = vi.fn() const mockStore = { getState: vi.fn<() => FeatureStoreState>(() => mockFeatureStoreState), } diff --git a/web/app/components/app/configuration/config/config-document.spec.tsx b/web/app/components/app/configuration/config/config-document.spec.tsx index 2aa87717fc..300acb7ce7 100644 --- a/web/app/components/app/configuration/config/config-document.spec.tsx +++ b/web/app/components/app/configuration/config/config-document.spec.tsx @@ -1,4 +1,3 @@ -import type { Mock } from 'vitest' import type { FeatureStoreState } from '@/app/components/base/features/store' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' @@ -28,7 +27,7 @@ type SetupOptions = { } let mockFeatureStoreState: FeatureStoreState -let mockSetFeatures: Mock +let mockSetFeatures = vi.fn() const mockStore = { getState: vi.fn<() => FeatureStoreState>(() => mockFeatureStoreState), } diff --git a/web/app/components/app/configuration/config/index.spec.tsx b/web/app/components/app/configuration/config/index.spec.tsx index 875e583397..b24c719b99 100644 --- a/web/app/components/app/configuration/config/index.spec.tsx +++ b/web/app/components/app/configuration/config/index.spec.tsx @@ -1,4 +1,3 @@ -import type { Mock } from 'vitest' import type { ModelConfig, PromptVariable } from '@/models/debug' import type { ToolItem } from '@/types/app' import { render, screen } from '@testing-library/react' @@ -74,10 +73,10 @@ type MockContext = { history: boolean query: boolean } - showHistoryModal: Mock + showHistoryModal: () => void modelConfig: ModelConfig - setModelConfig: Mock - setPrevPromptConfig: Mock + setModelConfig: (modelConfig: ModelConfig) => void + setPrevPromptConfig: (configs: ModelConfig['configs']) => void } const createPromptVariable = (overrides: Partial = {}): PromptVariable => ({ @@ -142,7 +141,7 @@ const createContextValue = (overrides: Partial = {}): MockContext = ...overrides, }) -const mockUseContext = useContextSelector.useContext as Mock +const mockUseContext = vi.mocked(useContextSelector.useContext) const renderConfig = (contextOverrides: Partial = {}) => { const contextValue = createContextValue(contextOverrides) diff --git a/web/app/components/apps/hooks/__tests__/use-dsl-drag-drop.spec.ts b/web/app/components/apps/hooks/__tests__/use-dsl-drag-drop.spec.ts index 58fed4caa8..00e2d69ab2 100644 --- a/web/app/components/apps/hooks/__tests__/use-dsl-drag-drop.spec.ts +++ b/web/app/components/apps/hooks/__tests__/use-dsl-drag-drop.spec.ts @@ -1,16 +1,15 @@ -import type { Mock } from 'vitest' import { act, renderHook } from '@testing-library/react' import { useDSLDragDrop } from '../use-dsl-drag-drop' describe('useDSLDragDrop', () => { let container: HTMLDivElement - let mockOnDSLFileDropped: Mock + let mockOnDSLFileDropped = vi.fn<(file: File) => void>() beforeEach(() => { vi.clearAllMocks() container = document.createElement('div') document.body.appendChild(container) - mockOnDSLFileDropped = vi.fn() + mockOnDSLFileDropped = vi.fn<(file: File) => void>() }) afterEach(() => { diff --git a/web/app/components/base/carousel/__tests__/index.spec.tsx b/web/app/components/base/carousel/__tests__/index.spec.tsx index cc45256937..e409b85757 100644 --- a/web/app/components/base/carousel/__tests__/index.spec.tsx +++ b/web/app/components/base/carousel/__tests__/index.spec.tsx @@ -11,15 +11,15 @@ type EmblaEventName = 'reInit' | 'select' type EmblaListener = (api: MockEmblaApi | undefined) => void type MockEmblaApi = { - scrollPrev: Mock - scrollNext: Mock - scrollTo: Mock - selectedScrollSnap: Mock - canScrollPrev: Mock - canScrollNext: Mock - slideNodes: Mock - on: Mock - off: Mock + scrollPrev: Mock<() => void> + scrollNext: Mock<() => void> + scrollTo: Mock<(index: number) => void> + selectedScrollSnap: Mock<() => number> + canScrollPrev: Mock<() => boolean> + canScrollNext: Mock<() => boolean> + slideNodes: Mock<() => HTMLDivElement[]> + on: Mock<(event: EmblaEventName, callback: EmblaListener) => void> + off: Mock<(event: EmblaEventName, callback: EmblaListener) => void> } let mockCanScrollPrev = false @@ -33,19 +33,19 @@ const mockCarouselRef = vi.fn() const mockedUseEmblaCarousel = vi.mocked(useEmblaCarousel) const createMockEmblaApi = (): MockEmblaApi => ({ - scrollPrev: vi.fn(), - scrollNext: vi.fn(), - scrollTo: vi.fn(), - selectedScrollSnap: vi.fn(() => mockSelectedIndex), - canScrollPrev: vi.fn(() => mockCanScrollPrev), - canScrollNext: vi.fn(() => mockCanScrollNext), - slideNodes: vi.fn(() => - Array.from({ length: mockSlideCount }).fill(document.createElement('div')), + scrollPrev: vi.fn<() => void>(), + scrollNext: vi.fn<() => void>(), + scrollTo: vi.fn<(index: number) => void>(), + selectedScrollSnap: vi.fn<() => number>(() => mockSelectedIndex), + canScrollPrev: vi.fn<() => boolean>(() => mockCanScrollPrev), + canScrollNext: vi.fn<() => boolean>(() => mockCanScrollNext), + slideNodes: vi.fn<() => HTMLDivElement[]>(() => + Array.from({ length: mockSlideCount }, () => document.createElement('div')), ), - on: vi.fn((event: EmblaEventName, callback: EmblaListener) => { + on: vi.fn<(event: EmblaEventName, callback: EmblaListener) => void>((event, callback) => { listeners[event].push(callback) }), - off: vi.fn((event: EmblaEventName, callback: EmblaListener) => { + off: vi.fn<(event: EmblaEventName, callback: EmblaListener) => void>((event, callback) => { listeners[event] = listeners[event].filter(listener => listener !== callback) }), }) diff --git a/web/app/components/billing/upgrade-btn/__tests__/index.spec.tsx b/web/app/components/billing/upgrade-btn/__tests__/index.spec.tsx index 1840f1d33c..7eda24b944 100644 --- a/web/app/components/billing/upgrade-btn/__tests__/index.spec.tsx +++ b/web/app/components/billing/upgrade-btn/__tests__/index.spec.tsx @@ -1,4 +1,3 @@ -import type { Mock } from 'vitest' import { render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import UpgradeBtn from '../index' @@ -14,14 +13,16 @@ vi.mock('@/context/modal-context', () => ({ }), })) +type GtagHandler = (command: string, action: string, payload: { loc: string }) => void + // Typed window accessor for gtag tracking tests -const gtagWindow = window as unknown as Record -let mockGtag: Mock | undefined +const gtagWindow = window as unknown as { gtag?: GtagHandler } +let mockGtag = vi.fn() describe('UpgradeBtn', () => { beforeEach(() => { vi.clearAllMocks() - mockGtag = vi.fn() + mockGtag = vi.fn() gtagWindow.gtag = mockGtag }) diff --git a/web/eslint.config.mjs b/web/eslint.config.mjs index 940aad9f4c..020e960d73 100644 --- a/web/eslint.config.mjs +++ b/web/eslint.config.mjs @@ -56,6 +56,7 @@ export default antfu( }, }, e18e: false, + pnpm: false, }, { plugins: { diff --git a/web/next.config.ts b/web/next.config.ts index 838aa561a3..aa4d9318f4 100644 --- a/web/next.config.ts +++ b/web/next.config.ts @@ -10,7 +10,6 @@ const nextConfig: NextConfig = { basePath: env.NEXT_PUBLIC_BASE_PATH, transpilePackages: ['@t3-oss/env-core', '@t3-oss/env-nextjs', 'echarts', 'zrender'], turbopack: { - root: process.cwd(), rules: codeInspectorPlugin({ bundler: 'turbopack', }), diff --git a/web/package.json b/web/package.json index 65372ef5f5..9ed21fdb22 100644 --- a/web/package.json +++ b/web/package.json @@ -3,7 +3,6 @@ "type": "module", "version": "1.13.3", "private": true, - "packageManager": "pnpm@10.32.1", "imports": { "#i18n": { "react-server": "./i18n-config/lib.server.ts", @@ -22,9 +21,6 @@ "and_uc >= 15.5", "and_qq >= 14.9" ], - "engines": { - "node": "^22.22.1" - }, "scripts": { "analyze": "next experimental-analyze", "analyze-component": "node ./scripts/analyze-component.js", @@ -58,258 +54,189 @@ "uglify-embed": "node ./bin/uglify-embed" }, "dependencies": { - "@amplitude/analytics-browser": "2.37.0", - "@amplitude/plugin-session-replay-browser": "1.27.1", - "@base-ui/react": "1.3.0", - "@emoji-mart/data": "1.2.1", - "@floating-ui/react": "0.27.19", - "@formatjs/intl-localematcher": "0.8.2", - "@headlessui/react": "2.2.9", - "@heroicons/react": "2.2.0", - "@lexical/code": "0.42.0", - "@lexical/link": "0.42.0", - "@lexical/list": "0.42.0", - "@lexical/react": "0.42.0", - "@lexical/selection": "0.42.0", - "@lexical/text": "0.42.0", - "@lexical/utils": "0.42.0", - "@monaco-editor/react": "4.7.0", - "@orpc/client": "1.13.9", - "@orpc/contract": "1.13.9", - "@orpc/openapi-client": "1.13.9", - "@orpc/tanstack-query": "1.13.9", - "@remixicon/react": "4.9.0", - "@sentry/react": "10.45.0", - "@streamdown/math": "1.0.2", - "@svgdotjs/svg.js": "3.2.5", - "@t3-oss/env-nextjs": "0.13.11", - "@tailwindcss/typography": "0.5.19", - "@tanstack/react-form": "1.28.5", - "@tanstack/react-query": "5.95.0", - "abcjs": "6.6.2", - "ahooks": "3.9.6", - "class-variance-authority": "0.7.1", - "clsx": "2.1.1", - "cmdk": "1.1.1", - "copy-to-clipboard": "3.3.3", - "cron-parser": "5.5.0", - "dayjs": "1.11.20", - "decimal.js": "10.6.0", - "dompurify": "3.3.3", - "echarts": "6.0.0", - "echarts-for-react": "3.0.6", - "elkjs": "0.11.1", - "embla-carousel-autoplay": "8.6.0", - "embla-carousel-react": "8.6.0", - "emoji-mart": "5.6.0", - "es-toolkit": "1.45.1", - "fast-deep-equal": "3.1.3", - "foxact": "0.3.0", - "html-entities": "2.6.0", - "html-to-image": "1.11.13", - "i18next": "25.10.4", - "i18next-resources-to-backend": "1.2.1", - "immer": "11.1.4", - "jotai": "2.18.1", - "js-audio-recorder": "1.0.7", - "js-cookie": "3.0.5", - "js-yaml": "4.1.1", - "jsonschema": "1.5.0", - "katex": "0.16.40", - "ky": "1.14.3", - "lamejs": "1.2.1", - "lexical": "0.42.0", - "mermaid": "11.13.0", - "mime": "4.1.0", - "mitt": "3.0.1", - "negotiator": "1.0.0", - "next": "16.2.1", - "next-themes": "0.4.6", - "nuqs": "2.8.9", - "pinyin-pro": "3.28.0", - "qrcode.react": "4.2.0", - "qs": "6.15.0", - "react": "19.2.4", - "react-18-input-autosize": "3.0.0", - "react-dom": "19.2.4", - "react-easy-crop": "5.5.6", - "react-hotkeys-hook": "5.2.4", - "react-i18next": "16.6.1", - "react-multi-email": "1.0.25", - "react-papaparse": "4.4.0", - "react-pdf-highlighter": "8.0.0-rc.0", - "react-sortablejs": "6.1.4", - "react-syntax-highlighter": "15.6.6", - "react-textarea-autosize": "8.5.9", - "react-window": "1.8.11", - "reactflow": "11.11.4", - "remark-breaks": "4.0.0", - "remark-directive": "4.0.0", - "scheduler": "0.27.0", - "sharp": "0.34.5", - "sortablejs": "1.15.7", - "std-semver": "1.0.8", - "streamdown": "2.5.0", - "string-ts": "2.3.1", - "tailwind-merge": "2.6.1", - "tldts": "7.0.27", - "unist-util-visit": "5.1.0", - "use-context-selector": "2.0.0", - "uuid": "13.0.0", - "zod": "4.3.6", - "zundo": "2.3.0", - "zustand": "5.0.12" + "@amplitude/analytics-browser": "catalog:", + "@amplitude/plugin-session-replay-browser": "catalog:", + "@base-ui/react": "catalog:", + "@emoji-mart/data": "catalog:", + "@floating-ui/react": "catalog:", + "@formatjs/intl-localematcher": "catalog:", + "@headlessui/react": "catalog:", + "@heroicons/react": "catalog:", + "@lexical/code": "catalog:", + "@lexical/link": "catalog:", + "@lexical/list": "catalog:", + "@lexical/react": "catalog:", + "@lexical/selection": "catalog:", + "@lexical/text": "catalog:", + "@lexical/utils": "catalog:", + "@monaco-editor/react": "catalog:", + "@orpc/client": "catalog:", + "@orpc/contract": "catalog:", + "@orpc/openapi-client": "catalog:", + "@orpc/tanstack-query": "catalog:", + "@remixicon/react": "catalog:", + "@sentry/react": "catalog:", + "@streamdown/math": "catalog:", + "@svgdotjs/svg.js": "catalog:", + "@t3-oss/env-nextjs": "catalog:", + "@tailwindcss/typography": "catalog:", + "@tanstack/react-form": "catalog:", + "@tanstack/react-query": "catalog:", + "abcjs": "catalog:", + "ahooks": "catalog:", + "class-variance-authority": "catalog:", + "clsx": "catalog:", + "cmdk": "catalog:", + "copy-to-clipboard": "catalog:", + "cron-parser": "catalog:", + "dayjs": "catalog:", + "decimal.js": "catalog:", + "dompurify": "catalog:", + "echarts": "catalog:", + "echarts-for-react": "catalog:", + "elkjs": "catalog:", + "embla-carousel-autoplay": "catalog:", + "embla-carousel-react": "catalog:", + "emoji-mart": "catalog:", + "es-toolkit": "catalog:", + "fast-deep-equal": "catalog:", + "foxact": "catalog:", + "html-entities": "catalog:", + "html-to-image": "catalog:", + "i18next": "catalog:", + "i18next-resources-to-backend": "catalog:", + "immer": "catalog:", + "jotai": "catalog:", + "js-audio-recorder": "catalog:", + "js-cookie": "catalog:", + "js-yaml": "catalog:", + "jsonschema": "catalog:", + "katex": "catalog:", + "ky": "catalog:", + "lamejs": "catalog:", + "lexical": "catalog:", + "mermaid": "catalog:", + "mime": "catalog:", + "mitt": "catalog:", + "negotiator": "catalog:", + "next": "catalog:", + "next-themes": "catalog:", + "nuqs": "catalog:", + "pinyin-pro": "catalog:", + "qrcode.react": "catalog:", + "qs": "catalog:", + "react": "catalog:", + "react-18-input-autosize": "catalog:", + "react-dom": "catalog:", + "react-easy-crop": "catalog:", + "react-hotkeys-hook": "catalog:", + "react-i18next": "catalog:", + "react-multi-email": "catalog:", + "react-papaparse": "catalog:", + "react-pdf-highlighter": "catalog:", + "react-sortablejs": "catalog:", + "react-syntax-highlighter": "catalog:", + "react-textarea-autosize": "catalog:", + "react-window": "catalog:", + "reactflow": "catalog:", + "remark-breaks": "catalog:", + "remark-directive": "catalog:", + "scheduler": "catalog:", + "sharp": "catalog:", + "sortablejs": "catalog:", + "std-semver": "catalog:", + "streamdown": "catalog:", + "string-ts": "catalog:", + "tailwind-merge": "catalog:", + "tldts": "catalog:", + "unist-util-visit": "catalog:", + "use-context-selector": "catalog:", + "uuid": "catalog:", + "zod": "catalog:", + "zundo": "catalog:", + "zustand": "catalog:" }, "devDependencies": { - "@antfu/eslint-config": "7.7.3", - "@chromatic-com/storybook": "5.0.2", - "@egoist/tailwindcss-icons": "1.9.2", - "@eslint-react/eslint-plugin": "3.0.0", - "@hono/node-server": "1.19.11", - "@iconify-json/heroicons": "1.2.3", - "@iconify-json/ri": "1.2.10", - "@mdx-js/loader": "3.1.1", - "@mdx-js/react": "3.1.1", - "@mdx-js/rollup": "3.1.1", - "@next/eslint-plugin-next": "16.2.1", - "@next/mdx": "16.2.1", - "@rgrove/parse-xml": "4.2.0", - "@storybook/addon-docs": "10.3.1", - "@storybook/addon-links": "10.3.1", - "@storybook/addon-onboarding": "10.3.1", - "@storybook/addon-themes": "10.3.1", - "@storybook/nextjs-vite": "10.3.1", - "@storybook/react": "10.3.1", - "@tanstack/eslint-plugin-query": "5.95.0", - "@tanstack/react-devtools": "0.10.0", - "@tanstack/react-form-devtools": "0.2.19", - "@tanstack/react-query-devtools": "5.95.0", - "@testing-library/dom": "10.4.1", - "@testing-library/jest-dom": "6.9.1", - "@testing-library/react": "16.3.2", - "@testing-library/user-event": "14.6.1", - "@tsslint/cli": "3.0.2", - "@tsslint/compat-eslint": "3.0.2", - "@tsslint/config": "3.0.2", - "@types/js-cookie": "3.0.6", - "@types/js-yaml": "4.0.9", - "@types/negotiator": "0.6.4", - "@types/node": "25.5.0", - "@types/postcss-js": "4.1.0", - "@types/qs": "6.15.0", - "@types/react": "19.2.14", - "@types/react-dom": "19.2.3", - "@types/react-syntax-highlighter": "15.5.13", - "@types/react-window": "1.8.8", - "@types/sortablejs": "1.15.9", - "@typescript-eslint/parser": "8.57.1", - "@typescript/native-preview": "7.0.0-dev.20260322.1", - "@vitejs/plugin-react": "6.0.1", - "@vitejs/plugin-rsc": "0.5.21", - "@vitest/coverage-v8": "4.1.0", - "agentation": "2.3.3", - "autoprefixer": "10.4.27", - "code-inspector-plugin": "1.4.5", - "eslint": "10.1.0", - "eslint-markdown": "0.6.0", - "eslint-plugin-better-tailwindcss": "4.3.2", - "eslint-plugin-hyoban": "0.14.1", - "eslint-plugin-markdown-preferences": "0.40.3", - "eslint-plugin-no-barrel-files": "1.2.2", - "eslint-plugin-react-hooks": "7.0.1", - "eslint-plugin-react-refresh": "0.5.2", - "eslint-plugin-sonarjs": "4.0.2", - "eslint-plugin-storybook": "10.3.1", - "happy-dom": "20.8.9", - "hono": "4.12.8", - "husky": "9.1.7", - "iconify-import-svg": "0.1.2", - "knip": "6.0.2", - "lint-staged": "16.4.0", - "postcss": "8.5.8", - "postcss-js": "5.1.0", - "react-server-dom-webpack": "19.2.4", - "sass": "1.98.0", - "storybook": "10.3.1", - "tailwindcss": "3.4.19", - "taze": "19.10.0", - "tsx": "4.21.0", - "typescript": "5.9.3", - "uglify-js": "3.19.3", - "vinext": "https://pkg.pr.new/vinext@b6a2cac", - "vite": "npm:@voidzero-dev/vite-plus-core@0.1.13", - "vite-plugin-inspect": "11.3.3", - "vite-plus": "0.1.13", - "vitest": "npm:@voidzero-dev/vite-plus-test@0.1.13", - "vitest-canvas-mock": "1.1.3" - }, - "pnpm": { - "overrides": { - "@lexical/code": "npm:lexical-code-no-prism@0.41.0", - "@monaco-editor/loader": "1.7.0", - "@nolyfill/safe-buffer": "npm:safe-buffer@^5.2.1", - "array-includes": "npm:@nolyfill/array-includes@^1.0.44", - "array.prototype.findlast": "npm:@nolyfill/array.prototype.findlast@^1.0.44", - "array.prototype.findlastindex": "npm:@nolyfill/array.prototype.findlastindex@^1.0.44", - "array.prototype.flat": "npm:@nolyfill/array.prototype.flat@^1.0.44", - "array.prototype.flatmap": "npm:@nolyfill/array.prototype.flatmap@^1.0.44", - "array.prototype.tosorted": "npm:@nolyfill/array.prototype.tosorted@^1.0.44", - "assert": "npm:@nolyfill/assert@^1.0.26", - "brace-expansion@<2.0.2": "2.0.2", - "canvas": "^3.2.2", - "devalue@<5.3.2": "5.3.2", - "dompurify@>=3.1.3 <=3.3.1": "3.3.2", - "es-iterator-helpers": "npm:@nolyfill/es-iterator-helpers@^1.0.21", - "esbuild@<0.27.2": "0.27.2", - "glob@>=10.2.0 <10.5.0": "11.1.0", - "hasown": "npm:@nolyfill/hasown@^1.0.44", - "is-arguments": "npm:@nolyfill/is-arguments@^1.0.44", - "is-core-module": "npm:@nolyfill/is-core-module@^1.0.39", - "is-generator-function": "npm:@nolyfill/is-generator-function@^1.0.44", - "is-typed-array": "npm:@nolyfill/is-typed-array@^1.0.44", - "isarray": "npm:@nolyfill/isarray@^1.0.44", - "object.assign": "npm:@nolyfill/object.assign@^1.0.44", - "object.entries": "npm:@nolyfill/object.entries@^1.0.44", - "object.fromentries": "npm:@nolyfill/object.fromentries@^1.0.44", - "object.groupby": "npm:@nolyfill/object.groupby@^1.0.44", - "object.values": "npm:@nolyfill/object.values@^1.0.44", - "pbkdf2": "~3.1.5", - "pbkdf2@<3.1.3": "3.1.3", - "picomatch@<2.3.2": "2.3.2", - "picomatch@>=4.0.0 <4.0.4": "4.0.4", - "prismjs": "~1.30", - "prismjs@<1.30.0": "1.30.0", - "rollup@>=4.0.0 <4.59.0": "4.59.0", - "safe-buffer": "^5.2.1", - "safe-regex-test": "npm:@nolyfill/safe-regex-test@^1.0.44", - "safer-buffer": "npm:@nolyfill/safer-buffer@^1.0.44", - "side-channel": "npm:@nolyfill/side-channel@^1.0.44", - "smol-toml@<1.6.1": "1.6.1", - "solid-js": "1.9.11", - "string-width": "~8.2.0", - "string.prototype.includes": "npm:@nolyfill/string.prototype.includes@^1.0.44", - "string.prototype.matchall": "npm:@nolyfill/string.prototype.matchall@^1.0.44", - "string.prototype.repeat": "npm:@nolyfill/string.prototype.repeat@^1.0.44", - "string.prototype.trimend": "npm:@nolyfill/string.prototype.trimend@^1.0.44", - "svgo@>=3.0.0 <3.3.3": "3.3.3", - "tar@<=7.5.10": "7.5.11", - "typed-array-buffer": "npm:@nolyfill/typed-array-buffer@^1.0.44", - "undici@>=7.0.0 <7.24.0": "7.24.0", - "vite": "npm:@voidzero-dev/vite-plus-core@0.1.13", - "vitest": "npm:@voidzero-dev/vite-plus-test@0.1.13", - "which-typed-array": "npm:@nolyfill/which-typed-array@^1.0.44", - "yaml@>=2.0.0 <2.8.3": "2.8.3", - "yauzl@<3.2.1": "3.2.1" - }, - "ignoredBuiltDependencies": [ - "canvas", - "core-js-pure" - ], - "onlyBuiltDependencies": [ - "@parcel/watcher", - "esbuild", - "sharp" - ] + "@antfu/eslint-config": "catalog:", + "@chromatic-com/storybook": "catalog:", + "@egoist/tailwindcss-icons": "catalog:", + "@eslint-react/eslint-plugin": "catalog:", + "@hono/node-server": "catalog:", + "@iconify-json/heroicons": "catalog:", + "@iconify-json/ri": "catalog:", + "@mdx-js/loader": "catalog:", + "@mdx-js/react": "catalog:", + "@mdx-js/rollup": "catalog:", + "@next/eslint-plugin-next": "catalog:", + "@next/mdx": "catalog:", + "@rgrove/parse-xml": "catalog:", + "@storybook/addon-docs": "catalog:", + "@storybook/addon-links": "catalog:", + "@storybook/addon-onboarding": "catalog:", + "@storybook/addon-themes": "catalog:", + "@storybook/nextjs-vite": "catalog:", + "@storybook/react": "catalog:", + "@tanstack/eslint-plugin-query": "catalog:", + "@tanstack/react-devtools": "catalog:", + "@tanstack/react-form-devtools": "catalog:", + "@tanstack/react-query-devtools": "catalog:", + "@testing-library/dom": "catalog:", + "@testing-library/jest-dom": "catalog:", + "@testing-library/react": "catalog:", + "@testing-library/user-event": "catalog:", + "@tsslint/cli": "catalog:", + "@tsslint/compat-eslint": "catalog:", + "@tsslint/config": "catalog:", + "@types/js-cookie": "catalog:", + "@types/js-yaml": "catalog:", + "@types/negotiator": "catalog:", + "@types/node": "catalog:", + "@types/postcss-js": "catalog:", + "@types/qs": "catalog:", + "@types/react": "catalog:", + "@types/react-dom": "catalog:", + "@types/react-syntax-highlighter": "catalog:", + "@types/react-window": "catalog:", + "@types/sortablejs": "catalog:", + "@typescript-eslint/parser": "catalog:", + "@typescript/native-preview": "catalog:", + "@vitejs/plugin-react": "catalog:", + "@vitejs/plugin-rsc": "catalog:", + "@vitest/coverage-v8": "catalog:", + "agentation": "catalog:", + "autoprefixer": "catalog:", + "code-inspector-plugin": "catalog:", + "eslint": "catalog:", + "eslint-markdown": "catalog:", + "eslint-plugin-better-tailwindcss": "catalog:", + "eslint-plugin-hyoban": "catalog:", + "eslint-plugin-markdown-preferences": "catalog:", + "eslint-plugin-no-barrel-files": "catalog:", + "eslint-plugin-react-hooks": "catalog:", + "eslint-plugin-react-refresh": "catalog:", + "eslint-plugin-sonarjs": "catalog:", + "eslint-plugin-storybook": "catalog:", + "happy-dom": "catalog:", + "hono": "catalog:", + "husky": "catalog:", + "iconify-import-svg": "catalog:", + "knip": "catalog:", + "lint-staged": "catalog:", + "postcss": "catalog:", + "postcss-js": "catalog:", + "react-server-dom-webpack": "catalog:", + "sass": "catalog:", + "storybook": "catalog:", + "tailwindcss": "catalog:", + "tsx": "catalog:", + "typescript": "catalog:", + "uglify-js": "catalog:", + "vinext": "catalog:", + "vite": "catalog:", + "vite-plugin-inspect": "catalog:", + "vite-plus": "catalog:", + "vitest": "catalog:", + "vitest-canvas-mock": "catalog:" }, "lint-staged": { "*": "eslint --fix --pass-on-unpruned-suppressions" diff --git a/web/scripts/copy-and-start.mjs b/web/scripts/copy-and-start.mjs index 9525c6b45f..932a88a32d 100644 --- a/web/scripts/copy-and-start.mjs +++ b/web/scripts/copy-and-start.mjs @@ -8,21 +8,6 @@ import { spawn } from 'node:child_process' import { cp, mkdir, stat } from 'node:fs/promises' import path from 'node:path' -// Configuration for directories to copy -const DIRS_TO_COPY = [ - { - src: path.join('.next', 'static'), - dest: path.join('.next', 'standalone', '.next', 'static'), - }, - { - src: 'public', - dest: path.join('.next', 'standalone', 'public'), - }, -] - -// Path to the server script -const SERVER_SCRIPT_PATH = path.join('.next', 'standalone', 'server.js') - // Function to check if a path exists const pathExists = async (path) => { try { @@ -40,6 +25,23 @@ const pathExists = async (path) => { } } +const STANDALONE_ROOT_CANDIDATES = [ + path.join('.next', 'standalone', 'web'), + path.join('.next', 'standalone'), +] + +const getStandaloneRoot = async () => { + for (const standaloneRoot of STANDALONE_ROOT_CANDIDATES) { + const serverScriptPath = path.join(standaloneRoot, 'server.js') + if (await pathExists(serverScriptPath)) + return standaloneRoot + } + + throw new Error( + `Unable to find Next standalone server entry. Checked: ${STANDALONE_ROOT_CANDIDATES.join(', ')}`, + ) +} + // Function to recursively copy directories const copyDir = async (src, dest) => { console.debug(`Copying directory from ${src} to ${dest}`) @@ -48,9 +50,20 @@ const copyDir = async (src, dest) => { } // Process each directory copy operation -const copyAllDirs = async () => { +const copyAllDirs = async (standaloneRoot) => { + const dirsToCopy = [ + { + src: path.join('.next', 'static'), + dest: path.join(standaloneRoot, '.next', 'static'), + }, + { + src: 'public', + dest: path.join(standaloneRoot, 'public'), + }, + ] + console.debug('Starting directory copy operations') - for (const { src, dest } of DIRS_TO_COPY) { + for (const { src, dest } of dirsToCopy) { try { // Instead of pre-creating destination directory, we ensure parent directory exists const destParent = path.dirname(dest) @@ -75,19 +88,22 @@ const copyAllDirs = async () => { // Run copy operations and start server const main = async () => { console.debug('Starting copy-and-start script') - await copyAllDirs() + const standaloneRoot = await getStandaloneRoot() + const serverScriptPath = path.join(standaloneRoot, 'server.js') + + await copyAllDirs(standaloneRoot) // Start server const port = process.env.npm_config_port || process.env.PORT || '3000' const host = process.env.npm_config_host || process.env.HOSTNAME || '0.0.0.0' console.info(`Starting server on ${host}:${port}`) - console.debug(`Server script path: ${SERVER_SCRIPT_PATH}`) + console.debug(`Server script path: ${serverScriptPath}`) console.debug(`Environment variables - PORT: ${port}, HOSTNAME: ${host}`) const server = spawn( process.execPath, - [SERVER_SCRIPT_PATH], + [serverScriptPath], { env: { ...process.env, diff --git a/web/vitest.setup.ts b/web/vitest.setup.ts index ac26ac5d25..b17a59bab6 100644 --- a/web/vitest.setup.ts +++ b/web/vitest.setup.ts @@ -1,8 +1,11 @@ +import * as jestDomMatchers from '@testing-library/jest-dom/matchers' import { act, cleanup } from '@testing-library/react' import * as React from 'react' import '@testing-library/jest-dom/vitest' import 'vitest-canvas-mock' +expect.extend(jestDomMatchers) + // Suppress act() warnings from @headlessui/react internal Transition component // These warnings are caused by Headless UI's internal async state updates, not our code const originalConsoleError = console.error From ae9a16a397f709568725ce220547fa79400ea6ee Mon Sep 17 00:00:00 2001 From: lif <1835304752@qq.com> Date: Mon, 30 Mar 2026 21:06:55 +0800 Subject: [PATCH 06/40] fix: upgrade langfuse SDK to v3+ for LLM-as-judge support (#34265) Signed-off-by: majiayu000 <1835304752@qq.com> --- api/core/app/workflow/layers/observability.py | 3 +- .../aliyun_trace/data_exporter/traceclient.py | 16 +- .../arize_phoenix_trace.py | 10 +- api/core/ops/langfuse_trace/langfuse_trace.py | 107 +++++++++-- api/core/ops/tencent_trace/client.py | 22 ++- api/enterprise/telemetry/exporter.py | 9 +- api/extensions/ext_sentry.py | 15 +- api/pyproject.toml | 34 ++-- .../ops/langfuse_trace/test_langfuse_trace.py | 16 +- api/uv.lock | 168 +++++++++--------- 10 files changed, 257 insertions(+), 143 deletions(-) diff --git a/api/core/app/workflow/layers/observability.py b/api/core/app/workflow/layers/observability.py index 8565c3076c..c4ed54a140 100644 --- a/api/core/app/workflow/layers/observability.py +++ b/api/core/app/workflow/layers/observability.py @@ -8,6 +8,7 @@ associates with the node span. """ import logging +from contextvars import Token from dataclasses import dataclass from typing import cast, final @@ -35,7 +36,7 @@ logger = logging.getLogger(__name__) @dataclass(slots=True) class _NodeSpanContext: span: "Span" - token: object + token: Token[context_api.Context] @final diff --git a/api/core/ops/aliyun_trace/data_exporter/traceclient.py b/api/core/ops/aliyun_trace/data_exporter/traceclient.py index 0e00e90520..67d5163b0f 100644 --- a/api/core/ops/aliyun_trace/data_exporter/traceclient.py +++ b/api/core/ops/aliyun_trace/data_exporter/traceclient.py @@ -16,7 +16,13 @@ from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExport from opentelemetry.sdk.resources import Resource from opentelemetry.sdk.trace import ReadableSpan from opentelemetry.sdk.util.instrumentation import InstrumentationScope -from opentelemetry.semconv.resource import ResourceAttributes +from opentelemetry.semconv._incubating.attributes.deployment_attributes import ( # type: ignore[import-untyped] + DEPLOYMENT_ENVIRONMENT, +) +from opentelemetry.semconv._incubating.attributes.host_attributes import ( # type: ignore[import-untyped] + HOST_NAME, +) +from opentelemetry.semconv.attributes import service_attributes from opentelemetry.trace import Link, SpanContext, TraceFlags from configs import dify_config @@ -45,10 +51,10 @@ class TraceClient: self.endpoint = endpoint self.resource = Resource( attributes={ - ResourceAttributes.SERVICE_NAME: service_name, - ResourceAttributes.SERVICE_VERSION: f"dify-{dify_config.project.version}-{dify_config.COMMIT_SHA}", - ResourceAttributes.DEPLOYMENT_ENVIRONMENT: f"{dify_config.DEPLOY_ENV}-{dify_config.EDITION}", - ResourceAttributes.HOST_NAME: socket.gethostname(), + service_attributes.SERVICE_NAME: service_name, + service_attributes.SERVICE_VERSION: f"dify-{dify_config.project.version}-{dify_config.COMMIT_SHA}", + DEPLOYMENT_ENVIRONMENT: f"{dify_config.DEPLOY_ENV}-{dify_config.EDITION}", + HOST_NAME: socket.gethostname(), ACS_ARMS_SERVICE_FEATURE: "genai_app", } ) diff --git a/api/core/ops/arize_phoenix_trace/arize_phoenix_trace.py b/api/core/ops/arize_phoenix_trace/arize_phoenix_trace.py index 39d97e2882..902f58e6b7 100644 --- a/api/core/ops/arize_phoenix_trace/arize_phoenix_trace.py +++ b/api/core/ops/arize_phoenix_trace/arize_phoenix_trace.py @@ -19,7 +19,7 @@ from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExport from opentelemetry.sdk import trace as trace_sdk from opentelemetry.sdk.resources import Resource from opentelemetry.sdk.trace.export import SimpleSpanProcessor -from opentelemetry.semconv.trace import SpanAttributes as OTELSpanAttributes +from opentelemetry.semconv.attributes import exception_attributes from opentelemetry.trace import Span, Status, StatusCode, set_span_in_context, use_span from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator from opentelemetry.util.types import AttributeValue @@ -134,10 +134,10 @@ def set_span_status(current_span: Span, error: Exception | str | None = None): if not exception_message: exception_message = repr(error) attributes: dict[str, AttributeValue] = { - OTELSpanAttributes.EXCEPTION_TYPE: exception_type, - OTELSpanAttributes.EXCEPTION_MESSAGE: exception_message, - OTELSpanAttributes.EXCEPTION_ESCAPED: False, - OTELSpanAttributes.EXCEPTION_STACKTRACE: error_string, + exception_attributes.EXCEPTION_TYPE: exception_type, + exception_attributes.EXCEPTION_MESSAGE: exception_message, + exception_attributes.EXCEPTION_ESCAPED: False, + exception_attributes.EXCEPTION_STACKTRACE: error_string, } current_span.add_event(name="exception", attributes=attributes) else: diff --git a/api/core/ops/langfuse_trace/langfuse_trace.py b/api/core/ops/langfuse_trace/langfuse_trace.py index 3644b6b4c2..9be2ce1bdf 100644 --- a/api/core/ops/langfuse_trace/langfuse_trace.py +++ b/api/core/ops/langfuse_trace/langfuse_trace.py @@ -1,9 +1,19 @@ import logging import os -from datetime import datetime, timedelta +import uuid +from datetime import UTC, datetime, timedelta from graphon.enums import BuiltinNodeTypes from langfuse import Langfuse +from langfuse.api import ( + CreateGenerationBody, + CreateSpanBody, + IngestionEvent_GenerationCreate, + IngestionEvent_SpanCreate, + IngestionEvent_TraceCreate, + TraceBody, +) +from langfuse.api.commons.types.usage import Usage from sqlalchemy.orm import sessionmaker from core.ops.base_trace_instance import BaseTraceInstance @@ -396,18 +406,61 @@ class LangFuseDataTrace(BaseTraceInstance): ) self.add_span(langfuse_span_data=name_generation_span_data) + def _make_event_id(self) -> str: + return str(uuid.uuid4()) + + def _now_iso(self) -> str: + return datetime.now(UTC).isoformat() + def add_trace(self, langfuse_trace_data: LangfuseTrace | None = None): - format_trace_data = filter_none_values(langfuse_trace_data.model_dump()) if langfuse_trace_data else {} + data = filter_none_values(langfuse_trace_data.model_dump()) if langfuse_trace_data else {} try: - self.langfuse_client.trace(**format_trace_data) + body = TraceBody( + id=data.get("id"), + name=data.get("name"), + user_id=data.get("user_id"), + input=data.get("input"), + output=data.get("output"), + metadata=data.get("metadata"), + session_id=data.get("session_id"), + version=data.get("version"), + release=data.get("release"), + tags=data.get("tags"), + public=data.get("public"), + ) + event = IngestionEvent_TraceCreate( + body=body, + id=self._make_event_id(), + timestamp=self._now_iso(), + ) + self.langfuse_client.api.ingestion.batch(batch=[event]) logger.debug("LangFuse Trace created successfully") except Exception as e: raise ValueError(f"LangFuse Failed to create trace: {str(e)}") def add_span(self, langfuse_span_data: LangfuseSpan | None = None): - format_span_data = filter_none_values(langfuse_span_data.model_dump()) if langfuse_span_data else {} + data = filter_none_values(langfuse_span_data.model_dump()) if langfuse_span_data else {} try: - self.langfuse_client.span(**format_span_data) + body = CreateSpanBody( + id=data.get("id"), + trace_id=data.get("trace_id"), + name=data.get("name"), + start_time=data.get("start_time"), + end_time=data.get("end_time"), + input=data.get("input"), + output=data.get("output"), + metadata=data.get("metadata"), + level=data.get("level"), + status_message=data.get("status_message"), + parent_observation_id=data.get("parent_observation_id"), + version=data.get("version"), + ) + event = IngestionEvent_SpanCreate( + body=body, + id=self._make_event_id(), + timestamp=self._now_iso(), + ) + self.langfuse_client.api.ingestion.batch(batch=[event]) logger.debug("LangFuse Span created successfully") except Exception as e: raise ValueError(f"LangFuse Failed to create span: {str(e)}") @@ -418,11 +471,45 @@ class LangFuseDataTrace(BaseTraceInstance): span.end(**format_span_data) def add_generation(self, langfuse_generation_data: LangfuseGeneration | None = None): - format_generation_data = ( - filter_none_values(langfuse_generation_data.model_dump()) if langfuse_generation_data else {} - ) + data = filter_none_values(langfuse_generation_data.model_dump()) if langfuse_generation_data else {} try: - self.langfuse_client.generation(**format_generation_data) + usage_data = data.pop("usage", None) + usage = None + if usage_data: + usage = Usage( + input=usage_data.get("input", 0) or 0, + output=usage_data.get("output", 0) or 0, + total=usage_data.get("total", 0) or 0, + unit=usage_data.get("unit"), + input_cost=usage_data.get("inputCost"), + output_cost=usage_data.get("outputCost"), + total_cost=usage_data.get("totalCost"), + ) + + body = CreateGenerationBody( + id=data.get("id"), + trace_id=data.get("trace_id"), + name=data.get("name"), + start_time=data.get("start_time"), + end_time=data.get("end_time"), + model=data.get("model"), + model_parameters=data.get("model_parameters"), + input=data.get("input"), + output=data.get("output"), + usage=usage, + metadata=data.get("metadata"), + level=data.get("level"), + status_message=data.get("status_message"), + parent_observation_id=data.get("parent_observation_id"), + version=data.get("version"), + completion_start_time=data.get("completion_start_time"), + ) + event = IngestionEvent_GenerationCreate( + body=body, + id=self._make_event_id(), + timestamp=self._now_iso(), + ) + self.langfuse_client.api.ingestion.batch(batch=[event]) logger.debug("LangFuse Generation created successfully") except Exception as e: raise ValueError(f"LangFuse Failed to create generation: {str(e)}") @@ -443,7 +530,7 @@ class LangFuseDataTrace(BaseTraceInstance): def get_project_key(self): try: - projects = self.langfuse_client.client.projects.get() + projects = self.langfuse_client.api.projects.get() return projects.data[0].id except Exception as e: logger.debug("LangFuse get project key failed: %s", str(e)) diff --git a/api/core/ops/tencent_trace/client.py b/api/core/ops/tencent_trace/client.py index c39093bf4c..be06ab4a36 100644 --- a/api/core/ops/tencent_trace/client.py +++ b/api/core/ops/tencent_trace/client.py @@ -26,7 +26,13 @@ from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExport from opentelemetry.sdk.resources import Resource from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor -from opentelemetry.semconv.resource import ResourceAttributes +from opentelemetry.semconv._incubating.attributes.deployment_attributes import ( # type: ignore[import-untyped] + DEPLOYMENT_ENVIRONMENT, +) +from opentelemetry.semconv._incubating.attributes.host_attributes import ( # type: ignore[import-untyped] + HOST_NAME, +) +from opentelemetry.semconv.attributes import service_attributes from opentelemetry.trace import SpanKind from opentelemetry.util.types import AttributeValue @@ -73,13 +79,13 @@ class TencentTraceClient: self.resource = Resource( attributes={ - ResourceAttributes.SERVICE_NAME: service_name, - ResourceAttributes.SERVICE_VERSION: f"dify-{dify_config.project.version}-{dify_config.COMMIT_SHA}", - ResourceAttributes.DEPLOYMENT_ENVIRONMENT: f"{dify_config.DEPLOY_ENV}-{dify_config.EDITION}", - ResourceAttributes.HOST_NAME: socket.gethostname(), - ResourceAttributes.TELEMETRY_SDK_LANGUAGE: "python", - ResourceAttributes.TELEMETRY_SDK_NAME: "opentelemetry", - ResourceAttributes.TELEMETRY_SDK_VERSION: _get_opentelemetry_sdk_version(), + service_attributes.SERVICE_NAME: service_name, + service_attributes.SERVICE_VERSION: f"dify-{dify_config.project.version}-{dify_config.COMMIT_SHA}", + DEPLOYMENT_ENVIRONMENT: f"{dify_config.DEPLOY_ENV}-{dify_config.EDITION}", + HOST_NAME: socket.gethostname(), + "telemetry.sdk.language": "python", + "telemetry.sdk.name": "opentelemetry", + "telemetry.sdk.version": _get_opentelemetry_sdk_version(), } ) # Prepare gRPC endpoint/metadata diff --git a/api/enterprise/telemetry/exporter.py b/api/enterprise/telemetry/exporter.py index b2f860764f..80959514f2 100644 --- a/api/enterprise/telemetry/exporter.py +++ b/api/enterprise/telemetry/exporter.py @@ -27,7 +27,10 @@ from opentelemetry.sdk.resources import Resource from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.sdk.trace.sampling import ParentBasedTraceIdRatio -from opentelemetry.semconv.resource import ResourceAttributes +from opentelemetry.semconv._incubating.attributes.host_attributes import ( # type: ignore[import-untyped] + HOST_NAME, +) +from opentelemetry.semconv.attributes import service_attributes from opentelemetry.trace import SpanContext, TraceFlags from opentelemetry.util.types import Attributes, AttributeValue @@ -114,8 +117,8 @@ class EnterpriseExporter: resource = Resource( attributes={ - ResourceAttributes.SERVICE_NAME: service_name, - ResourceAttributes.HOST_NAME: socket.gethostname(), + service_attributes.SERVICE_NAME: service_name, + HOST_NAME: socket.gethostname(), } ) sampler = ParentBasedTraceIdRatio(sampling_rate) diff --git a/api/extensions/ext_sentry.py b/api/extensions/ext_sentry.py index 651f8ed898..5cc58f27c4 100644 --- a/api/extensions/ext_sentry.py +++ b/api/extensions/ext_sentry.py @@ -6,15 +6,24 @@ def init_app(app: DifyApp): if dify_config.SENTRY_DSN: import sentry_sdk from graphon.model_runtime.errors.invoke import InvokeRateLimitError - from langfuse import parse_error from sentry_sdk.integrations.celery import CeleryIntegration from sentry_sdk.integrations.flask import FlaskIntegration from werkzeug.exceptions import HTTPException + try: + from langfuse._utils import parse_error + + _langfuse_error_response = parse_error.defaultErrorResponse + except (ImportError, AttributeError): + _langfuse_error_response = ( + "Unexpected error occurred. Please check your request" + " and contact support: https://langfuse.com/support." + ) + def before_send(event, hint): if "exc_info" in hint: _, exc_value, _ = hint["exc_info"] - if parse_error.defaultErrorResponse in str(exc_value): + if _langfuse_error_response in str(exc_value): return None return event @@ -27,7 +36,7 @@ def init_app(app: DifyApp): ValueError, FileNotFoundError, InvokeRateLimitError, - parse_error.defaultErrorResponse, + _langfuse_error_response, ], traces_sample_rate=dify_config.SENTRY_TRACES_SAMPLE_RATE, profiles_sample_rate=dify_config.SENTRY_PROFILES_SAMPLE_RATE, diff --git a/api/pyproject.toml b/api/pyproject.toml index f737d0699f..a09b474bf5 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -33,7 +33,7 @@ dependencies = [ "httpx[socks]~=0.28.0", "jieba==0.42.1", "json-repair>=0.55.1", - "langfuse~=2.51.3", + "langfuse>=3.0.0,<5.0.0", "langsmith~=0.7.16", "markdown~=3.10.2", "mlflow-skinny>=3.0.0", @@ -41,23 +41,23 @@ dependencies = [ "openpyxl~=3.1.5", "opik~=1.10.37", "litellm==1.82.6", # Pinned to avoid madoka dependency issue - "opentelemetry-api==1.28.0", - "opentelemetry-distro==0.49b0", - "opentelemetry-exporter-otlp==1.28.0", - "opentelemetry-exporter-otlp-proto-common==1.28.0", - "opentelemetry-exporter-otlp-proto-grpc==1.28.0", - "opentelemetry-exporter-otlp-proto-http==1.28.0", - "opentelemetry-instrumentation==0.49b0", - "opentelemetry-instrumentation-celery==0.49b0", - "opentelemetry-instrumentation-flask==0.49b0", - "opentelemetry-instrumentation-httpx==0.49b0", - "opentelemetry-instrumentation-redis==0.49b0", - "opentelemetry-instrumentation-sqlalchemy==0.49b0", + "opentelemetry-api==1.40.0", + "opentelemetry-distro==0.61b0", + "opentelemetry-exporter-otlp==1.40.0", + "opentelemetry-exporter-otlp-proto-common==1.40.0", + "opentelemetry-exporter-otlp-proto-grpc==1.40.0", + "opentelemetry-exporter-otlp-proto-http==1.40.0", + "opentelemetry-instrumentation==0.61b0", + "opentelemetry-instrumentation-celery==0.61b0", + "opentelemetry-instrumentation-flask==0.61b0", + "opentelemetry-instrumentation-httpx==0.61b0", + "opentelemetry-instrumentation-redis==0.61b0", + "opentelemetry-instrumentation-sqlalchemy==0.61b0", "opentelemetry-propagator-b3==1.40.0", - "opentelemetry-proto==1.28.0", - "opentelemetry-sdk==1.28.0", - "opentelemetry-semantic-conventions==0.49b0", - "opentelemetry-util-http==0.49b0", + "opentelemetry-proto==1.40.0", + "opentelemetry-sdk==1.40.0", + "opentelemetry-semantic-conventions==0.61b0", + "opentelemetry-util-http==0.61b0", "pandas[excel,output-formatting,performance]~=3.0.1", "psycogreen~=1.0.2", "psycopg2-binary~=2.9.6", diff --git a/api/tests/unit_tests/core/ops/langfuse_trace/test_langfuse_trace.py b/api/tests/unit_tests/core/ops/langfuse_trace/test_langfuse_trace.py index 97f7a16327..374371fb42 100644 --- a/api/tests/unit_tests/core/ops/langfuse_trace/test_langfuse_trace.py +++ b/api/tests/unit_tests/core/ops/langfuse_trace/test_langfuse_trace.py @@ -521,11 +521,11 @@ def test_generate_name_trace(trace_instance): def test_add_trace_success(trace_instance): data = LangfuseTrace(id="t1", name="trace") trace_instance.add_trace(data) - trace_instance.langfuse_client.trace.assert_called_once() + trace_instance.langfuse_client.api.ingestion.batch.assert_called_once() def test_add_trace_error(trace_instance): - trace_instance.langfuse_client.trace.side_effect = Exception("error") + trace_instance.langfuse_client.api.ingestion.batch.side_effect = Exception("error") data = LangfuseTrace(id="t1", name="trace") with pytest.raises(ValueError, match="LangFuse Failed to create trace: error"): trace_instance.add_trace(data) @@ -534,11 +534,11 @@ def test_add_trace_error(trace_instance): def test_add_span_success(trace_instance): data = LangfuseSpan(id="s1", name="span", trace_id="t1") trace_instance.add_span(data) - trace_instance.langfuse_client.span.assert_called_once() + trace_instance.langfuse_client.api.ingestion.batch.assert_called_once() def test_add_span_error(trace_instance): - trace_instance.langfuse_client.span.side_effect = Exception("error") + trace_instance.langfuse_client.api.ingestion.batch.side_effect = Exception("error") data = LangfuseSpan(id="s1", name="span", trace_id="t1") with pytest.raises(ValueError, match="LangFuse Failed to create span: error"): trace_instance.add_span(data) @@ -554,11 +554,11 @@ def test_update_span(trace_instance): def test_add_generation_success(trace_instance): data = LangfuseGeneration(id="g1", name="gen", trace_id="t1") trace_instance.add_generation(data) - trace_instance.langfuse_client.generation.assert_called_once() + trace_instance.langfuse_client.api.ingestion.batch.assert_called_once() def test_add_generation_error(trace_instance): - trace_instance.langfuse_client.generation.side_effect = Exception("error") + trace_instance.langfuse_client.api.ingestion.batch.side_effect = Exception("error") data = LangfuseGeneration(id="g1", name="gen", trace_id="t1") with pytest.raises(ValueError, match="LangFuse Failed to create generation: error"): trace_instance.add_generation(data) @@ -585,12 +585,12 @@ def test_api_check_error(trace_instance): def test_get_project_key_success(trace_instance): mock_data = MagicMock() mock_data.id = "proj-1" - trace_instance.langfuse_client.client.projects.get.return_value = MagicMock(data=[mock_data]) + trace_instance.langfuse_client.api.projects.get.return_value = MagicMock(data=[mock_data]) assert trace_instance.get_project_key() == "proj-1" def test_get_project_key_error(trace_instance): - trace_instance.langfuse_client.client.projects.get.side_effect = Exception("fail") + trace_instance.langfuse_client.api.projects.get.side_effect = Exception("fail") with pytest.raises(ValueError, match="LangFuse get project key failed: fail"): trace_instance.get_project_key() diff --git a/api/uv.lock b/api/uv.lock index c4cf31e3f5..3e8d794866 100644 --- a/api/uv.lock +++ b/api/uv.lock @@ -1700,30 +1700,30 @@ requires-dist = [ { name = "httpx-sse", specifier = "~=0.4.0" }, { name = "jieba", specifier = "==0.42.1" }, { name = "json-repair", specifier = ">=0.55.1" }, - { name = "langfuse", specifier = "~=2.51.3" }, + { name = "langfuse", specifier = ">=3.0.0,<5.0.0" }, { name = "langsmith", specifier = "~=0.7.16" }, { name = "litellm", specifier = "==1.82.6" }, { name = "markdown", specifier = "~=3.10.2" }, { name = "mlflow-skinny", specifier = ">=3.0.0" }, { name = "numpy", specifier = "~=1.26.4" }, { name = "openpyxl", specifier = "~=3.1.5" }, - { name = "opentelemetry-api", specifier = "==1.28.0" }, - { name = "opentelemetry-distro", specifier = "==0.49b0" }, - { name = "opentelemetry-exporter-otlp", specifier = "==1.28.0" }, - { name = "opentelemetry-exporter-otlp-proto-common", specifier = "==1.28.0" }, - { name = "opentelemetry-exporter-otlp-proto-grpc", specifier = "==1.28.0" }, - { name = "opentelemetry-exporter-otlp-proto-http", specifier = "==1.28.0" }, - { name = "opentelemetry-instrumentation", specifier = "==0.49b0" }, - { name = "opentelemetry-instrumentation-celery", specifier = "==0.49b0" }, - { name = "opentelemetry-instrumentation-flask", specifier = "==0.49b0" }, - { name = "opentelemetry-instrumentation-httpx", specifier = "==0.49b0" }, - { name = "opentelemetry-instrumentation-redis", specifier = "==0.49b0" }, - { name = "opentelemetry-instrumentation-sqlalchemy", specifier = "==0.49b0" }, + { name = "opentelemetry-api", specifier = "==1.40.0" }, + { name = "opentelemetry-distro", specifier = "==0.61b0" }, + { name = "opentelemetry-exporter-otlp", specifier = "==1.40.0" }, + { name = "opentelemetry-exporter-otlp-proto-common", specifier = "==1.40.0" }, + { name = "opentelemetry-exporter-otlp-proto-grpc", specifier = "==1.40.0" }, + { name = "opentelemetry-exporter-otlp-proto-http", specifier = "==1.40.0" }, + { name = "opentelemetry-instrumentation", specifier = "==0.61b0" }, + { name = "opentelemetry-instrumentation-celery", specifier = "==0.61b0" }, + { name = "opentelemetry-instrumentation-flask", specifier = "==0.61b0" }, + { name = "opentelemetry-instrumentation-httpx", specifier = "==0.61b0" }, + { name = "opentelemetry-instrumentation-redis", specifier = "==0.61b0" }, + { name = "opentelemetry-instrumentation-sqlalchemy", specifier = "==0.61b0" }, { name = "opentelemetry-propagator-b3", specifier = "==1.40.0" }, - { name = "opentelemetry-proto", specifier = "==1.28.0" }, - { name = "opentelemetry-sdk", specifier = "==1.28.0" }, - { name = "opentelemetry-semantic-conventions", specifier = "==0.49b0" }, - { name = "opentelemetry-util-http", specifier = "==0.49b0" }, + { name = "opentelemetry-proto", specifier = "==1.40.0" }, + { name = "opentelemetry-sdk", specifier = "==1.40.0" }, + { name = "opentelemetry-semantic-conventions", specifier = "==0.61b0" }, + { name = "opentelemetry-util-http", specifier = "==0.61b0" }, { name = "opik", specifier = "~=1.10.37" }, { name = "packaging", specifier = "~=23.2" }, { name = "pandas", extras = ["excel", "output-formatting", "performance"], specifier = "~=3.0.1" }, @@ -3393,20 +3393,22 @@ sdist = { url = "https://files.pythonhosted.org/packages/0e/72/a3add0e4eec4eb9e2 [[package]] name = "langfuse" -version = "2.51.5" +version = "4.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "anyio" }, { name = "backoff" }, { name = "httpx" }, - { name = "idna" }, + { name = "openai" }, + { name = "opentelemetry-api" }, + { name = "opentelemetry-exporter-otlp-proto-http" }, + { name = "opentelemetry-sdk" }, { name = "packaging" }, { name = "pydantic" }, { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3c/e9/22c9c05d877ab85da6d9008aaa7360f2a9ad58787a8e36e00b1b5be9a990/langfuse-2.51.5.tar.gz", hash = "sha256:55bc37b5c5d3ae133c1a95db09117cfb3117add110ba02ebbf2ce45ac4395c5b", size = 117574, upload-time = "2024-10-09T00:59:15.016Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/94/ab00e21fa5977d6b9c68fb3a95de2aa1a1e586964ff2af3e37405bf65d9f/langfuse-4.0.1.tar.gz", hash = "sha256:40a6daf3ab505945c314246d5b577d48fcfde0a47e8c05267ea6bd494ae9608e", size = 272749, upload-time = "2026-03-19T14:03:34.508Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/03/f7/242a13ca094c78464b7d4df77dfe7d4c44ed77b15fed3d2e3486afa5d2e1/langfuse-2.51.5-py3-none-any.whl", hash = "sha256:b95401ca710ef94b521afa6541933b6f93d7cfd4a97523c8fc75bca4d6d219fb", size = 214281, upload-time = "2024-10-09T00:59:12.596Z" }, + { url = "https://files.pythonhosted.org/packages/27/8f/3145ef00940f9c29d7e0200fd040f35616eac21c6ab4610a1ba14f3a04c1/langfuse-4.0.1-py3-none-any.whl", hash = "sha256:e22f49ea31304f97fc31a97c014ba63baa8802d9568295d54f06b00b43c30524", size = 465049, upload-time = "2026-03-19T14:03:32.527Z" }, ] [[package]] @@ -4200,95 +4202,95 @@ wheels = [ [[package]] name = "opentelemetry-api" -version = "1.28.0" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "deprecated" }, { name = "importlib-metadata" }, + { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/79/36/260eaea0f74fdd0c0d8f22ed3a3031109ea1c85531f94f4fde266c29e29a/opentelemetry_api-1.28.0.tar.gz", hash = "sha256:578610bcb8aa5cdcb11169d136cc752958548fb6ccffb0969c1036b0ee9e5353", size = 62803, upload-time = "2024-11-05T19:14:45.497Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/1d/4049a9e8698361cc1a1aa03a6c59e4fa4c71e0c0f94a30f988a6876a2ae6/opentelemetry_api-1.40.0.tar.gz", hash = "sha256:159be641c0b04d11e9ecd576906462773eb97ae1b657730f0ecf64d32071569f", size = 70851, upload-time = "2026-03-04T14:17:21.555Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/22/e4/3b25d8b856791c04d8a62b1257b5fc09dc41a057800db06885af8ddcdce1/opentelemetry_api-1.28.0-py3-none-any.whl", hash = "sha256:8457cd2c59ea1bd0988560f021656cecd254ad7ef6be4ba09dbefeca2409ce52", size = 64314, upload-time = "2024-11-05T19:14:21.659Z" }, + { url = "https://files.pythonhosted.org/packages/5f/bf/93795954016c522008da367da292adceed71cca6ee1717e1d64c83089099/opentelemetry_api-1.40.0-py3-none-any.whl", hash = "sha256:82dd69331ae74b06f6a874704be0cfaa49a1650e1537d4a813b86ecef7d0ecf9", size = 68676, upload-time = "2026-03-04T14:17:01.24Z" }, ] [[package]] name = "opentelemetry-distro" -version = "0.49b0" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "opentelemetry-instrumentation" }, { name = "opentelemetry-sdk" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4d/75/7cb7c33899e66bb366d40a889111a78c22df0951038b6699f1663e715a9f/opentelemetry_distro-0.49b0.tar.gz", hash = "sha256:1bafa274f9e83baa0d2a5d47ed02caffcf9bcca60107b389b145400d82b07513", size = 2560, upload-time = "2024-11-05T19:21:39.379Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f5/00/1f8acc51326956a596fefaf67751380001af36029132a7a07d4debce3c06/opentelemetry_distro-0.61b0.tar.gz", hash = "sha256:975b845f50181ad53753becf4fd4b123b54fa04df5a9d78812264436d6518981", size = 2590, upload-time = "2026-03-04T14:20:12.453Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4c/db/806172b6a4933966eee518db814b375e620602f7fe776b74ef795690f135/opentelemetry_distro-0.49b0-py3-none-any.whl", hash = "sha256:1af4074702f605ea210753dd41947dc2fd61b39724f23cdcf15d5654867cd3c2", size = 3318, upload-time = "2024-11-05T19:20:34.065Z" }, + { url = "https://files.pythonhosted.org/packages/56/2c/efcc995cd7484e6e55b1d26bd7fa6c55ca96bd415ff94310b52c19f330b0/opentelemetry_distro-0.61b0-py3-none-any.whl", hash = "sha256:f21d1ac0627549795d75e332006dd068877f00e461b1b2e8fe4568d6eb7b9590", size = 3349, upload-time = "2026-03-04T14:18:57.788Z" }, ] [[package]] name = "opentelemetry-exporter-otlp" -version = "1.28.0" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-exporter-otlp-proto-grpc" }, { name = "opentelemetry-exporter-otlp-proto-http" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/eb/16/14e3fc163930ea68f0980a4cdd4ae5796e60aeb898965990e13263d64baf/opentelemetry_exporter_otlp-1.28.0.tar.gz", hash = "sha256:31ae7495831681dd3da34ac457f6970f147465ae4b9aae3a888d7a581c7cd868", size = 6170, upload-time = "2024-11-05T19:14:47.349Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/37/b6708e0eff5c5fb9aba2e0ea09f7f3bcbfd12a592d2a780241b5f6014df7/opentelemetry_exporter_otlp-1.40.0.tar.gz", hash = "sha256:7caa0870b95e2fcb59d64e16e2b639ecffb07771b6cd0000b5d12e5e4fef765a", size = 6152, upload-time = "2026-03-04T14:17:23.235Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/82/3f521b3c1f2a411ed60a24a8c9f486c1beeaf8c6c55337c87d3ae1642151/opentelemetry_exporter_otlp-1.28.0-py3-none-any.whl", hash = "sha256:1fd02d70f2c1b7ac5579c81e78de4594b188d3317c8ceb69e8b53900fb7b40fd", size = 7024, upload-time = "2024-11-05T19:14:24.534Z" }, + { url = "https://files.pythonhosted.org/packages/2d/fc/aea77c28d9f3ffef2fdafdc3f4a235aee4091d262ddabd25882f47ce5c5f/opentelemetry_exporter_otlp-1.40.0-py3-none-any.whl", hash = "sha256:48c87e539ec9afb30dc443775a1334cc5487de2f72a770a4c00b1610bf6c697d", size = 7023, upload-time = "2026-03-04T14:17:03.612Z" }, ] [[package]] name = "opentelemetry-exporter-otlp-proto-common" -version = "1.28.0" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-proto" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c2/8d/5d411084ac441052f4c9bae03a1aec65ae5d16b439fea7b9c5ac3842c013/opentelemetry_exporter_otlp_proto_common-1.28.0.tar.gz", hash = "sha256:5fa0419b0c8e291180b0fc8430a20dd44a3f3236f8e0827992145914f273ec4f", size = 18505, upload-time = "2024-11-05T19:14:48.204Z" } +sdist = { url = "https://files.pythonhosted.org/packages/51/bc/1559d46557fe6eca0b46c88d4c2676285f1f3be2e8d06bb5d15fbffc814a/opentelemetry_exporter_otlp_proto_common-1.40.0.tar.gz", hash = "sha256:1cbee86a4064790b362a86601ee7934f368b81cd4cc2f2e163902a6e7818a0fa", size = 20416, upload-time = "2026-03-04T14:17:23.801Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e1/72/3c44aabc74db325aaba09361b6a0d80f6d601f0ff86ecea8ee655c9538fc/opentelemetry_exporter_otlp_proto_common-1.28.0-py3-none-any.whl", hash = "sha256:467e6437d24e020156dffecece8c0a4471a8a60f6a34afeda7386df31a092410", size = 18403, upload-time = "2024-11-05T19:14:25.798Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ca/8f122055c97a932311a3f640273f084e738008933503d0c2563cd5d591fc/opentelemetry_exporter_otlp_proto_common-1.40.0-py3-none-any.whl", hash = "sha256:7081ff453835a82417bf38dccf122c827c3cbc94f2079b03bba02a3165f25149", size = 18369, upload-time = "2026-03-04T14:17:04.796Z" }, ] [[package]] name = "opentelemetry-exporter-otlp-proto-grpc" -version = "1.28.0" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "deprecated" }, { name = "googleapis-common-protos" }, { name = "grpcio" }, { name = "opentelemetry-api" }, { name = "opentelemetry-exporter-otlp-proto-common" }, { name = "opentelemetry-proto" }, { name = "opentelemetry-sdk" }, + { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/43/4d/f215162e58041afb4bdf5dbd0d8faf0b7fc9bf7b3d3fc0e44e06f9e7e869/opentelemetry_exporter_otlp_proto_grpc-1.28.0.tar.gz", hash = "sha256:47a11c19dc7f4289e220108e113b7de90d59791cb4c37fc29f69a6a56f2c3735", size = 26237, upload-time = "2024-11-05T19:14:49.026Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8f/7f/b9e60435cfcc7590fa87436edad6822240dddbc184643a2a005301cc31f4/opentelemetry_exporter_otlp_proto_grpc-1.40.0.tar.gz", hash = "sha256:bd4015183e40b635b3dab8da528b27161ba83bf4ef545776b196f0fb4ec47740", size = 25759, upload-time = "2026-03-04T14:17:24.4Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/b5/afabc8106abc0f9cfeecf5b3e682622b3e04bba1d9b967dbfcd91b9c4ebe/opentelemetry_exporter_otlp_proto_grpc-1.28.0-py3-none-any.whl", hash = "sha256:edbdc53e7783f88d4535db5807cb91bd7b1ec9e9b9cdbfee14cd378f29a3b328", size = 18532, upload-time = "2024-11-05T19:14:26.853Z" }, + { url = "https://files.pythonhosted.org/packages/96/6f/7ee0980afcbdcd2d40362da16f7f9796bd083bf7f0b8e038abfbc0300f5d/opentelemetry_exporter_otlp_proto_grpc-1.40.0-py3-none-any.whl", hash = "sha256:2aa0ca53483fe0cf6405087a7491472b70335bc5c7944378a0a8e72e86995c52", size = 20304, upload-time = "2026-03-04T14:17:05.942Z" }, ] [[package]] name = "opentelemetry-exporter-otlp-proto-http" -version = "1.28.0" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "deprecated" }, { name = "googleapis-common-protos" }, { name = "opentelemetry-api" }, { name = "opentelemetry-exporter-otlp-proto-common" }, { name = "opentelemetry-proto" }, { name = "opentelemetry-sdk" }, { name = "requests" }, + { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f1/2a/555f2845928086cd51aa6941c7a546470805b68ed631ec139ce7d841763d/opentelemetry_exporter_otlp_proto_http-1.28.0.tar.gz", hash = "sha256:d83a9a03a8367ead577f02a64127d827c79567de91560029688dd5cfd0152a8e", size = 15051, upload-time = "2024-11-05T19:14:49.813Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/fa/73d50e2c15c56be4d000c98e24221d494674b0cc95524e2a8cb3856d95a4/opentelemetry_exporter_otlp_proto_http-1.40.0.tar.gz", hash = "sha256:db48f5e0f33217588bbc00274a31517ba830da576e59503507c839b38fa0869c", size = 17772, upload-time = "2026-03-04T14:17:25.324Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b2/ce/80d5adabbf7ab4a0ca7b5e0f4039b24d273be370c3ba85fc05b13794411c/opentelemetry_exporter_otlp_proto_http-1.28.0-py3-none-any.whl", hash = "sha256:e8f3f7961b747edb6b44d51de4901a61e9c01d50debd747b120a08c4996c7e7b", size = 17228, upload-time = "2024-11-05T19:14:28.613Z" }, + { url = "https://files.pythonhosted.org/packages/a0/3a/8865d6754e61c9fb170cdd530a124a53769ee5f740236064816eb0ca7301/opentelemetry_exporter_otlp_proto_http-1.40.0-py3-none-any.whl", hash = "sha256:a8d1dab28f504c5d96577d6509f80a8150e44e8f45f82cdbe0e34c99ab040069", size = 19960, upload-time = "2026-03-04T14:17:07.153Z" }, ] [[package]] name = "opentelemetry-instrumentation" -version = "0.49b0" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -4296,14 +4298,14 @@ dependencies = [ { name = "packaging" }, { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/de/6b/6c25b15063c92a011cf3f68375971e2c58a9c764690847edc97df2d94eeb/opentelemetry_instrumentation-0.49b0.tar.gz", hash = "sha256:398a93e0b9dc2d11cc8627e1761665c506fe08c6b2df252a2ab3ade53d751c46", size = 26478, upload-time = "2024-11-05T19:21:41.402Z" } +sdist = { url = "https://files.pythonhosted.org/packages/da/37/6bf8e66bfcee5d3c6515b79cb2ee9ad05fe573c20f7ceb288d0e7eeec28c/opentelemetry_instrumentation-0.61b0.tar.gz", hash = "sha256:cb21b48db738c9de196eba6b805b4ff9de3b7f187e4bbf9a466fa170514f1fc7", size = 32606, upload-time = "2026-03-04T14:20:16.825Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/93/61/e0d21e958d6072ce25c4f5e26a1d22835fc86f80836660adf6badb6038ce/opentelemetry_instrumentation-0.49b0-py3-none-any.whl", hash = "sha256:68364d73a1ff40894574cbc6138c5f98674790cae1f3b0865e21cf702f24dcb3", size = 30694, upload-time = "2024-11-05T19:20:38.584Z" }, + { url = "https://files.pythonhosted.org/packages/d8/3e/f6f10f178b6316de67f0dfdbbb699a24fbe8917cf1743c1595fb9dcdd461/opentelemetry_instrumentation-0.61b0-py3-none-any.whl", hash = "sha256:92a93a280e69788e8f88391247cc530fd81f16f2b011979d4d6398f805cfbc63", size = 33448, upload-time = "2026-03-04T14:19:02.447Z" }, ] [[package]] name = "opentelemetry-instrumentation-asgi" -version = "0.49b0" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "asgiref" }, @@ -4312,28 +4314,28 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "opentelemetry-util-http" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e8/55/693c3d0938ba5fead5c3aa4ac7022a992b4ff99a8e9979800d0feb843ff4/opentelemetry_instrumentation_asgi-0.49b0.tar.gz", hash = "sha256:959fd9b1345c92f20c6ef1d42f92ef6a76b3c3083fbc4104d59da6859b15b083", size = 24117, upload-time = "2024-11-05T19:21:46.769Z" } +sdist = { url = "https://files.pythonhosted.org/packages/00/3e/143cf5c034e58037307e6a24f06e0dd64b2c49ae60a965fc580027581931/opentelemetry_instrumentation_asgi-0.61b0.tar.gz", hash = "sha256:9d08e127244361dc33976d39dd4ca8f128b5aa5a7ae425208400a80a095019b5", size = 26691, upload-time = "2026-03-04T14:20:21.038Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/0b/7900c782a1dfaa584588d724bc3bbdf8405a32497537dd96b3fcbf8461b9/opentelemetry_instrumentation_asgi-0.49b0-py3-none-any.whl", hash = "sha256:722a90856457c81956c88f35a6db606cc7db3231046b708aae2ddde065723dbe", size = 16326, upload-time = "2024-11-05T19:20:46.176Z" }, + { url = "https://files.pythonhosted.org/packages/19/78/154470cf9d741a7487fbb5067357b87386475bbb77948a6707cae982e158/opentelemetry_instrumentation_asgi-0.61b0-py3-none-any.whl", hash = "sha256:e4b3ce6b66074e525e717efff20745434e5efd5d9df6557710856fba356da7a4", size = 16980, upload-time = "2026-03-04T14:19:10.894Z" }, ] [[package]] name = "opentelemetry-instrumentation-celery" -version = "0.49b0" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "opentelemetry-instrumentation" }, { name = "opentelemetry-semantic-conventions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4c/8b/9b8a9dda3ed53354c6f707a45cdb7a4730e1c109b50fc1b413525493f811/opentelemetry_instrumentation_celery-0.49b0.tar.gz", hash = "sha256:afbaee97cc9c75f29bcc9784f16f8e37c415d4fe9b334748c5b90a3d30d12473", size = 14702, upload-time = "2024-11-05T19:21:53.672Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8d/43/e79108a804d16b1dc8ff28edd0e94ac393cf6359a5adcd7cdd2ec4be85f4/opentelemetry_instrumentation_celery-0.61b0.tar.gz", hash = "sha256:0e352a567dc89ed8bc083fc635035ce3c5b96bbbd92831ffd676e93b87f8e94f", size = 14780, upload-time = "2026-03-04T14:20:27.776Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/21/8c/d7d4adb36abbc0e517a69f7a069f32742122ae22d6017202f64570d9f4c5/opentelemetry_instrumentation_celery-0.49b0-py3-none-any.whl", hash = "sha256:38d4a78c78f33020032ef77ef0ead756bdf7838bcfb603de10f5925d39f14929", size = 13749, upload-time = "2024-11-05T19:20:54.98Z" }, + { url = "https://files.pythonhosted.org/packages/a2/ed/c05f3c84b455654eb6c047474ffde61ed92efc24030f64213c98bca9d44b/opentelemetry_instrumentation_celery-0.61b0-py3-none-any.whl", hash = "sha256:01235733ff0cdf571cb03b270645abb14b9c8d830313dc5842097ec90146320b", size = 13856, upload-time = "2026-03-04T14:19:20.98Z" }, ] [[package]] name = "opentelemetry-instrumentation-fastapi" -version = "0.49b0" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -4342,14 +4344,14 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "opentelemetry-util-http" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fe/bf/8e6d2a4807360f2203192017eb4845f5628dbeaf0597adf3d141cc5c24e1/opentelemetry_instrumentation_fastapi-0.49b0.tar.gz", hash = "sha256:6d14935c41fd3e49328188b6a59dd4c37bd17a66b01c15b0c64afa9714a1f905", size = 19230, upload-time = "2024-11-05T19:21:59.361Z" } +sdist = { url = "https://files.pythonhosted.org/packages/37/35/aa727bb6e6ef930dcdc96a617b83748fece57b43c47d83ba8d83fbeca657/opentelemetry_instrumentation_fastapi-0.61b0.tar.gz", hash = "sha256:3a24f35b07c557ae1bbc483bf8412221f25d79a405f8b047de8b670722e2fa9f", size = 24800, upload-time = "2026-03-04T14:20:32.759Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/f4/0895b9410c10abf987c90dee1b7688a8f2214a284fe15e575648f6a1473a/opentelemetry_instrumentation_fastapi-0.49b0-py3-none-any.whl", hash = "sha256:646e1b18523cbe6860ae9711eb2c7b9c85466c3c7697cd6b8fb5180d85d3fe6e", size = 12101, upload-time = "2024-11-05T19:21:01.805Z" }, + { url = "https://files.pythonhosted.org/packages/91/05/acfeb2cccd434242a0a7d0ea29afaf077e04b42b35b485d89aee4e0d9340/opentelemetry_instrumentation_fastapi-0.61b0-py3-none-any.whl", hash = "sha256:a1a844d846540d687d377516b2ff698b51d87c781b59f47c214359c4a241047c", size = 13485, upload-time = "2026-03-04T14:19:30.351Z" }, ] [[package]] name = "opentelemetry-instrumentation-flask" -version = "0.49b0" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -4359,14 +4361,14 @@ dependencies = [ { name = "opentelemetry-util-http" }, { name = "packaging" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/17/12/dc72873fb1e35699941d8eb6a53ef25e8c5843dea37665dad33bd720f047/opentelemetry_instrumentation_flask-0.49b0.tar.gz", hash = "sha256:f7c5ab67753c4781a2e21c8f43dc5fc02ece74fdd819466c75d025db80aa7576", size = 19176, upload-time = "2024-11-05T19:22:00.816Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d9/33/d6852d8f2c3eef86f2f8c858d6f5315983c7063e07e595519e96d4c31c06/opentelemetry_instrumentation_flask-0.61b0.tar.gz", hash = "sha256:e9faf58dfd9860a1868442d180142645abdafc1a652dd73d469a5efd106a7d49", size = 24071, upload-time = "2026-03-04T14:20:33.437Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/fc/354da8f33ef0daebfc8e4eac995d342ae13a35097bbad512cfe0d2f3c61a/opentelemetry_instrumentation_flask-0.49b0-py3-none-any.whl", hash = "sha256:f3ef330c3cee3e2c161f27f1e7017c8800b9bfb6f9204f2f7bfb0b274874be0e", size = 14582, upload-time = "2024-11-05T19:21:02.793Z" }, + { url = "https://files.pythonhosted.org/packages/3e/41/619f3530324a58491f2d20f216a10dd7393629b29db4610dda642a27f4ed/opentelemetry_instrumentation_flask-0.61b0-py3-none-any.whl", hash = "sha256:e8ce474d7ce543bfbbb3e93f8a6f8263348af9d7b45502f387420cf3afa71253", size = 15996, upload-time = "2026-03-04T14:19:31.304Z" }, ] [[package]] name = "opentelemetry-instrumentation-httpx" -version = "0.49b0" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -4375,14 +4377,14 @@ dependencies = [ { name = "opentelemetry-util-http" }, { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a0/53/8b5e05e55a513d846ead5afb0509bec37a34a1c3e82f30b13d14156334b1/opentelemetry_instrumentation_httpx-0.49b0.tar.gz", hash = "sha256:07165b624f3e58638cee47ecf1c81939a8c2beb7e42ce9f69e25a9f21dc3f4cf", size = 17750, upload-time = "2024-11-05T19:22:02.911Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/2a/e2becd55e33c29d1d9ef76e2579040ed1951cb33bacba259f6aff2fdd2a6/opentelemetry_instrumentation_httpx-0.61b0.tar.gz", hash = "sha256:6569ec097946c5551c2a4252f74c98666addd1bf047c1dde6b4ef426719ff8dd", size = 24104, upload-time = "2026-03-04T14:20:34.752Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/9f/843391c6d645cd4f6914b27bc807fc1ff52b97f84cbe3ca675641976b23f/opentelemetry_instrumentation_httpx-0.49b0-py3-none-any.whl", hash = "sha256:e59e0d2fda5ef841630c68da1d78ff9192f63590a9099f12f0eab614abdf239a", size = 14110, upload-time = "2024-11-05T19:21:04.698Z" }, + { url = "https://files.pythonhosted.org/packages/af/88/dde310dce56e2d85cf1a09507f5888544955309edc4b8d22971d6d3d1417/opentelemetry_instrumentation_httpx-0.61b0-py3-none-any.whl", hash = "sha256:dee05c93a6593a5dc3ae5d9d5c01df8b4e2c5d02e49275e5558534ee46343d5e", size = 17198, upload-time = "2026-03-04T14:19:33.585Z" }, ] [[package]] name = "opentelemetry-instrumentation-redis" -version = "0.49b0" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -4390,14 +4392,14 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/19/5b/1398eb2f92fd76787ccec28d24dc4c7dfaaf97a7557e7729e2f7c2c05d84/opentelemetry_instrumentation_redis-0.49b0.tar.gz", hash = "sha256:922542c3bd192ad4ba74e2c7e0a253c7c58a5cefbd6f89da2aba4d193a974703", size = 11353, upload-time = "2024-11-05T19:22:12.822Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/21/26205f89358a5f2be3ee5512d3d3bce16b622977f64aeaa9d3fa8887dd39/opentelemetry_instrumentation_redis-0.61b0.tar.gz", hash = "sha256:ae0fbb56be9a641e621d55b02a7d62977a2c77c5ee760addd79b9b266e46e523", size = 14781, upload-time = "2026-03-04T14:20:45.694Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/24/e4/4f258fef0759629f2e8a0210d5533cfef3ecad69ff35be044637a3e2783e/opentelemetry_instrumentation_redis-0.49b0-py3-none-any.whl", hash = "sha256:b7d8f758bac53e77b7e7ca98ce80f91230577502dacb619ebe8e8b6058042067", size = 12453, upload-time = "2024-11-05T19:21:18.534Z" }, + { url = "https://files.pythonhosted.org/packages/a5/e1/8f4c8e4194291dbe828aeabe779050a8497b379ad90040a5a0a7074b1d08/opentelemetry_instrumentation_redis-0.61b0-py3-none-any.whl", hash = "sha256:8d4e850bbb5f8eeafa44c0eac3a007990c7125de187bc9c3659e29ff7e091172", size = 15506, upload-time = "2026-03-04T14:19:48.588Z" }, ] [[package]] name = "opentelemetry-instrumentation-sqlalchemy" -version = "0.49b0" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -4406,14 +4408,14 @@ dependencies = [ { name = "packaging" }, { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a0/a7/24f6cce3808ae1802dd1b60d752fbab877db5655198929cf4ee8ea416923/opentelemetry_instrumentation_sqlalchemy-0.49b0.tar.gz", hash = "sha256:32658e520fc8b35823c722f5d8831d3a410b76dd2724adb2887befc041ddef04", size = 13194, upload-time = "2024-11-05T19:22:14.92Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9e/4f/3a325b180944610697a0a926d49d782b41a86120050d44fefb2715b630ac/opentelemetry_instrumentation_sqlalchemy-0.61b0.tar.gz", hash = "sha256:13a3a159a2043a52f0180b3757fbaa26741b0e08abb50deddce4394c118956e6", size = 15343, upload-time = "2026-03-04T14:20:47.648Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/6b/a1a3685fed593282999cdc374ece15efbd56f8d774bd368bf7ff2cf5923c/opentelemetry_instrumentation_sqlalchemy-0.49b0-py3-none-any.whl", hash = "sha256:d854052d2b02cd0562e5628a514c8153fceada7f585137e173165dfd0a46ef6a", size = 13358, upload-time = "2024-11-05T19:21:23.654Z" }, + { url = "https://files.pythonhosted.org/packages/1f/97/b906a930c6a1a20c53ecc8b58cabc2cdd0ce560a2b5d44259084ffe4333e/opentelemetry_instrumentation_sqlalchemy-0.61b0-py3-none-any.whl", hash = "sha256:f115e0be54116ba4c327b8d7b68db4045ee18d44439d888ab8130a549c50d1c1", size = 14547, upload-time = "2026-03-04T14:19:53.088Z" }, ] [[package]] name = "opentelemetry-instrumentation-wsgi" -version = "0.49b0" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -4421,9 +4423,9 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "opentelemetry-util-http" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/17/2b/91b022b004ac9e9ab0eefd10bc4257975291f88adc81b4ef2c601ddb1adf/opentelemetry_instrumentation_wsgi-0.49b0.tar.gz", hash = "sha256:0812a02e132f8fc3d5c897bba84e530c37b85c315b199bb97ca6508279e7eb23", size = 17733, upload-time = "2024-11-05T19:22:24.3Z" } +sdist = { url = "https://files.pythonhosted.org/packages/89/e5/189f2845362cfe78e356ba127eab21456309def411c6874aa4800c3de816/opentelemetry_instrumentation_wsgi-0.61b0.tar.gz", hash = "sha256:380f2ae61714e5303275a80b2e14c58571573cd1fddf496d8c39fb9551c5e532", size = 19898, upload-time = "2026-03-04T14:20:54.068Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/02/1d/59979665778ed8c85bc31c92b75571cd7afb8e3322fb513c87fe1bad6d78/opentelemetry_instrumentation_wsgi-0.49b0-py3-none-any.whl", hash = "sha256:8869ccf96611827e4448417718920e9eec6d25bffb5bf72c7952c7346ec33fbc", size = 13699, upload-time = "2024-11-05T19:21:35.039Z" }, + { url = "https://files.pythonhosted.org/packages/96/75/d6b42ba26f3c921be6d01b16561b7bb863f843bad7ac3a5011f62617bcab/opentelemetry_instrumentation_wsgi-0.61b0-py3-none-any.whl", hash = "sha256:bd33b0824166f24134a3400648805e8d2e6a7951f070241294e8b8866611d7fa", size = 14628, upload-time = "2026-03-04T14:20:03.934Z" }, ] [[package]] @@ -4441,50 +4443,50 @@ wheels = [ [[package]] name = "opentelemetry-proto" -version = "1.28.0" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c9/63/ac4cef4d30ea0ca1d2153ad2fc62d91d1cf3b89b0e4e5cbd61a8c567885f/opentelemetry_proto-1.28.0.tar.gz", hash = "sha256:4a45728dfefa33f7908b828b9b7c9f2c6de42a05d5ec7b285662ddae71c4c870", size = 34331, upload-time = "2024-11-05T19:14:59.503Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/77/dd38991db037fdfce45849491cb61de5ab000f49824a00230afb112a4392/opentelemetry_proto-1.40.0.tar.gz", hash = "sha256:03f639ca129ba513f5819810f5b1f42bcb371391405d99c168fe6937c62febcd", size = 45667, upload-time = "2026-03-04T14:17:31.194Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/86/94/c0b43d16e1d96ee1e699373aa59f14a3aa2e7126af3f11d6adc5dcc531cd/opentelemetry_proto-1.28.0-py3-none-any.whl", hash = "sha256:d5ad31b997846543b8e15504657d9a8cf1ad3c71dcbbb6c4799b1ab29e38f7f9", size = 55832, upload-time = "2024-11-05T19:14:40.446Z" }, + { url = "https://files.pythonhosted.org/packages/b9/b2/189b2577dde745b15625b3214302605b1353436219d42b7912e77fa8dc24/opentelemetry_proto-1.40.0-py3-none-any.whl", hash = "sha256:266c4385d88923a23d63e353e9761af0f47a6ed0d486979777fe4de59dc9b25f", size = 72073, upload-time = "2026-03-04T14:17:16.673Z" }, ] [[package]] name = "opentelemetry-sdk" -version = "1.28.0" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "opentelemetry-semantic-conventions" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0c/5b/a509ccab93eacc6044591d5ec437d8266e76f893d0389bbf7e5592c7da32/opentelemetry_sdk-1.28.0.tar.gz", hash = "sha256:41d5420b2e3fb7716ff4981b510d551eff1fc60eb5a95cf7335b31166812a893", size = 156155, upload-time = "2024-11-05T19:15:00.451Z" } +sdist = { url = "https://files.pythonhosted.org/packages/58/fd/3c3125b20ba18ce2155ba9ea74acb0ae5d25f8cd39cfd37455601b7955cc/opentelemetry_sdk-1.40.0.tar.gz", hash = "sha256:18e9f5ec20d859d268c7cb3c5198c8d105d073714db3de50b593b8c1345a48f2", size = 184252, upload-time = "2026-03-04T14:17:31.87Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c3/fe/c8decbebb5660529f1d6ba65e50a45b1294022dfcba2968fc9c8697c42b2/opentelemetry_sdk-1.28.0-py3-none-any.whl", hash = "sha256:4b37da81d7fad67f6683c4420288c97f4ed0d988845d5886435f428ec4b8429a", size = 118692, upload-time = "2024-11-05T19:14:41.669Z" }, + { url = "https://files.pythonhosted.org/packages/2c/c5/6a852903d8bfac758c6dc6e9a68b015d3c33f2f1be5e9591e0f4b69c7e0a/opentelemetry_sdk-1.40.0-py3-none-any.whl", hash = "sha256:787d2154a71f4b3d81f20524a8ce061b7db667d24e46753f32a7bc48f1c1f3f1", size = 141951, upload-time = "2026-03-04T14:17:17.961Z" }, ] [[package]] name = "opentelemetry-semantic-conventions" -version = "0.49b0" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "deprecated" }, { name = "opentelemetry-api" }, + { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ee/c8/433b0e54143f8c9369f5c4a7a83e73eec7eb2ee7d0b7e81a9243e78c8e80/opentelemetry_semantic_conventions-0.49b0.tar.gz", hash = "sha256:dbc7b28339e5390b6b28e022835f9bac4e134a80ebf640848306d3c5192557e8", size = 95227, upload-time = "2024-11-05T19:15:01.443Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6d/c0/4ae7973f3c2cfd2b6e321f1675626f0dab0a97027cc7a297474c9c8f3d04/opentelemetry_semantic_conventions-0.61b0.tar.gz", hash = "sha256:072f65473c5d7c6dc0355b27d6c9d1a679d63b6d4b4b16a9773062cb7e31192a", size = 145755, upload-time = "2026-03-04T14:17:32.664Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/25/05/20104df4ef07d3bf5c3fd6bcc796ef70ab4ea4309378a9ba57bc4b4d01fa/opentelemetry_semantic_conventions-0.49b0-py3-none-any.whl", hash = "sha256:0458117f6ead0b12e3221813e3e511d85698c31901cac84682052adb9c17c7cd", size = 159214, upload-time = "2024-11-05T19:14:43.047Z" }, + { url = "https://files.pythonhosted.org/packages/b2/37/cc6a55e448deaa9b27377d087da8615a3416d8ad523d5960b78dbeadd02a/opentelemetry_semantic_conventions-0.61b0-py3-none-any.whl", hash = "sha256:fa530a96be229795f8cef353739b618148b0fe2b4b3f005e60e262926c4d38e2", size = 231621, upload-time = "2026-03-04T14:17:19.33Z" }, ] [[package]] name = "opentelemetry-util-http" -version = "0.49b0" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a3/99/377ef446928808211b127b9ab31c348bc465c8da4514ebeec6e4a3de3d21/opentelemetry_util_http-0.49b0.tar.gz", hash = "sha256:02928496afcffd58a7c15baf99d2cedae9b8325a8ac52b0d0877b2e8f936dd1b", size = 7863, upload-time = "2024-11-05T19:22:26.973Z" } +sdist = { url = "https://files.pythonhosted.org/packages/57/3c/f0196223efc5c4ca19f8fad3d5462b171ac6333013335ce540c01af419e9/opentelemetry_util_http-0.61b0.tar.gz", hash = "sha256:1039cb891334ad2731affdf034d8fb8b48c239af9b6dd295e5fabd07f1c95572", size = 11361, upload-time = "2026-03-04T14:20:57.01Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/66/0e/ab0a89b315d0bacdd355a345bb69b20c50fc1f0804b52b56fe1c35a60e68/opentelemetry_util_http-0.49b0-py3-none-any.whl", hash = "sha256:8661bbd6aea1839badc44de067ec9c15c05eab05f729f496c856c50a1203caf1", size = 6945, upload-time = "2024-11-05T19:21:37.81Z" }, + { url = "https://files.pythonhosted.org/packages/0d/e5/c08aaaf2f64288d2b6ef65741d2de5454e64af3e050f34285fb1907492fe/opentelemetry_util_http-0.61b0-py3-none-any.whl", hash = "sha256:8e715e848233e9527ea47e275659ea60a57a75edf5206a3b937e236a6da5fc33", size = 9281, upload-time = "2026-03-04T14:20:08.364Z" }, ] [[package]] From 51f6ca2bed96cbc736371fbce22786ddf773ad65 Mon Sep 17 00:00:00 2001 From: Wu Tianwei <30284043+WTW0313@users.noreply.github.com> Date: Mon, 30 Mar 2026 21:07:20 +0800 Subject: [PATCH 07/40] fix(workflow): improve node organization (#34276) --- .../use-workflow-interactions.spec.tsx | 6 +- .../workflow/hooks/use-workflow-organize.ts | 4 +- .../utils/__tests__/elk-layout.spec.ts | 68 ++--- .../components/workflow/utils/elk-layout.ts | 233 +++++++----------- 4 files changed, 123 insertions(+), 188 deletions(-) diff --git a/web/app/components/workflow/hooks/__tests__/use-workflow-interactions.spec.tsx b/web/app/components/workflow/hooks/__tests__/use-workflow-interactions.spec.tsx index 457b54e763..95dc3dff00 100644 --- a/web/app/components/workflow/hooks/__tests__/use-workflow-interactions.spec.tsx +++ b/web/app/components/workflow/hooks/__tests__/use-workflow-interactions.spec.tsx @@ -28,7 +28,7 @@ const mockHandleEdgeCancelRunningStatus = vi.hoisted(() => vi.fn()) const mockHandleSyncWorkflowDraft = vi.hoisted(() => vi.fn()) const mockSaveStateToHistory = vi.hoisted(() => vi.fn()) const mockGetLayoutForChildNodes = vi.hoisted(() => vi.fn()) -const mockGetLayoutByDagre = vi.hoisted(() => vi.fn()) +const mockGetLayoutByELK = vi.hoisted(() => vi.fn()) const mockInitialNodes = vi.hoisted(() => vi.fn((nodes: unknown[], _edges: unknown[]) => nodes)) const mockInitialEdges = vi.hoisted(() => vi.fn((edges: unknown[], _nodes: unknown[]) => edges)) @@ -112,7 +112,7 @@ vi.mock('../use-workflow-history', () => ({ vi.mock('../../utils', async importOriginal => ({ ...(await importOriginal()), getLayoutForChildNodes: (...args: unknown[]) => mockGetLayoutForChildNodes(...args), - getLayoutByDagre: (...args: unknown[]) => mockGetLayoutByDagre(...args), + getLayoutByELK: (...args: unknown[]) => mockGetLayoutByELK(...args), initialNodes: (nodes: unknown[], edges: unknown[]) => mockInitialNodes(nodes, edges), initialEdges: (edges: unknown[], nodes: unknown[]) => mockInitialEdges(edges, nodes), })) @@ -203,7 +203,7 @@ describe('use-workflow-interactions exports', () => { ['loop-child', { x: 40, y: 60, width: 100, height: 60 }], ]), }) - mockGetLayoutByDagre.mockResolvedValue({ + mockGetLayoutByELK.mockResolvedValue({ nodes: new Map([ ['loop-node', { x: 10, y: 20, width: 360, height: 260, layer: 0 }], ['top-node', { x: 500, y: 30, width: 240, height: 100, layer: 0 }], diff --git a/web/app/components/workflow/hooks/use-workflow-organize.ts b/web/app/components/workflow/hooks/use-workflow-organize.ts index 284fb2261c..da158a4214 100644 --- a/web/app/components/workflow/hooks/use-workflow-organize.ts +++ b/web/app/components/workflow/hooks/use-workflow-organize.ts @@ -2,7 +2,7 @@ import { useCallback } from 'react' import { useReactFlow, useStoreApi } from 'reactflow' import { useWorkflowStore } from '../store' import { - getLayoutByDagre, + getLayoutByELK, getLayoutForChildNodes, } from '../utils' import { useNodesSyncDraft } from './use-nodes-sync-draft' @@ -49,7 +49,7 @@ export const useWorkflowOrganize = () => { nodes, getContainerSizeChanges(parentNodes, childLayoutsMap), ) - const layout = await getLayoutByDagre(nodesWithUpdatedSizes, edges) + const layout = await getLayoutByELK(nodesWithUpdatedSizes, edges) const nextNodes = applyLayoutToNodes({ nodes: nodesWithUpdatedSizes, layout, diff --git a/web/app/components/workflow/utils/__tests__/elk-layout.spec.ts b/web/app/components/workflow/utils/__tests__/elk-layout.spec.ts index 662b380f5d..1a3c52ec2d 100644 --- a/web/app/components/workflow/utils/__tests__/elk-layout.spec.ts +++ b/web/app/components/workflow/utils/__tests__/elk-layout.spec.ts @@ -5,7 +5,7 @@ import { CUSTOM_ITERATION_START_NODE } from '../../nodes/iteration-start/constan import { CUSTOM_LOOP_START_NODE } from '../../nodes/loop-start/constants' import { BlockEnum } from '../../types' -type ElkChild = Record & { id: string, width?: number, height?: number, x?: number, y?: number, children?: ElkChild[], ports?: Array<{ id: string }>, layoutOptions?: Record } +type ElkChild = Record & { id: string, width?: number, height?: number, x?: number, y?: number, children?: ElkChild[], ports?: Array<{ id: string, layoutOptions?: Record }>, layoutOptions?: Record } type ElkGraph = Record & { id: string, children?: ElkChild[], edges?: Array> } let layoutCallArgs: ElkGraph | null = null @@ -32,7 +32,7 @@ vi.mock('elkjs/lib/elk.bundled.js', () => { } }) -const { getLayoutByDagre, getLayoutForChildNodes } = await import('../elk-layout') +const { getLayoutByELK, getLayoutForChildNodes } = await import('../elk-layout') function makeWorkflowNode(overrides: Omit, 'data'> & { data?: Partial & Record } = {}): Node { return createNode({ @@ -51,7 +51,7 @@ beforeEach(() => { mockReturnOverride = null }) -describe('getLayoutByDagre', () => { +describe('getLayoutByELK', () => { it('should return layout for simple linear graph', async () => { const nodes = [ makeWorkflowNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }), @@ -59,7 +59,7 @@ describe('getLayoutByDagre', () => { ] const edges = [makeWorkflowEdge({ source: 'a', target: 'b' })] - const result = await getLayoutByDagre(nodes, edges) + const result = await getLayoutByELK(nodes, edges) expect(result.nodes.size).toBe(2) expect(result.nodes.has('a')).toBe(true) @@ -74,7 +74,7 @@ describe('getLayoutByDagre', () => { makeWorkflowNode({ id: 'child', data: { type: BlockEnum.Code, title: '', desc: '' }, parentId: 'a' }), ] - const result = await getLayoutByDagre(nodes, []) + const result = await getLayoutByELK(nodes, []) expect(result.nodes.size).toBe(1) expect(result.nodes.has('child')).toBe(false) }) @@ -85,7 +85,7 @@ describe('getLayoutByDagre', () => { makeWorkflowNode({ id: 'iter-start', type: CUSTOM_ITERATION_START_NODE, data: { type: BlockEnum.IterationStart, title: '', desc: '' } }), ] - const result = await getLayoutByDagre(nodes, []) + const result = await getLayoutByELK(nodes, []) expect(result.nodes.size).toBe(1) }) @@ -98,7 +98,7 @@ describe('getLayoutByDagre', () => { makeWorkflowEdge({ source: 'a', target: 'b', data: { isInIteration: true, iteration_id: 'iter-1' } }), ] - await getLayoutByDagre(nodes, edges) + await getLayoutByELK(nodes, edges) expect(layoutCallArgs!.edges).toHaveLength(0) }) @@ -107,7 +107,7 @@ describe('getLayoutByDagre', () => { Reflect.deleteProperty(node, 'width') Reflect.deleteProperty(node, 'height') - const result = await getLayoutByDagre([node], []) + const result = await getLayoutByELK([node], []) expect(result.nodes.size).toBe(1) const info = result.nodes.get('a')! expect(info.width).toBe(244) @@ -133,13 +133,13 @@ describe('getLayoutByDagre', () => { makeWorkflowEdge({ id: 'e2', source: 'if-1', target: 'c', sourceHandle: 'false' }), ] - await getLayoutByDagre(nodes, edges) + await getLayoutByELK(nodes, edges) const ifElkNode = layoutCallArgs!.children!.find((c: ElkChild) => c.id === 'if-1')! expect(ifElkNode.ports).toHaveLength(2) expect(ifElkNode.layoutOptions!['elk.portConstraints']).toBe('FIXED_ORDER') }) - it('should use normal node for IfElse with single branch', async () => { + it('should build ports for IfElse even with single branch', async () => { const nodes = [ makeWorkflowNode({ id: 'if-1', @@ -149,9 +149,10 @@ describe('getLayoutByDagre', () => { ] const edges = [makeWorkflowEdge({ source: 'if-1', target: 'b', sourceHandle: 'case-1' })] - await getLayoutByDagre(nodes, edges) + await getLayoutByELK(nodes, edges) const ifElkNode = layoutCallArgs!.children!.find((c: ElkChild) => c.id === 'if-1')! - expect(ifElkNode.ports).toBeUndefined() + expect(ifElkNode.ports).toHaveLength(1) + expect(ifElkNode.ports![0].layoutOptions!['elk.port.side']).toBe('EAST') }) it('should build ports for HumanInput nodes with multiple branches', async () => { @@ -168,12 +169,12 @@ describe('getLayoutByDagre', () => { makeWorkflowEdge({ id: 'e2', source: 'hi-1', target: 'c', sourceHandle: '__timeout' }), ] - await getLayoutByDagre(nodes, edges) + await getLayoutByELK(nodes, edges) const hiElkNode = layoutCallArgs!.children!.find((c: ElkChild) => c.id === 'hi-1')! expect(hiElkNode.ports).toHaveLength(2) }) - it('should use normal node for HumanInput with single branch', async () => { + it('should build ports for HumanInput even with single branch', async () => { const nodes = [ makeWorkflowNode({ id: 'hi-1', @@ -183,20 +184,21 @@ describe('getLayoutByDagre', () => { ] const edges = [makeWorkflowEdge({ source: 'hi-1', target: 'b', sourceHandle: 'action-1' })] - await getLayoutByDagre(nodes, edges) + await getLayoutByELK(nodes, edges) const hiElkNode = layoutCallArgs!.children!.find((c: ElkChild) => c.id === 'hi-1')! - expect(hiElkNode.ports).toBeUndefined() + expect(hiElkNode.ports).toHaveLength(1) + expect(hiElkNode.ports![0].layoutOptions!['elk.port.side']).toBe('EAST') }) it('should normalise bounds so minX and minY start at 0', async () => { const nodes = [makeWorkflowNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } })] - const result = await getLayoutByDagre(nodes, []) + const result = await getLayoutByELK(nodes, []) expect(result.bounds.minX).toBe(0) expect(result.bounds.minY).toBe(0) }) it('should return empty layout when no nodes match filter', async () => { - const result = await getLayoutByDagre([], []) + const result = await getLayoutByELK([], []) expect(result.nodes.size).toBe(0) expect(result.bounds).toEqual({ minX: 0, minY: 0, maxX: 0, maxY: 0 }) }) @@ -225,7 +227,7 @@ describe('getLayoutByDagre', () => { makeWorkflowEdge({ id: 'e-b', source: 'if-1', target: 'y', sourceHandle: 'case-b' }), ] - await getLayoutByDagre(nodes, edges) + await getLayoutByELK(nodes, edges) const ifNode = layoutCallArgs!.children!.find((c: ElkChild) => c.id === 'if-1')! const portIds = ifNode.ports!.map((p: { id: string }) => p.id) expect(portIds[portIds.length - 1]).toContain('false') @@ -247,7 +249,7 @@ describe('getLayoutByDagre', () => { makeWorkflowEdge({ id: 'e-a2', source: 'hi-1', target: 'y', sourceHandle: 'a2' }), ] - await getLayoutByDagre(nodes, edges) + await getLayoutByELK(nodes, edges) const hiNode = layoutCallArgs!.children!.find((c: ElkChild) => c.id === 'hi-1')! const portIds = hiNode.ports!.map((p: { id: string }) => p.id) expect(portIds[portIds.length - 1]).toContain('__timeout') @@ -267,7 +269,7 @@ describe('getLayoutByDagre', () => { makeWorkflowEdge({ id: 'e2', source: 'if-1', target: 'c', sourceHandle: 'false' }), ] - await getLayoutByDagre(nodes, edges) + await getLayoutByELK(nodes, edges) const portEdges = layoutCallArgs!.edges!.filter((e: Record) => e.sourcePort) expect(portEdges.length).toBeGreaterThan(0) }) @@ -286,7 +288,7 @@ describe('getLayoutByDagre', () => { Reflect.deleteProperty(e1, 'sourceHandle') Reflect.deleteProperty(e2, 'sourceHandle') - const result = await getLayoutByDagre(nodes, [e1, e2]) + const result = await getLayoutByELK(nodes, [e1, e2]) expect(result.nodes.size).toBeGreaterThan(0) }) @@ -299,7 +301,7 @@ describe('getLayoutByDagre', () => { }) const nodes = [makeWorkflowNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } })] - const result = await getLayoutByDagre(nodes, []) + const result = await getLayoutByELK(nodes, []) const info = result.nodes.get('a')! expect(info.x).toBe(0) expect(info.y).toBe(0) @@ -326,7 +328,7 @@ describe('getLayoutByDagre', () => { makeWorkflowNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }), makeWorkflowNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), ] - const result = await getLayoutByDagre(nodes, []) + const result = await getLayoutByELK(nodes, []) expect(result.nodes.get('a')!.layer).toBe(0) expect(result.nodes.get('b')!.layer).toBe(1) }) @@ -354,7 +356,7 @@ describe('getLayoutByDagre', () => { makeWorkflowNode({ id: 'nested-1', data: { type: BlockEnum.Code, title: '', desc: '' } }), makeWorkflowNode({ id: 'nested-2', data: { type: BlockEnum.Code, title: '', desc: '' } }), ] - const result = await getLayoutByDagre(nodes, []) + const result = await getLayoutByELK(nodes, []) expect(result.nodes.has('nested-1')).toBe(true) expect(result.nodes.has('nested-2')).toBe(true) }) @@ -372,7 +374,7 @@ describe('getLayoutByDagre', () => { makeWorkflowNode({ id: 'visible', data: { type: BlockEnum.Start, title: '', desc: '' } }), makeWorkflowNode({ id: 'also-visible', data: { type: BlockEnum.Code, title: '', desc: '' } }), ] - const result = await getLayoutByDagre(nodes, []) + const result = await getLayoutByELK(nodes, []) expect(result.nodes.size).toBe(2) }) @@ -390,7 +392,7 @@ describe('getLayoutByDagre', () => { makeWorkflowEdge({ id: 'e2', source: 'if-1', target: 'c', sourceHandle: 'other-unknown' }), ] - await getLayoutByDagre(nodes, edges) + await getLayoutByELK(nodes, edges) const ifNode = layoutCallArgs!.children!.find((c: ElkChild) => c.id === 'if-1')! expect(ifNode.ports).toHaveLength(2) }) @@ -409,7 +411,7 @@ describe('getLayoutByDagre', () => { makeWorkflowEdge({ id: 'e2', source: 'hi-1', target: 'c', sourceHandle: 'another-unknown' }), ] - await getLayoutByDagre(nodes, edges) + await getLayoutByELK(nodes, edges) const hiNode = layoutCallArgs!.children!.find((c: ElkChild) => c.id === 'hi-1')! expect(hiNode.ports).toHaveLength(2) }) @@ -428,7 +430,7 @@ describe('getLayoutByDagre', () => { Reflect.deleteProperty(e1, 'sourceHandle') Reflect.deleteProperty(e2, 'sourceHandle') - await getLayoutByDagre(nodes, [e1, e2]) + await getLayoutByELK(nodes, [e1, e2]) const ifNode = layoutCallArgs!.children!.find((c: ElkChild) => c.id === 'if-1')! expect(ifNode.ports).toHaveLength(2) }) @@ -447,7 +449,7 @@ describe('getLayoutByDagre', () => { Reflect.deleteProperty(e1, 'sourceHandle') Reflect.deleteProperty(e2, 'sourceHandle') - await getLayoutByDagre(nodes, [e1, e2]) + await getLayoutByELK(nodes, [e1, e2]) const hiNode = layoutCallArgs!.children!.find((c: ElkChild) => c.id === 'hi-1')! expect(hiNode.ports).toHaveLength(2) }) @@ -463,7 +465,7 @@ describe('getLayoutByDagre', () => { makeWorkflowEdge({ id: 'e2', source: 'if-1', target: 'c', sourceHandle: 'false' }), ] - await getLayoutByDagre(nodes, edges) + await getLayoutByELK(nodes, edges) const ifNode = layoutCallArgs!.children!.find((c: ElkChild) => c.id === 'if-1')! expect(ifNode.ports).toHaveLength(2) }) @@ -479,7 +481,7 @@ describe('getLayoutByDagre', () => { makeWorkflowEdge({ id: 'e2', source: 'hi-1', target: 'c', sourceHandle: '__timeout' }), ] - await getLayoutByDagre(nodes, edges) + await getLayoutByELK(nodes, edges) const hiNode = layoutCallArgs!.children!.find((c: ElkChild) => c.id === 'hi-1')! expect(hiNode.ports).toHaveLength(2) }) @@ -492,7 +494,7 @@ describe('getLayoutByDagre', () => { makeWorkflowEdge({ source: 'x', target: 'y', data: { isInLoop: true, loop_id: 'loop-1' } }), ] - await getLayoutByDagre(nodes, edges) + await getLayoutByELK(nodes, edges) expect(layoutCallArgs!.edges).toHaveLength(0) }) }) diff --git a/web/app/components/workflow/utils/elk-layout.ts b/web/app/components/workflow/utils/elk-layout.ts index 280d0f7b1d..9860bbc770 100644 --- a/web/app/components/workflow/utils/elk-layout.ts +++ b/web/app/components/workflow/utils/elk-layout.ts @@ -18,9 +18,6 @@ import { BlockEnum, } from '@/app/components/workflow/types' -// Although the file name refers to Dagre, the implementation now relies on ELK's layered algorithm. -// Keep the export signatures unchanged to minimise the blast radius while we migrate the layout stack. - const elk = new ELK() const DEFAULT_NODE_WIDTH = 244 @@ -41,7 +38,6 @@ const ROOT_LAYOUT_OPTIONS = { // === Port Configuration === 'elk.portConstraints': 'FIXED_ORDER', 'elk.layered.considerModelOrder.strategy': 'PREFER_EDGES', - 'elk.port.side': 'SOUTH', // === Node Placement - Best quality === 'elk.layered.nodePlacement.strategy': 'NETWORK_SIMPLEX', @@ -278,32 +274,16 @@ const collectLayout = (graph: ElkNode, predicate: (id: string) => boolean): Layo } } -/** - * Build If/Else node with ELK native Ports instead of dummy nodes - * This is the recommended approach for handling multiple branches - */ -const buildIfElseWithPorts = ( - ifElseNode: Node, - edges: Edge[], -): { node: ElkNodeShape, portMap: Map } | null => { - const childEdges = edges.filter(edge => edge.source === ifElseNode.id) - - if (childEdges.length <= 1) - return null - - // Sort child edges according to case order - const sortedChildEdges = [...childEdges].sort((edgeA, edgeB) => { +const sortIfElseOutEdges = (ifElseNode: Node, outEdges: Edge[]): Edge[] => { + return [...outEdges].sort((edgeA, edgeB) => { const handleA = edgeA.sourceHandle const handleB = edgeB.sourceHandle if (handleA && handleB) { const cases = (ifElseNode.data as IfElseNodeType).cases || [] - const isAElse = handleA === 'false' - const isBElse = handleB === 'false' - - if (isAElse) + if (handleA === 'false') return 1 - if (isBElse) + if (handleB === 'false') return -1 const indexA = cases.findIndex((c: CaseItem) => c.case_id === handleA) @@ -315,67 +295,20 @@ const buildIfElseWithPorts = ( return 0 }) - - // Create ELK ports for each branch - const ports: ElkPortShape[] = sortedChildEdges.map((edge, index) => ({ - id: `${ifElseNode.id}-port-${edge.sourceHandle || index}`, - layoutOptions: { - 'port.side': 'EAST', // Ports on the right side (matching 'RIGHT' direction) - 'port.index': String(index), - }, - })) - - // Build port mapping: sourceHandle -> portId - const portMap = new Map() - sortedChildEdges.forEach((edge, index) => { - const portId = `${ifElseNode.id}-port-${edge.sourceHandle || index}` - portMap.set(edge.id, portId) - }) - - return { - node: { - id: ifElseNode.id, - width: ifElseNode.width ?? DEFAULT_NODE_WIDTH, - height: ifElseNode.height ?? DEFAULT_NODE_HEIGHT, - ports, - layoutOptions: { - 'elk.portConstraints': 'FIXED_ORDER', - }, - }, - portMap, - } } -/** - * Build Human Input node with ELK native Ports for multiple branches - * Handles user actions as branches with __timeout as the last fixed branch - */ -const buildHumanInputWithPorts = ( - humanInputNode: Node, - edges: Edge[], -): { node: ElkNodeShape, portMap: Map } | null => { - const childEdges = edges.filter(edge => edge.source === humanInputNode.id) - - if (childEdges.length <= 1) - return null - - // Sort child edges: user actions first (by order), then __timeout last - const sortedChildEdges = [...childEdges].sort((edgeA, edgeB) => { +const sortHumanInputOutEdges = (humanInputNode: Node, outEdges: Edge[]): Edge[] => { + return [...outEdges].sort((edgeA, edgeB) => { const handleA = edgeA.sourceHandle const handleB = edgeB.sourceHandle if (handleA && handleB) { const userActions = (humanInputNode.data as HumanInputNodeType).user_actions || [] - const isATimeout = handleA === '__timeout' - const isBTimeout = handleB === '__timeout' - - // __timeout should always be last - if (isATimeout) + if (handleA === '__timeout') return 1 - if (isBTimeout) + if (handleB === '__timeout') return -1 - // Sort by user_actions order const indexA = userActions.findIndex(action => action.id === handleA) const indexB = userActions.findIndex(action => action.id === handleB) @@ -385,35 +318,6 @@ const buildHumanInputWithPorts = ( return 0 }) - - // Create ELK ports for each branch - const ports: ElkPortShape[] = sortedChildEdges.map((edge, index) => ({ - id: `${humanInputNode.id}-port-${edge.sourceHandle || index}`, - layoutOptions: { - 'port.side': 'EAST', - 'port.index': String(index), - }, - })) - - // Build port mapping: edge.id -> portId - const portMap = new Map() - sortedChildEdges.forEach((edge, index) => { - const portId = `${humanInputNode.id}-port-${edge.sourceHandle || index}` - portMap.set(edge.id, portId) - }) - - return { - node: { - id: humanInputNode.id, - width: humanInputNode.width ?? DEFAULT_NODE_WIDTH, - height: humanInputNode.height ?? DEFAULT_NODE_HEIGHT, - ports, - layoutOptions: { - 'elk.portConstraints': 'FIXED_ORDER', - }, - }, - portMap, - } } const normaliseBounds = (layout: LayoutResult): LayoutResult => { @@ -448,58 +352,87 @@ const normaliseBounds = (layout: LayoutResult): LayoutResult => { } } -export const getLayoutByDagre = async (originNodes: Node[], originEdges: Edge[]): Promise => { +export const getLayoutByELK = async (originNodes: Node[], originEdges: Edge[]): Promise => { edgeCounter = 0 const nodes = cloneDeep(originNodes).filter(node => !node.parentId && node.type === CUSTOM_NODE) const edges = cloneDeep(originEdges).filter(edge => (!edge.data?.isInIteration && !edge.data?.isInLoop)) - const elkNodes: ElkNodeShape[] = [] - const elkEdges: ElkEdgeShape[] = [] - - // Track which edges have been processed for If/Else nodes with ports - const edgeToPortMap = new Map() - - // Build nodes with ports for If/Else and Human Input nodes - nodes.forEach((node) => { - if (node.data.type === BlockEnum.IfElse) { - const portsResult = buildIfElseWithPorts(node, edges) - if (portsResult) { - // Use node with ports - elkNodes.push(portsResult.node) - // Store port mappings for edges - portsResult.portMap.forEach((portId, edgeId) => { - edgeToPortMap.set(edgeId, portId) - }) - } - else { - // No multiple branches, use normal node - elkNodes.push(toElkNode(node)) - } - } - else if (node.data.type === BlockEnum.HumanInput) { - const portsResult = buildHumanInputWithPorts(node, edges) - if (portsResult) { - // Use node with ports - elkNodes.push(portsResult.node) - // Store port mappings for edges - portsResult.portMap.forEach((portId, edgeId) => { - edgeToPortMap.set(edgeId, portId) - }) - } - else { - // No multiple branches, use normal node - elkNodes.push(toElkNode(node)) - } - } - else { - elkNodes.push(toElkNode(node)) - } + const outEdgesByNode = new Map() + const inEdgesByNode = new Map() + edges.forEach((edge) => { + if (!outEdgesByNode.has(edge.source)) + outEdgesByNode.set(edge.source, []) + outEdgesByNode.get(edge.source)!.push(edge) + if (!inEdgesByNode.has(edge.target)) + inEdgesByNode.set(edge.target, []) + inEdgesByNode.get(edge.target)!.push(edge) }) - // Build edges with port connections - edges.forEach((edge) => { - const sourcePort = edgeToPortMap.get(edge.id) - elkEdges.push(createEdge(edge.source, edge.target, sourcePort)) + const elkNodes: ElkNodeShape[] = [] + const elkEdges: ElkEdgeShape[] = [] + const sourcePortMap = new Map() + const targetPortMap = new Map() + const sortedOutEdgesByNode = new Map() + + nodes.forEach((node) => { + const inEdges = inEdgesByNode.get(node.id) || [] + let outEdges = outEdgesByNode.get(node.id) || [] + + if (node.data.type === BlockEnum.IfElse) + outEdges = sortIfElseOutEdges(node, outEdges) + else if (node.data.type === BlockEnum.HumanInput) + outEdges = sortHumanInputOutEdges(node, outEdges) + + sortedOutEdgesByNode.set(node.id, outEdges) + + const ports: ElkPortShape[] = [] + + inEdges.forEach((edge, index) => { + const portId = `${node.id}-in-${index}` + ports.push({ + id: portId, + layoutOptions: { + 'elk.port.side': 'WEST', + 'elk.port.index': String(index), + }, + }) + targetPortMap.set(edge.id, portId) + }) + + outEdges.forEach((edge, index) => { + const portId = `${node.id}-out-${edge.sourceHandle || index}` + ports.push({ + id: portId, + layoutOptions: { + 'elk.port.side': 'EAST', + 'elk.port.index': String(index), + }, + }) + sourcePortMap.set(edge.id, portId) + }) + + elkNodes.push({ + id: node.id, + width: node.width ?? DEFAULT_NODE_WIDTH, + height: node.height ?? DEFAULT_NODE_HEIGHT, + ...(ports.length > 0 && { + ports, + layoutOptions: { 'elk.portConstraints': 'FIXED_ORDER' }, + }), + }) + }) + + // Build edges in sorted per-node order so PREFER_EDGES aligns with port order + nodes.forEach((node) => { + const outEdges = sortedOutEdgesByNode.get(node.id) || [] + outEdges.forEach((edge) => { + elkEdges.push(createEdge( + edge.source, + edge.target, + sourcePortMap.get(edge.id), + targetPortMap.get(edge.id), + )) + }) }) const graph = { From 3c7180bfd5e4c17deb19728234db29a2a3e6e6a5 Mon Sep 17 00:00:00 2001 From: YBoy Date: Mon, 30 Mar 2026 17:56:30 +0300 Subject: [PATCH 08/40] test: migrate trigger providers controller tests to testcontainers (#34295) --- .../workspace/test_trigger_providers.py | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) rename api/tests/{unit_tests => test_containers_integration_tests}/controllers/console/workspace/test_trigger_providers.py (95%) diff --git a/api/tests/unit_tests/controllers/console/workspace/test_trigger_providers.py b/api/tests/test_containers_integration_tests/controllers/console/workspace/test_trigger_providers.py similarity index 95% rename from api/tests/unit_tests/controllers/console/workspace/test_trigger_providers.py rename to api/tests/test_containers_integration_tests/controllers/console/workspace/test_trigger_providers.py index 4776bc7af0..b4d12bff62 100644 --- a/api/tests/unit_tests/controllers/console/workspace/test_trigger_providers.py +++ b/api/tests/test_containers_integration_tests/controllers/console/workspace/test_trigger_providers.py @@ -1,3 +1,7 @@ +"""Testcontainers integration tests for controllers.console.workspace.trigger_providers endpoints.""" + +from __future__ import annotations + from unittest.mock import MagicMock, patch import pytest @@ -40,6 +44,10 @@ def mock_user(): class TestTriggerProviderApis: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_icon_success(self, app): api = TriggerProviderIconApi() method = unwrap(api.get) @@ -84,6 +92,10 @@ class TestTriggerProviderApis: class TestTriggerSubscriptionListApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_list_success(self, app): api = TriggerSubscriptionListApi() method = unwrap(api.get) @@ -115,6 +127,10 @@ class TestTriggerSubscriptionListApi: class TestTriggerSubscriptionBuilderApis: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_create_builder(self, app): api = TriggerSubscriptionBuilderCreateApi() method = unwrap(api.post) @@ -219,6 +235,10 @@ class TestTriggerSubscriptionBuilderApis: class TestTriggerSubscriptionCrud: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_update_rename_only(self, app): api = TriggerSubscriptionUpdateApi() method = unwrap(api.post) @@ -321,6 +341,10 @@ class TestTriggerSubscriptionCrud: class TestTriggerOAuthApis: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_oauth_authorize_success(self, app): api = TriggerOAuthAuthorizeApi() method = unwrap(api.get) @@ -455,6 +479,10 @@ class TestTriggerOAuthApis: class TestTriggerOAuthClientManageApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_get_client(self, app): api = TriggerOAuthClientManageApi() method = unwrap(api.get) @@ -527,6 +555,10 @@ class TestTriggerOAuthClientManageApi: class TestTriggerSubscriptionVerifyApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_verify_success(self, app): api = TriggerSubscriptionVerifyApi() method = unwrap(api.post) From a1513f06c31dc09c2a2c6d63162c6ae88fbc0796 Mon Sep 17 00:00:00 2001 From: doskoi <50610194+t-daisuke@users.noreply.github.com> Date: Mon, 30 Mar 2026 23:56:58 +0900 Subject: [PATCH 09/40] =?UTF-8?q?fix(i18n):=20translate=20"nodes.note.addN?= =?UTF-8?q?ote"=20as=20"=E3=83=A1=E3=83=A2=E3=82=92=E8=BF=BD=E5=8A=A0"=20i?= =?UTF-8?q?n=20ja-JP=20(#34294)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/i18n/ja-JP/workflow.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/i18n/ja-JP/workflow.json b/web/i18n/ja-JP/workflow.json index b9b60d6e73..acf43b8ce8 100644 --- a/web/i18n/ja-JP/workflow.json +++ b/web/i18n/ja-JP/workflow.json @@ -818,7 +818,7 @@ "nodes.loop.setLoopVariables": "ループスコープ内で変数を設定", "nodes.loop.totalLoopCount": "総ループ回数:{{count}}", "nodes.loop.variableName": "変数名", - "nodes.note.addNote": "コメントを追加", + "nodes.note.addNote": "メモを追加", "nodes.note.editor.bold": "太字", "nodes.note.editor.bulletList": "リスト", "nodes.note.editor.enterUrl": "リンク入力中...", From dede190be2721370404b9e81f2f5519f5c8ce126 Mon Sep 17 00:00:00 2001 From: YBoy Date: Mon, 30 Mar 2026 17:57:28 +0300 Subject: [PATCH 10/40] test: migrate data source controller tests to testcontainers (#34292) --- .../console/datasets/test_data_source.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) rename api/tests/{unit_tests => test_containers_integration_tests}/controllers/console/datasets/test_data_source.py (95%) diff --git a/api/tests/unit_tests/controllers/console/datasets/test_data_source.py b/api/tests/test_containers_integration_tests/controllers/console/datasets/test_data_source.py similarity index 95% rename from api/tests/unit_tests/controllers/console/datasets/test_data_source.py rename to api/tests/test_containers_integration_tests/controllers/console/datasets/test_data_source.py index d841f67f9b..1c07d4ca1c 100644 --- a/api/tests/unit_tests/controllers/console/datasets/test_data_source.py +++ b/api/tests/test_containers_integration_tests/controllers/console/datasets/test_data_source.py @@ -1,3 +1,7 @@ +"""Testcontainers integration tests for controllers.console.datasets.data_source endpoints.""" + +from __future__ import annotations + from unittest.mock import MagicMock, PropertyMock, patch import pytest @@ -46,6 +50,10 @@ def mock_engine(): class TestDataSourceApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_get_success(self, app, patch_tenant): api = DataSourceApi() method = unwrap(api.get) @@ -179,6 +187,10 @@ class TestDataSourceApi: class TestDataSourceNotionListApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_get_credential_not_found(self, app, patch_tenant): api = DataSourceNotionListApi() method = unwrap(api.get) @@ -310,6 +322,10 @@ class TestDataSourceNotionListApi: class TestDataSourceNotionApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_get_preview_success(self, app, patch_tenant): api = DataSourceNotionApi() method = unwrap(api.get) @@ -364,6 +380,10 @@ class TestDataSourceNotionApi: class TestDataSourceNotionDatasetSyncApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_get_success(self, app, patch_tenant): api = DataSourceNotionDatasetSyncApi() method = unwrap(api.get) @@ -403,6 +423,10 @@ class TestDataSourceNotionDatasetSyncApi: class TestDataSourceNotionDocumentSyncApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_get_success(self, app, patch_tenant): api = DataSourceNotionDocumentSyncApi() method = unwrap(api.get) From 623c8ae803c155283adfb4b65a43e710ccd36f9f Mon Sep 17 00:00:00 2001 From: YBoy Date: Mon, 30 Mar 2026 17:58:04 +0300 Subject: [PATCH 11/40] test: migrate app apis controller tests to testcontainers (#34291) --- .../controllers/console/app/test_app_apis.py | 87 ++++++------------- 1 file changed, 25 insertions(+), 62 deletions(-) rename api/tests/{unit_tests => test_containers_integration_tests}/controllers/console/app/test_app_apis.py (90%) diff --git a/api/tests/unit_tests/controllers/console/app/test_app_apis.py b/api/tests/test_containers_integration_tests/controllers/console/app/test_app_apis.py similarity index 90% rename from api/tests/unit_tests/controllers/console/app/test_app_apis.py rename to api/tests/test_containers_integration_tests/controllers/console/app/test_app_apis.py index 1d1e119fd6..fbaec069bb 100644 --- a/api/tests/unit_tests/controllers/console/app/test_app_apis.py +++ b/api/tests/test_containers_integration_tests/controllers/console/app/test_app_apis.py @@ -1,7 +1,4 @@ -""" -Additional tests to improve coverage for low-coverage modules in controllers/console/app. -Target: increase coverage for files with <75% coverage. -""" +"""Testcontainers integration tests for controllers/console/app endpoints.""" from __future__ import annotations @@ -70,26 +67,12 @@ def _unwrap(func): return func -class _ConnContext: - def __init__(self, rows): - self._rows = rows - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc, tb): - return False - - def execute(self, _query, _args): - return self._rows - - -# ========== Completion Tests ========== class TestCompletionEndpoints: - """Tests for completion API endpoints.""" + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers def test_completion_create_payload(self): - """Test completion creation payload.""" payload = CompletionMessagePayload(inputs={"prompt": "test"}, model_config={}) assert payload.inputs == {"prompt": "test"} @@ -209,7 +192,9 @@ class TestCompletionEndpoints: class TestAppEndpoints: - """Tests for app endpoints.""" + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers def test_app_put_should_preserve_icon_type_when_payload_omits_it(self, app, monkeypatch): api = app_module.AppApi() @@ -250,12 +235,12 @@ class TestAppEndpoints: ) -# ========== OpsTrace Tests ========== class TestOpsTraceEndpoints: - """Tests for ops_trace endpoint.""" + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers def test_ops_trace_query_basic(self): - """Test ops_trace query.""" query = TraceProviderQuery(tracing_provider="langfuse") assert query.tracing_provider == "langfuse" @@ -310,12 +295,12 @@ class TestOpsTraceEndpoints: method(app_id="app-1") -# ========== Site Tests ========== class TestSiteEndpoints: - """Tests for site endpoint.""" + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers def test_site_response_structure(self): - """Test site response structure.""" payload = AppSiteUpdatePayload(title="My Site", description="Test site") assert payload.title == "My Site" @@ -369,27 +354,22 @@ class TestSiteEndpoints: assert result is site -# ========== Workflow Tests ========== class TestWorkflowEndpoints: - """Tests for workflow endpoints.""" - def test_workflow_copy_payload(self): - """Test workflow copy payload.""" payload = SyncDraftWorkflowPayload(graph={}, features={}) assert payload.graph == {} def test_workflow_mode_query(self): - """Test workflow mode query.""" payload = AdvancedChatWorkflowRunPayload(inputs={}, query="hi") assert payload.query == "hi" -# ========== Workflow App Log Tests ========== class TestWorkflowAppLogEndpoints: - """Tests for workflow app log endpoints.""" + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers def test_workflow_app_log_query(self): - """Test workflow app log query.""" query = WorkflowAppLogQuery(keyword="test", page=1, limit=20) assert query.keyword == "test" @@ -427,12 +407,12 @@ class TestWorkflowAppLogEndpoints: assert result == {"items": [], "total": 0} -# ========== Workflow Draft Variable Tests ========== class TestWorkflowDraftVariableEndpoints: - """Tests for workflow draft variable endpoints.""" + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers def test_workflow_variable_creation(self): - """Test workflow variable creation.""" payload = WorkflowDraftVariableUpdatePayload(name="var1", value="test") assert payload.name == "var1" @@ -472,12 +452,12 @@ class TestWorkflowDraftVariableEndpoints: assert result == {"items": [], "total": 0} -# ========== Workflow Statistic Tests ========== class TestWorkflowStatisticEndpoints: - """Tests for workflow statistic endpoints.""" + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers def test_workflow_statistic_time_range(self): - """Test workflow statistic time range query.""" query = WorkflowStatisticQuery(start="2024-01-01", end="2024-12-31") assert query.start == "2024-01-01" @@ -541,12 +521,12 @@ class TestWorkflowStatisticEndpoints: assert response.get_json() == {"data": [{"date": "2024-01-02"}]} -# ========== Workflow Trigger Tests ========== class TestWorkflowTriggerEndpoints: - """Tests for workflow trigger endpoints.""" + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers def test_webhook_trigger_payload(self): - """Test webhook trigger payload.""" payload = Parser(node_id="node-1") assert payload.node_id == "node-1" @@ -578,22 +558,13 @@ class TestWorkflowTriggerEndpoints: assert result is trigger -# ========== Wraps Tests ========== class TestWrapsEndpoints: - """Tests for wraps utility functions.""" - def test_get_app_model_context(self): - """Test get_app_model wrapper context.""" - # These are decorator functions, so we test their availability assert hasattr(wraps_module, "get_app_model") -# ========== MCP Server Tests ========== class TestMCPServerEndpoints: - """Tests for MCP server endpoints.""" - def test_mcp_server_connection(self): - """Test MCP server connection.""" payload = MCPServerCreatePayload(parameters={"url": "http://localhost:3000"}) assert payload.parameters["url"] == "http://localhost:3000" @@ -602,22 +573,14 @@ class TestMCPServerEndpoints: assert payload.status == "active" -# ========== Error Handling Tests ========== class TestErrorHandling: - """Tests for error handling in various endpoints.""" - def test_annotation_list_query_validation(self): - """Test annotation list query validation.""" with pytest.raises(ValueError): annotation_module.AnnotationListQuery(page=0) -# ========== Integration-like Tests ========== class TestPayloadIntegration: - """Integration tests for payload handling.""" - def test_multiple_payload_types(self): - """Test handling of multiple payload types.""" payloads = [ annotation_module.AnnotationReplyPayload( score_threshold=0.5, embedding_provider_name="openai", embedding_model_name="text-embedding-3-small" From cc89b57c1f53361778af356be77334ccdbb38eb6 Mon Sep 17 00:00:00 2001 From: YBoy Date: Mon, 30 Mar 2026 18:01:50 +0300 Subject: [PATCH 12/40] test: migrate web forgot password controller tests to testcontainers (#34288) --- .../web/test_web_forgot_password.py | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) rename api/tests/{unit_tests => test_containers_integration_tests}/controllers/web/test_web_forgot_password.py (95%) diff --git a/api/tests/unit_tests/controllers/web/test_web_forgot_password.py b/api/tests/test_containers_integration_tests/controllers/web/test_web_forgot_password.py similarity index 95% rename from api/tests/unit_tests/controllers/web/test_web_forgot_password.py rename to api/tests/test_containers_integration_tests/controllers/web/test_web_forgot_password.py index 3d7c319947..19057726c3 100644 --- a/api/tests/unit_tests/controllers/web/test_web_forgot_password.py +++ b/api/tests/test_containers_integration_tests/controllers/web/test_web_forgot_password.py @@ -1,9 +1,12 @@ +"""Testcontainers integration tests for controllers.web.forgot_password endpoints.""" + +from __future__ import annotations + import base64 from types import SimpleNamespace from unittest.mock import MagicMock, patch import pytest -from flask import Flask from controllers.web.forgot_password import ( ForgotPasswordCheckApi, @@ -12,13 +15,6 @@ from controllers.web.forgot_password import ( ) -@pytest.fixture -def app(): - flask_app = Flask(__name__) - flask_app.config["TESTING"] = True - return flask_app - - @pytest.fixture(autouse=True) def _patch_wraps(): wraps_features = SimpleNamespace(enable_email_password_login=True) @@ -33,6 +29,10 @@ def _patch_wraps(): class TestForgotPasswordSendEmailApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + @patch("controllers.web.forgot_password.AccountService.send_reset_password_email") @patch("controllers.web.forgot_password.AccountService.get_account_by_email_with_case_fallback") @patch("controllers.web.forgot_password.AccountService.is_email_send_ip_limit", return_value=False) @@ -69,6 +69,10 @@ class TestForgotPasswordSendEmailApi: class TestForgotPasswordCheckApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + @patch("controllers.web.forgot_password.AccountService.reset_forgot_password_error_rate_limit") @patch("controllers.web.forgot_password.AccountService.generate_reset_password_token") @patch("controllers.web.forgot_password.AccountService.revoke_reset_password_token") @@ -143,6 +147,10 @@ class TestForgotPasswordCheckApi: class TestForgotPasswordResetApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + @patch("controllers.web.forgot_password.ForgotPasswordResetApi._update_existing_account") @patch("controllers.web.forgot_password.AccountService.get_account_by_email_with_case_fallback") @patch("controllers.web.forgot_password.Session") From bc14ad6a8f6476f205dabd5f382051b7bd410152 Mon Sep 17 00:00:00 2001 From: lif <1835304752@qq.com> Date: Mon, 30 Mar 2026 23:05:57 +0800 Subject: [PATCH 13/40] fix: map checkbox and json_object types in MCP schema publishing (#34226) Signed-off-by: majiayu000 <1835304752@qq.com> Co-authored-by: Asuka Minato --- api/controllers/mcp/mcp.py | 1 + api/core/mcp/server/streamable_http.py | 8 ++ .../core/mcp/server/test_streamable_http.py | 80 +++++++++++++++++-- 3 files changed, 82 insertions(+), 7 deletions(-) diff --git a/api/controllers/mcp/mcp.py b/api/controllers/mcp/mcp.py index 3d00f77e79..58ec76243b 100644 --- a/api/controllers/mcp/mcp.py +++ b/api/controllers/mcp/mcp.py @@ -174,6 +174,7 @@ class MCPAppApi(Resource): required=variable.get("required", False), max_length=variable.get("max_length"), options=variable.get("options") or [], + json_schema=variable.get("json_schema"), ) def _parse_mcp_request(self, args: dict) -> mcp_types.ClientRequest | mcp_types.ClientNotification: diff --git a/api/core/mcp/server/streamable_http.py b/api/core/mcp/server/streamable_http.py index 27000c947c..278add8cc9 100644 --- a/api/core/mcp/server/streamable_http.py +++ b/api/core/mcp/server/streamable_http.py @@ -260,4 +260,12 @@ def convert_input_form_to_parameters( parameters[item.variable]["enum"] = item.options elif item.type == VariableEntityType.NUMBER: parameters[item.variable]["type"] = "number" + elif item.type == VariableEntityType.CHECKBOX: + parameters[item.variable]["type"] = "boolean" + elif item.type == VariableEntityType.JSON_OBJECT: + parameters[item.variable]["type"] = "object" + if item.json_schema: + for key in ("properties", "required", "additionalProperties"): + if key in item.json_schema: + parameters[item.variable][key] = item.json_schema[key] return parameters, required diff --git a/api/tests/unit_tests/core/mcp/server/test_streamable_http.py b/api/tests/unit_tests/core/mcp/server/test_streamable_http.py index 313d18c695..9a815fb94d 100644 --- a/api/tests/unit_tests/core/mcp/server/test_streamable_http.py +++ b/api/tests/unit_tests/core/mcp/server/test_streamable_http.py @@ -415,12 +415,44 @@ class TestUtilityFunctions: label="Upload", required=False, ), + VariableEntity( + type=VariableEntityType.CHECKBOX, + variable="enabled", + description="Enable flag", + label="Enabled", + required=False, + ), + VariableEntity( + type=VariableEntityType.JSON_OBJECT, + variable="config", + description="Config object", + label="Config", + required=True, + ), + VariableEntity( + type=VariableEntityType.JSON_OBJECT, + variable="schema_config", + description="Config with schema", + label="Schema Config", + required=False, + json_schema={ + "properties": { + "host": {"type": "string"}, + "port": {"type": "number"}, + }, + "required": ["host"], + "additionalProperties": False, + }, + ), ] parameters_dict: dict[str, str] = { "name": "Enter your name", "category": "Select category", "count": "Enter count", + "enabled": "Enable flag", + "config": "Config object", + "schema_config": "Config with schema", } parameters, required = convert_input_form_to_parameters(user_input_form, parameters_dict) @@ -437,20 +469,35 @@ class TestUtilityFunctions: assert "count" in parameters assert parameters["count"]["type"] == "number" - # FILE type should be skipped - it creates empty dict but gets filtered later - # Check that it doesn't have any meaningful content - if "upload" in parameters: - assert parameters["upload"] == {} + # FILE type is skipped entirely via `continue` — key should not exist + assert "upload" not in parameters + + # CHECKBOX maps to boolean + assert parameters["enabled"]["type"] == "boolean" + + # JSON_OBJECT without json_schema maps to object + assert parameters["config"]["type"] == "object" + assert "properties" not in parameters["config"] + + # JSON_OBJECT with json_schema forwards schema keys + assert parameters["schema_config"]["type"] == "object" + assert parameters["schema_config"]["properties"] == { + "host": {"type": "string"}, + "port": {"type": "number"}, + } + assert parameters["schema_config"]["required"] == ["host"] + assert parameters["schema_config"]["additionalProperties"] is False # Check required fields assert "name" in required assert "count" in required + assert "config" in required assert "category" not in required # Note: _get_request_id function has been removed as request_id is now passed as parameter def test_convert_input_form_to_parameters_jsonschema_validation_ok(self): - """Current schema uses 'number' for numeric fields; it should be a valid JSON Schema.""" + """Generated schema with all supported types should be valid JSON Schema.""" user_input_form = [ VariableEntity( type=VariableEntityType.NUMBER, @@ -466,11 +513,27 @@ class TestUtilityFunctions: label="Name", required=False, ), + VariableEntity( + type=VariableEntityType.CHECKBOX, + variable="enabled", + description="Toggle", + label="Enabled", + required=False, + ), + VariableEntity( + type=VariableEntityType.JSON_OBJECT, + variable="metadata", + description="Metadata", + label="Metadata", + required=False, + ), ] parameters_dict = { "count": "Enter count", "name": "Enter your name", + "enabled": "Toggle flag", + "metadata": "Metadata object", } parameters, required = convert_input_form_to_parameters(user_input_form, parameters_dict) @@ -485,9 +548,12 @@ class TestUtilityFunctions: # 1) The schema itself must be valid jsonschema.Draft202012Validator.check_schema(schema) - # 2) Both float and integer instances should pass validation + # 2) Validate instances with all types jsonschema.validate(instance={"count": 3.14, "name": "alice"}, schema=schema) - jsonschema.validate(instance={"count": 2, "name": "bob"}, schema=schema) + jsonschema.validate( + instance={"count": 2, "enabled": True, "metadata": {"key": "val"}}, + schema=schema, + ) def test_legacy_float_type_schema_is_invalid(self): """Legacy/buggy behavior: using 'float' should produce an invalid JSON Schema.""" From 953bcc33b1f4691833932614399123e06d363310 Mon Sep 17 00:00:00 2001 From: YBoy Date: Mon, 30 Mar 2026 19:18:21 +0300 Subject: [PATCH 14/40] test: migrate workspace wraps controller tests to testcontainers (#34296) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- .../console/workspace/test_workspace_wraps.py | 185 ++++++++++++++++++ .../console/workspace/test_workspace_wraps.py | 142 -------------- 2 files changed, 185 insertions(+), 142 deletions(-) create mode 100644 api/tests/test_containers_integration_tests/controllers/console/workspace/test_workspace_wraps.py delete mode 100644 api/tests/unit_tests/controllers/console/workspace/test_workspace_wraps.py diff --git a/api/tests/test_containers_integration_tests/controllers/console/workspace/test_workspace_wraps.py b/api/tests/test_containers_integration_tests/controllers/console/workspace/test_workspace_wraps.py new file mode 100644 index 0000000000..99cabb6cea --- /dev/null +++ b/api/tests/test_containers_integration_tests/controllers/console/workspace/test_workspace_wraps.py @@ -0,0 +1,185 @@ +"""Testcontainers integration tests for plugin_permission_required decorator.""" + +from __future__ import annotations + +from types import SimpleNamespace +from unittest.mock import patch + +import pytest +from sqlalchemy.orm import Session +from werkzeug.exceptions import Forbidden + +from controllers.console.workspace import plugin_permission_required +from models.account import Tenant, TenantPluginPermission, TenantStatus + + +def _create_tenant(db_session: Session) -> Tenant: + tenant = Tenant(name="test-tenant", status=TenantStatus.NORMAL, plan="basic") + db_session.add(tenant) + db_session.commit() + db_session.expire_all() + return tenant + + +def _create_permission( + db_session: Session, + tenant_id: str, + install: TenantPluginPermission.InstallPermission = TenantPluginPermission.InstallPermission.EVERYONE, + debug: TenantPluginPermission.DebugPermission = TenantPluginPermission.DebugPermission.EVERYONE, +) -> TenantPluginPermission: + perm = TenantPluginPermission( + tenant_id=tenant_id, + install_permission=install, + debug_permission=debug, + ) + db_session.add(perm) + db_session.commit() + db_session.expire_all() + return perm + + +class TestPluginPermissionRequired: + def test_allows_without_permission(self, db_session_with_containers: Session): + tenant = _create_tenant(db_session_with_containers) + user = SimpleNamespace(is_admin_or_owner=False) + + with patch( + "controllers.console.workspace.current_account_with_tenant", + return_value=(user, tenant.id), + ): + + @plugin_permission_required() + def handler(): + return "ok" + + assert handler() == "ok" + + def test_install_nobody_forbidden(self, db_session_with_containers: Session): + tenant = _create_tenant(db_session_with_containers) + _create_permission( + db_session_with_containers, + tenant.id, + install=TenantPluginPermission.InstallPermission.NOBODY, + debug=TenantPluginPermission.DebugPermission.EVERYONE, + ) + user = SimpleNamespace(is_admin_or_owner=True) + + with patch( + "controllers.console.workspace.current_account_with_tenant", + return_value=(user, tenant.id), + ): + + @plugin_permission_required(install_required=True) + def handler(): + return "ok" + + with pytest.raises(Forbidden): + handler() + + def test_install_admin_requires_admin(self, db_session_with_containers: Session): + tenant = _create_tenant(db_session_with_containers) + _create_permission( + db_session_with_containers, + tenant.id, + install=TenantPluginPermission.InstallPermission.ADMINS, + debug=TenantPluginPermission.DebugPermission.EVERYONE, + ) + user = SimpleNamespace(is_admin_or_owner=False) + + with patch( + "controllers.console.workspace.current_account_with_tenant", + return_value=(user, tenant.id), + ): + + @plugin_permission_required(install_required=True) + def handler(): + return "ok" + + with pytest.raises(Forbidden): + handler() + + def test_install_admin_allows_admin(self, db_session_with_containers: Session): + tenant = _create_tenant(db_session_with_containers) + _create_permission( + db_session_with_containers, + tenant.id, + install=TenantPluginPermission.InstallPermission.ADMINS, + debug=TenantPluginPermission.DebugPermission.EVERYONE, + ) + user = SimpleNamespace(is_admin_or_owner=True) + + with patch( + "controllers.console.workspace.current_account_with_tenant", + return_value=(user, tenant.id), + ): + + @plugin_permission_required(install_required=True) + def handler(): + return "ok" + + assert handler() == "ok" + + def test_debug_nobody_forbidden(self, db_session_with_containers: Session): + tenant = _create_tenant(db_session_with_containers) + _create_permission( + db_session_with_containers, + tenant.id, + install=TenantPluginPermission.InstallPermission.EVERYONE, + debug=TenantPluginPermission.DebugPermission.NOBODY, + ) + user = SimpleNamespace(is_admin_or_owner=True) + + with patch( + "controllers.console.workspace.current_account_with_tenant", + return_value=(user, tenant.id), + ): + + @plugin_permission_required(debug_required=True) + def handler(): + return "ok" + + with pytest.raises(Forbidden): + handler() + + def test_debug_admin_requires_admin(self, db_session_with_containers: Session): + tenant = _create_tenant(db_session_with_containers) + _create_permission( + db_session_with_containers, + tenant.id, + install=TenantPluginPermission.InstallPermission.EVERYONE, + debug=TenantPluginPermission.DebugPermission.ADMINS, + ) + user = SimpleNamespace(is_admin_or_owner=False) + + with patch( + "controllers.console.workspace.current_account_with_tenant", + return_value=(user, tenant.id), + ): + + @plugin_permission_required(debug_required=True) + def handler(): + return "ok" + + with pytest.raises(Forbidden): + handler() + + def test_debug_admin_allows_admin(self, db_session_with_containers: Session): + tenant = _create_tenant(db_session_with_containers) + _create_permission( + db_session_with_containers, + tenant.id, + install=TenantPluginPermission.InstallPermission.EVERYONE, + debug=TenantPluginPermission.DebugPermission.ADMINS, + ) + user = SimpleNamespace(is_admin_or_owner=True) + + with patch( + "controllers.console.workspace.current_account_with_tenant", + return_value=(user, tenant.id), + ): + + @plugin_permission_required(debug_required=True) + def handler(): + return "ok" + + assert handler() == "ok" diff --git a/api/tests/unit_tests/controllers/console/workspace/test_workspace_wraps.py b/api/tests/unit_tests/controllers/console/workspace/test_workspace_wraps.py deleted file mode 100644 index b290748155..0000000000 --- a/api/tests/unit_tests/controllers/console/workspace/test_workspace_wraps.py +++ /dev/null @@ -1,142 +0,0 @@ -from __future__ import annotations - -import importlib -from types import SimpleNamespace - -import pytest -from werkzeug.exceptions import Forbidden - -from controllers.console.workspace import plugin_permission_required -from models.account import TenantPluginPermission - - -class _SessionStub: - def __init__(self, permission): - self._permission = permission - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc, tb): - return False - - def query(self, *_args, **_kwargs): - return self - - def where(self, *_args, **_kwargs): - return self - - def first(self): - return self._permission - - -def _workspace_module(): - return importlib.import_module(plugin_permission_required.__module__) - - -def _patch_session(monkeypatch: pytest.MonkeyPatch, permission): - module = _workspace_module() - monkeypatch.setattr(module, "Session", lambda *_args, **_kwargs: _SessionStub(permission)) - monkeypatch.setattr(module, "db", SimpleNamespace(engine=object())) - - -def test_plugin_permission_allows_without_permission(monkeypatch: pytest.MonkeyPatch) -> None: - user = SimpleNamespace(is_admin_or_owner=False) - module = _workspace_module() - monkeypatch.setattr(module, "current_account_with_tenant", lambda: (user, "t1")) - _patch_session(monkeypatch, None) - - @plugin_permission_required() - def handler(): - return "ok" - - assert handler() == "ok" - - -def test_plugin_permission_install_nobody_forbidden(monkeypatch: pytest.MonkeyPatch) -> None: - user = SimpleNamespace(is_admin_or_owner=True) - permission = SimpleNamespace( - install_permission=TenantPluginPermission.InstallPermission.NOBODY, - debug_permission=TenantPluginPermission.DebugPermission.EVERYONE, - ) - module = _workspace_module() - monkeypatch.setattr(module, "current_account_with_tenant", lambda: (user, "t1")) - _patch_session(monkeypatch, permission) - - @plugin_permission_required(install_required=True) - def handler(): - return "ok" - - with pytest.raises(Forbidden): - handler() - - -def test_plugin_permission_install_admin_requires_admin(monkeypatch: pytest.MonkeyPatch) -> None: - user = SimpleNamespace(is_admin_or_owner=False) - permission = SimpleNamespace( - install_permission=TenantPluginPermission.InstallPermission.ADMINS, - debug_permission=TenantPluginPermission.DebugPermission.EVERYONE, - ) - module = _workspace_module() - monkeypatch.setattr(module, "current_account_with_tenant", lambda: (user, "t1")) - _patch_session(monkeypatch, permission) - - @plugin_permission_required(install_required=True) - def handler(): - return "ok" - - with pytest.raises(Forbidden): - handler() - - -def test_plugin_permission_install_admin_allows_admin(monkeypatch: pytest.MonkeyPatch) -> None: - user = SimpleNamespace(is_admin_or_owner=True) - permission = SimpleNamespace( - install_permission=TenantPluginPermission.InstallPermission.ADMINS, - debug_permission=TenantPluginPermission.DebugPermission.EVERYONE, - ) - module = _workspace_module() - monkeypatch.setattr(module, "current_account_with_tenant", lambda: (user, "t1")) - _patch_session(monkeypatch, permission) - - @plugin_permission_required(install_required=True) - def handler(): - return "ok" - - assert handler() == "ok" - - -def test_plugin_permission_debug_nobody_forbidden(monkeypatch: pytest.MonkeyPatch) -> None: - user = SimpleNamespace(is_admin_or_owner=True) - permission = SimpleNamespace( - install_permission=TenantPluginPermission.InstallPermission.EVERYONE, - debug_permission=TenantPluginPermission.DebugPermission.NOBODY, - ) - module = _workspace_module() - monkeypatch.setattr(module, "current_account_with_tenant", lambda: (user, "t1")) - _patch_session(monkeypatch, permission) - - @plugin_permission_required(debug_required=True) - def handler(): - return "ok" - - with pytest.raises(Forbidden): - handler() - - -def test_plugin_permission_debug_admin_requires_admin(monkeypatch: pytest.MonkeyPatch) -> None: - user = SimpleNamespace(is_admin_or_owner=False) - permission = SimpleNamespace( - install_permission=TenantPluginPermission.InstallPermission.EVERYONE, - debug_permission=TenantPluginPermission.DebugPermission.ADMINS, - ) - module = _workspace_module() - monkeypatch.setattr(module, "current_account_with_tenant", lambda: (user, "t1")) - _patch_session(monkeypatch, permission) - - @plugin_permission_required(debug_required=True) - def handler(): - return "ok" - - with pytest.raises(Forbidden): - handler() From 5fc4dfaf7ba182149079c1fa91a87056687ee33e Mon Sep 17 00:00:00 2001 From: YBoy Date: Mon, 30 Mar 2026 19:19:15 +0300 Subject: [PATCH 15/40] test: migrate web wraps controller tests to testcontainers (#34289) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- .../controllers/web/test_wraps.py | 215 ++++++++---------- 1 file changed, 95 insertions(+), 120 deletions(-) rename api/tests/{unit_tests => test_containers_integration_tests}/controllers/web/test_wraps.py (67%) diff --git a/api/tests/unit_tests/controllers/web/test_wraps.py b/api/tests/test_containers_integration_tests/controllers/web/test_wraps.py similarity index 67% rename from api/tests/unit_tests/controllers/web/test_wraps.py rename to api/tests/test_containers_integration_tests/controllers/web/test_wraps.py index 85049ae975..19833cc772 100644 --- a/api/tests/unit_tests/controllers/web/test_wraps.py +++ b/api/tests/test_containers_integration_tests/controllers/web/test_wraps.py @@ -1,13 +1,14 @@ -"""Unit tests for controllers.web.wraps — JWT auth decorator and validation helpers.""" +"""Testcontainers integration tests for controllers.web.wraps — JWT auth decorator and validation helpers.""" from __future__ import annotations from datetime import UTC, datetime, timedelta from types import SimpleNamespace from unittest.mock import MagicMock, patch +from uuid import uuid4 import pytest -from flask import Flask +from sqlalchemy.orm import Session from werkzeug.exceptions import BadRequest, NotFound, Unauthorized from controllers.web.error import WebAppAuthAccessDeniedError, WebAppAuthRequiredError @@ -18,12 +19,8 @@ from controllers.web.wraps import ( ) -# --------------------------------------------------------------------------- -# _validate_webapp_token -# --------------------------------------------------------------------------- class TestValidateWebappToken: def test_enterprise_enabled_and_app_auth_requires_webapp_source(self) -> None: - """When both flags are true, a non-webapp source must raise.""" decoded = {"token_source": "other"} with pytest.raises(WebAppAuthRequiredError): _validate_webapp_token(decoded, app_web_auth_enabled=True, system_webapp_auth_enabled=True) @@ -38,7 +35,6 @@ class TestValidateWebappToken: _validate_webapp_token(decoded, app_web_auth_enabled=True, system_webapp_auth_enabled=True) def test_public_app_rejects_webapp_source(self) -> None: - """When auth is not required, a webapp-sourced token must be rejected.""" decoded = {"token_source": "webapp"} with pytest.raises(Unauthorized): _validate_webapp_token(decoded, app_web_auth_enabled=False, system_webapp_auth_enabled=False) @@ -52,18 +48,13 @@ class TestValidateWebappToken: _validate_webapp_token(decoded, app_web_auth_enabled=False, system_webapp_auth_enabled=False) def test_system_enabled_but_app_public(self) -> None: - """system_webapp_auth_enabled=True but app is public — webapp source rejected.""" decoded = {"token_source": "webapp"} with pytest.raises(Unauthorized): _validate_webapp_token(decoded, app_web_auth_enabled=False, system_webapp_auth_enabled=True) -# --------------------------------------------------------------------------- -# _validate_user_accessibility -# --------------------------------------------------------------------------- class TestValidateUserAccessibility: def test_skips_when_auth_disabled(self) -> None: - """No checks when system or app auth is disabled.""" _validate_user_accessibility( decoded={}, app_code="code", @@ -123,7 +114,6 @@ class TestValidateUserAccessibility: def test_external_auth_type_checks_sso_update_time( self, mock_perm_check: MagicMock, mock_sso_time: MagicMock ) -> None: - # granted_at is before SSO update time → denied mock_sso_time.return_value = datetime.now(UTC) old_granted = int((datetime.now(UTC) - timedelta(hours=1)).timestamp()) decoded = {"user_id": "u1", "auth_type": "external", "granted_at": old_granted} @@ -164,7 +154,6 @@ class TestValidateUserAccessibility: recent_granted = int(datetime.now(UTC).timestamp()) decoded = {"user_id": "u1", "auth_type": "external", "granted_at": recent_granted} settings = SimpleNamespace(access_mode="public") - # Should not raise _validate_user_accessibility( decoded=decoded, app_code="code", @@ -191,10 +180,49 @@ class TestValidateUserAccessibility: ) -# --------------------------------------------------------------------------- -# decode_jwt_token -# --------------------------------------------------------------------------- class TestDecodeJwtToken: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + + def _create_app_site_enduser(self, db_session: Session, *, enable_site: bool = True): + from models.model import App, AppMode, CustomizeTokenStrategy, EndUser, Site + + tenant_id = str(uuid4()) + app_model = App( + tenant_id=tenant_id, + mode=AppMode.CHAT.value, + name="test-app", + enable_site=enable_site, + enable_api=True, + ) + db_session.add(app_model) + db_session.commit() + db_session.expire_all() + + site = Site( + app_id=app_model.id, + title="test-site", + default_language="en-US", + customize_token_strategy=CustomizeTokenStrategy.NOT_ALLOW, + code="code1", + ) + db_session.add(site) + db_session.commit() + db_session.expire_all() + + end_user = EndUser( + tenant_id=tenant_id, + app_id=app_model.id, + type="browser", + session_id="sess-1", + ) + db_session.add(end_user) + db_session.commit() + db_session.expire_all() + + return app_model, site, end_user + @patch("controllers.web.wraps._validate_user_accessibility") @patch("controllers.web.wraps._validate_webapp_token") @patch("controllers.web.wraps.EnterpriseService.WebAppAuth.get_app_access_mode_by_id") @@ -202,10 +230,8 @@ class TestDecodeJwtToken: @patch("controllers.web.wraps.FeatureService.get_system_features") @patch("controllers.web.wraps.PassportService") @patch("controllers.web.wraps.extract_webapp_passport") - @patch("controllers.web.wraps.db") def test_happy_path( self, - mock_db: MagicMock, mock_extract: MagicMock, mock_passport_cls: MagicMock, mock_features: MagicMock, @@ -213,40 +239,28 @@ class TestDecodeJwtToken: mock_access_mode: MagicMock, mock_validate_token: MagicMock, mock_validate_user: MagicMock, - app: Flask, + app, + db_session_with_containers: Session, ) -> None: + app_model, site, end_user = self._create_app_site_enduser(db_session_with_containers) + mock_extract.return_value = "jwt-token" mock_passport_cls.return_value.verify.return_value = { - "app_code": "code1", - "app_id": "app-1", - "end_user_id": "eu-1", + "app_code": site.code, + "app_id": app_model.id, + "end_user_id": end_user.id, } mock_features.return_value = SimpleNamespace(webapp_auth=SimpleNamespace(enabled=False)) - app_model = SimpleNamespace(id="app-1", enable_site=True) - site = SimpleNamespace(code="code1") - end_user = SimpleNamespace(id="eu-1", session_id="sess-1") + with app.test_request_context("/", headers={"X-App-Code": site.code}): + result_app, result_user = decode_jwt_token() - # Configure session mock to return correct objects via scalar() - session_mock = MagicMock() - session_mock.scalar.side_effect = [app_model, site, end_user] - session_ctx = MagicMock() - session_ctx.__enter__ = MagicMock(return_value=session_mock) - session_ctx.__exit__ = MagicMock(return_value=False) - mock_db.engine = "engine" - - with patch("controllers.web.wraps.Session", return_value=session_ctx): - with app.test_request_context("/", headers={"X-App-Code": "code1"}): - result_app, result_user = decode_jwt_token() - - assert result_app.id == "app-1" - assert result_user.id == "eu-1" + assert result_app.id == app_model.id + assert result_user.id == end_user.id @patch("controllers.web.wraps.FeatureService.get_system_features") @patch("controllers.web.wraps.extract_webapp_passport") - def test_missing_token_raises_unauthorized( - self, mock_extract: MagicMock, mock_features: MagicMock, app: Flask - ) -> None: + def test_missing_token_raises_unauthorized(self, mock_extract: MagicMock, mock_features: MagicMock, app) -> None: mock_features.return_value = SimpleNamespace(webapp_auth=SimpleNamespace(enabled=False)) mock_extract.return_value = None @@ -257,137 +271,98 @@ class TestDecodeJwtToken: @patch("controllers.web.wraps.FeatureService.get_system_features") @patch("controllers.web.wraps.PassportService") @patch("controllers.web.wraps.extract_webapp_passport") - @patch("controllers.web.wraps.db") def test_missing_app_raises_not_found( self, - mock_db: MagicMock, mock_extract: MagicMock, mock_passport_cls: MagicMock, mock_features: MagicMock, - app: Flask, + app, ) -> None: + non_existent_id = str(uuid4()) mock_extract.return_value = "jwt-token" mock_passport_cls.return_value.verify.return_value = { "app_code": "code1", - "app_id": "app-1", - "end_user_id": "eu-1", + "app_id": non_existent_id, + "end_user_id": str(uuid4()), } mock_features.return_value = SimpleNamespace(webapp_auth=SimpleNamespace(enabled=False)) - session_mock = MagicMock() - session_mock.scalar.return_value = None # No app found - session_ctx = MagicMock() - session_ctx.__enter__ = MagicMock(return_value=session_mock) - session_ctx.__exit__ = MagicMock(return_value=False) - mock_db.engine = "engine" - - with patch("controllers.web.wraps.Session", return_value=session_ctx): - with app.test_request_context("/", headers={"X-App-Code": "code1"}): - with pytest.raises(NotFound): - decode_jwt_token() + with app.test_request_context("/", headers={"X-App-Code": "code1"}): + with pytest.raises(NotFound): + decode_jwt_token() @patch("controllers.web.wraps.FeatureService.get_system_features") @patch("controllers.web.wraps.PassportService") @patch("controllers.web.wraps.extract_webapp_passport") - @patch("controllers.web.wraps.db") def test_disabled_site_raises_bad_request( self, - mock_db: MagicMock, mock_extract: MagicMock, mock_passport_cls: MagicMock, mock_features: MagicMock, - app: Flask, + app, + db_session_with_containers: Session, ) -> None: + app_model, site, end_user = self._create_app_site_enduser(db_session_with_containers, enable_site=False) + mock_extract.return_value = "jwt-token" mock_passport_cls.return_value.verify.return_value = { - "app_code": "code1", - "app_id": "app-1", - "end_user_id": "eu-1", + "app_code": site.code, + "app_id": app_model.id, + "end_user_id": end_user.id, } mock_features.return_value = SimpleNamespace(webapp_auth=SimpleNamespace(enabled=False)) - app_model = SimpleNamespace(id="app-1", enable_site=False) - - session_mock = MagicMock() - # scalar calls: app_model, site (code found), then end_user - session_mock.scalar.side_effect = [app_model, SimpleNamespace(code="code1"), None] - session_ctx = MagicMock() - session_ctx.__enter__ = MagicMock(return_value=session_mock) - session_ctx.__exit__ = MagicMock(return_value=False) - mock_db.engine = "engine" - - with patch("controllers.web.wraps.Session", return_value=session_ctx): - with app.test_request_context("/", headers={"X-App-Code": "code1"}): - with pytest.raises(BadRequest, match="Site is disabled"): - decode_jwt_token() + with app.test_request_context("/", headers={"X-App-Code": site.code}): + with pytest.raises(BadRequest, match="Site is disabled"): + decode_jwt_token() @patch("controllers.web.wraps.FeatureService.get_system_features") @patch("controllers.web.wraps.PassportService") @patch("controllers.web.wraps.extract_webapp_passport") - @patch("controllers.web.wraps.db") def test_missing_end_user_raises_not_found( self, - mock_db: MagicMock, mock_extract: MagicMock, mock_passport_cls: MagicMock, mock_features: MagicMock, - app: Flask, + app, + db_session_with_containers: Session, ) -> None: + app_model, site, _ = self._create_app_site_enduser(db_session_with_containers) + non_existent_eu = str(uuid4()) + mock_extract.return_value = "jwt-token" mock_passport_cls.return_value.verify.return_value = { - "app_code": "code1", - "app_id": "app-1", - "end_user_id": "eu-1", + "app_code": site.code, + "app_id": app_model.id, + "end_user_id": non_existent_eu, } mock_features.return_value = SimpleNamespace(webapp_auth=SimpleNamespace(enabled=False)) - app_model = SimpleNamespace(id="app-1", enable_site=True) - site = SimpleNamespace(code="code1") - - session_mock = MagicMock() - session_mock.scalar.side_effect = [app_model, site, None] # end_user is None - session_ctx = MagicMock() - session_ctx.__enter__ = MagicMock(return_value=session_mock) - session_ctx.__exit__ = MagicMock(return_value=False) - mock_db.engine = "engine" - - with patch("controllers.web.wraps.Session", return_value=session_ctx): - with app.test_request_context("/", headers={"X-App-Code": "code1"}): - with pytest.raises(NotFound): - decode_jwt_token() + with app.test_request_context("/", headers={"X-App-Code": site.code}): + with pytest.raises(NotFound): + decode_jwt_token() @patch("controllers.web.wraps.FeatureService.get_system_features") @patch("controllers.web.wraps.PassportService") @patch("controllers.web.wraps.extract_webapp_passport") - @patch("controllers.web.wraps.db") def test_user_id_mismatch_raises_unauthorized( self, - mock_db: MagicMock, mock_extract: MagicMock, mock_passport_cls: MagicMock, mock_features: MagicMock, - app: Flask, + app, + db_session_with_containers: Session, ) -> None: + app_model, site, end_user = self._create_app_site_enduser(db_session_with_containers) + mock_extract.return_value = "jwt-token" mock_passport_cls.return_value.verify.return_value = { - "app_code": "code1", - "app_id": "app-1", - "end_user_id": "eu-1", + "app_code": site.code, + "app_id": app_model.id, + "end_user_id": end_user.id, } mock_features.return_value = SimpleNamespace(webapp_auth=SimpleNamespace(enabled=False)) - app_model = SimpleNamespace(id="app-1", enable_site=True) - site = SimpleNamespace(code="code1") - end_user = SimpleNamespace(id="eu-1", session_id="sess-1") - - session_mock = MagicMock() - session_mock.scalar.side_effect = [app_model, site, end_user] - session_ctx = MagicMock() - session_ctx.__enter__ = MagicMock(return_value=session_mock) - session_ctx.__exit__ = MagicMock(return_value=False) - mock_db.engine = "engine" - - with patch("controllers.web.wraps.Session", return_value=session_ctx): - with app.test_request_context("/", headers={"X-App-Code": "code1"}): - with pytest.raises(Unauthorized, match="expired"): - decode_jwt_token(user_id="different-user") + with app.test_request_context("/", headers={"X-App-Code": site.code}): + with pytest.raises(Unauthorized, match="expired"): + decode_jwt_token(user_id="different-user") From 3a7885819d7831380a862ef695f87ca999d18828 Mon Sep 17 00:00:00 2001 From: YBoy Date: Tue, 31 Mar 2026 03:25:46 +0300 Subject: [PATCH 16/40] test: migrate web conversation controller tests to testcontainers (#34287) --- .../controllers/web/test_conversation.py | 73 +++++++++---------- 1 file changed, 35 insertions(+), 38 deletions(-) rename api/tests/{unit_tests => test_containers_integration_tests}/controllers/web/test_conversation.py (72%) diff --git a/api/tests/unit_tests/controllers/web/test_conversation.py b/api/tests/test_containers_integration_tests/controllers/web/test_conversation.py similarity index 72% rename from api/tests/unit_tests/controllers/web/test_conversation.py rename to api/tests/test_containers_integration_tests/controllers/web/test_conversation.py index e5adbbbf66..e1e6741014 100644 --- a/api/tests/unit_tests/controllers/web/test_conversation.py +++ b/api/tests/test_containers_integration_tests/controllers/web/test_conversation.py @@ -1,4 +1,4 @@ -"""Unit tests for controllers.web.conversation endpoints.""" +"""Testcontainers integration tests for controllers.web.conversation endpoints.""" from __future__ import annotations @@ -7,7 +7,6 @@ from unittest.mock import MagicMock, patch from uuid import uuid4 import pytest -from flask import Flask from werkzeug.exceptions import NotFound from controllers.web.conversation import ( @@ -33,18 +32,18 @@ def _end_user() -> SimpleNamespace: return SimpleNamespace(id="eu-1") -# --------------------------------------------------------------------------- -# ConversationListApi -# --------------------------------------------------------------------------- class TestConversationListApi: - def test_non_chat_mode_raises(self, app: Flask) -> None: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + + def test_non_chat_mode_raises(self, app) -> None: with app.test_request_context("/conversations"): with pytest.raises(NotChatAppError): ConversationListApi().get(_completion_app(), _end_user()) @patch("controllers.web.conversation.WebConversationService.pagination_by_last_id") - @patch("controllers.web.conversation.db") - def test_happy_path(self, mock_db: MagicMock, mock_paginate: MagicMock, app: Flask) -> None: + def test_happy_path(self, mock_paginate: MagicMock, app) -> None: conv_id = str(uuid4()) conv = SimpleNamespace( id=conv_id, @@ -56,34 +55,26 @@ class TestConversationListApi: updated_at=1700000000, ) mock_paginate.return_value = SimpleNamespace(limit=20, has_more=False, data=[conv]) - mock_db.engine = "engine" - session_mock = MagicMock() - session_ctx = MagicMock() - session_ctx.__enter__ = MagicMock(return_value=session_mock) - session_ctx.__exit__ = MagicMock(return_value=False) - - with ( - app.test_request_context("/conversations?limit=20"), - patch("controllers.web.conversation.Session", return_value=session_ctx), - ): + with app.test_request_context("/conversations?limit=20"): result = ConversationListApi().get(_chat_app(), _end_user()) assert result["limit"] == 20 assert result["has_more"] is False -# --------------------------------------------------------------------------- -# ConversationApi (delete) -# --------------------------------------------------------------------------- class TestConversationApi: - def test_non_chat_mode_raises(self, app: Flask) -> None: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + + def test_non_chat_mode_raises(self, app) -> None: with app.test_request_context(f"/conversations/{uuid4()}"): with pytest.raises(NotChatAppError): ConversationApi().delete(_completion_app(), _end_user(), uuid4()) @patch("controllers.web.conversation.ConversationService.delete") - def test_delete_success(self, mock_delete: MagicMock, app: Flask) -> None: + def test_delete_success(self, mock_delete: MagicMock, app) -> None: c_id = uuid4() with app.test_request_context(f"/conversations/{c_id}"): result, status = ConversationApi().delete(_chat_app(), _end_user(), c_id) @@ -92,25 +83,26 @@ class TestConversationApi: assert result["result"] == "success" @patch("controllers.web.conversation.ConversationService.delete", side_effect=ConversationNotExistsError()) - def test_delete_not_found(self, mock_delete: MagicMock, app: Flask) -> None: + def test_delete_not_found(self, mock_delete: MagicMock, app) -> None: c_id = uuid4() with app.test_request_context(f"/conversations/{c_id}"): with pytest.raises(NotFound, match="Conversation Not Exists"): ConversationApi().delete(_chat_app(), _end_user(), c_id) -# --------------------------------------------------------------------------- -# ConversationRenameApi -# --------------------------------------------------------------------------- class TestConversationRenameApi: - def test_non_chat_mode_raises(self, app: Flask) -> None: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + + def test_non_chat_mode_raises(self, app) -> None: with app.test_request_context(f"/conversations/{uuid4()}/name", method="POST", json={"name": "x"}): with pytest.raises(NotChatAppError): ConversationRenameApi().post(_completion_app(), _end_user(), uuid4()) @patch("controllers.web.conversation.ConversationService.rename") @patch("controllers.web.conversation.web_ns") - def test_rename_success(self, mock_ns: MagicMock, mock_rename: MagicMock, app: Flask) -> None: + def test_rename_success(self, mock_ns: MagicMock, mock_rename: MagicMock, app) -> None: c_id = uuid4() mock_ns.payload = {"name": "New Name", "auto_generate": False} conv = SimpleNamespace( @@ -134,7 +126,7 @@ class TestConversationRenameApi: side_effect=ConversationNotExistsError(), ) @patch("controllers.web.conversation.web_ns") - def test_rename_not_found(self, mock_ns: MagicMock, mock_rename: MagicMock, app: Flask) -> None: + def test_rename_not_found(self, mock_ns: MagicMock, mock_rename: MagicMock, app) -> None: c_id = uuid4() mock_ns.payload = {"name": "X", "auto_generate": False} @@ -143,17 +135,18 @@ class TestConversationRenameApi: ConversationRenameApi().post(_chat_app(), _end_user(), c_id) -# --------------------------------------------------------------------------- -# ConversationPinApi / ConversationUnPinApi -# --------------------------------------------------------------------------- class TestConversationPinApi: - def test_non_chat_mode_raises(self, app: Flask) -> None: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + + def test_non_chat_mode_raises(self, app) -> None: with app.test_request_context(f"/conversations/{uuid4()}/pin", method="PATCH"): with pytest.raises(NotChatAppError): ConversationPinApi().patch(_completion_app(), _end_user(), uuid4()) @patch("controllers.web.conversation.WebConversationService.pin") - def test_pin_success(self, mock_pin: MagicMock, app: Flask) -> None: + def test_pin_success(self, mock_pin: MagicMock, app) -> None: c_id = uuid4() with app.test_request_context(f"/conversations/{c_id}/pin", method="PATCH"): result = ConversationPinApi().patch(_chat_app(), _end_user(), c_id) @@ -161,7 +154,7 @@ class TestConversationPinApi: assert result["result"] == "success" @patch("controllers.web.conversation.WebConversationService.pin", side_effect=ConversationNotExistsError()) - def test_pin_not_found(self, mock_pin: MagicMock, app: Flask) -> None: + def test_pin_not_found(self, mock_pin: MagicMock, app) -> None: c_id = uuid4() with app.test_request_context(f"/conversations/{c_id}/pin", method="PATCH"): with pytest.raises(NotFound): @@ -169,13 +162,17 @@ class TestConversationPinApi: class TestConversationUnPinApi: - def test_non_chat_mode_raises(self, app: Flask) -> None: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + + def test_non_chat_mode_raises(self, app) -> None: with app.test_request_context(f"/conversations/{uuid4()}/unpin", method="PATCH"): with pytest.raises(NotChatAppError): ConversationUnPinApi().patch(_completion_app(), _end_user(), uuid4()) @patch("controllers.web.conversation.WebConversationService.unpin") - def test_unpin_success(self, mock_unpin: MagicMock, app: Flask) -> None: + def test_unpin_success(self, mock_unpin: MagicMock, app) -> None: c_id = uuid4() with app.test_request_context(f"/conversations/{c_id}/unpin", method="PATCH"): result = ConversationUnPinApi().patch(_chat_app(), _end_user(), c_id) From c58170f5b83f98a3d766d73ddb946a8d38365e3e Mon Sep 17 00:00:00 2001 From: YBoy Date: Tue, 31 Mar 2026 03:26:50 +0300 Subject: [PATCH 17/40] test: migrate app import api controller tests to testcontainers (#34290) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- .../console/app/test_app_import_api.py | 142 ++++++++++++++++ .../console/app/test_app_import_api.py | 157 ------------------ 2 files changed, 142 insertions(+), 157 deletions(-) create mode 100644 api/tests/test_containers_integration_tests/controllers/console/app/test_app_import_api.py delete mode 100644 api/tests/unit_tests/controllers/console/app/test_app_import_api.py diff --git a/api/tests/test_containers_integration_tests/controllers/console/app/test_app_import_api.py b/api/tests/test_containers_integration_tests/controllers/console/app/test_app_import_api.py new file mode 100644 index 0000000000..d8c6821f8d --- /dev/null +++ b/api/tests/test_containers_integration_tests/controllers/console/app/test_app_import_api.py @@ -0,0 +1,142 @@ +"""Testcontainers integration tests for controllers.console.app.app_import endpoints.""" + +from __future__ import annotations + +from types import SimpleNamespace +from unittest.mock import MagicMock + +import pytest + +from controllers.console.app import app_import as app_import_module +from services.app_dsl_service import ImportStatus + + +def _unwrap(func): + bound_self = getattr(func, "__self__", None) + while hasattr(func, "__wrapped__"): + func = func.__wrapped__ + if bound_self is not None: + return func.__get__(bound_self, bound_self.__class__) + return func + + +class _Result: + def __init__(self, status: ImportStatus, app_id: str | None = "app-1"): + self.status = status + self.app_id = app_id + + def model_dump(self, mode: str = "json"): + return {"status": self.status, "app_id": self.app_id} + + +def _install_features(monkeypatch: pytest.MonkeyPatch, enabled: bool) -> None: + features = SimpleNamespace(webapp_auth=SimpleNamespace(enabled=enabled)) + monkeypatch.setattr(app_import_module.FeatureService, "get_system_features", lambda: features) + + +class TestAppImportApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + + def test_import_post_returns_failed_status(self, app, monkeypatch: pytest.MonkeyPatch) -> None: + api = app_import_module.AppImportApi() + method = _unwrap(api.post) + + _install_features(monkeypatch, enabled=False) + monkeypatch.setattr( + app_import_module.AppDslService, + "import_app", + lambda *_args, **_kwargs: _Result(ImportStatus.FAILED, app_id=None), + ) + monkeypatch.setattr(app_import_module, "current_account_with_tenant", lambda: (SimpleNamespace(id="u1"), "t1")) + + with app.test_request_context("/console/api/apps/imports", method="POST", json={"mode": "yaml-content"}): + response, status = method() + + assert status == 400 + assert response["status"] == ImportStatus.FAILED + + def test_import_post_returns_pending_status(self, app, monkeypatch: pytest.MonkeyPatch) -> None: + api = app_import_module.AppImportApi() + method = _unwrap(api.post) + + _install_features(monkeypatch, enabled=False) + monkeypatch.setattr( + app_import_module.AppDslService, + "import_app", + lambda *_args, **_kwargs: _Result(ImportStatus.PENDING), + ) + monkeypatch.setattr(app_import_module, "current_account_with_tenant", lambda: (SimpleNamespace(id="u1"), "t1")) + + with app.test_request_context("/console/api/apps/imports", method="POST", json={"mode": "yaml-content"}): + response, status = method() + + assert status == 202 + assert response["status"] == ImportStatus.PENDING + + def test_import_post_updates_webapp_auth_when_enabled(self, app, monkeypatch: pytest.MonkeyPatch) -> None: + api = app_import_module.AppImportApi() + method = _unwrap(api.post) + + _install_features(monkeypatch, enabled=True) + monkeypatch.setattr( + app_import_module.AppDslService, + "import_app", + lambda *_args, **_kwargs: _Result(ImportStatus.COMPLETED, app_id="app-123"), + ) + update_access = MagicMock() + monkeypatch.setattr(app_import_module.EnterpriseService.WebAppAuth, "update_app_access_mode", update_access) + monkeypatch.setattr(app_import_module, "current_account_with_tenant", lambda: (SimpleNamespace(id="u1"), "t1")) + + with app.test_request_context("/console/api/apps/imports", method="POST", json={"mode": "yaml-content"}): + response, status = method() + + update_access.assert_called_once_with("app-123", "private") + assert status == 200 + assert response["status"] == ImportStatus.COMPLETED + + +class TestAppImportConfirmApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + + def test_import_confirm_returns_failed_status(self, app, monkeypatch: pytest.MonkeyPatch) -> None: + api = app_import_module.AppImportConfirmApi() + method = _unwrap(api.post) + + monkeypatch.setattr( + app_import_module.AppDslService, + "confirm_import", + lambda *_args, **_kwargs: _Result(ImportStatus.FAILED), + ) + monkeypatch.setattr(app_import_module, "current_account_with_tenant", lambda: (SimpleNamespace(id="u1"), "t1")) + + with app.test_request_context("/console/api/apps/imports/import-1/confirm", method="POST"): + response, status = method(import_id="import-1") + + assert status == 400 + assert response["status"] == ImportStatus.FAILED + + +class TestAppImportCheckDependenciesApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + + def test_import_check_dependencies_returns_result(self, app, monkeypatch: pytest.MonkeyPatch) -> None: + api = app_import_module.AppImportCheckDependenciesApi() + method = _unwrap(api.get) + + monkeypatch.setattr( + app_import_module.AppDslService, + "check_dependencies", + lambda *_args, **_kwargs: SimpleNamespace(model_dump=lambda mode="json": {"leaked_dependencies": []}), + ) + + with app.test_request_context("/console/api/apps/imports/app-1/check-dependencies", method="GET"): + response, status = method(app_model=SimpleNamespace(id="app-1")) + + assert status == 200 + assert response["leaked_dependencies"] == [] diff --git a/api/tests/unit_tests/controllers/console/app/test_app_import_api.py b/api/tests/unit_tests/controllers/console/app/test_app_import_api.py deleted file mode 100644 index 91f58460ac..0000000000 --- a/api/tests/unit_tests/controllers/console/app/test_app_import_api.py +++ /dev/null @@ -1,157 +0,0 @@ -from __future__ import annotations - -from types import SimpleNamespace -from unittest.mock import MagicMock - -import pytest - -from controllers.console.app import app_import as app_import_module -from services.app_dsl_service import ImportStatus - - -def _unwrap(func): - bound_self = getattr(func, "__self__", None) - while hasattr(func, "__wrapped__"): - func = func.__wrapped__ - if bound_self is not None: - return func.__get__(bound_self, bound_self.__class__) - return func - - -class _Result: - def __init__(self, status: ImportStatus, app_id: str | None = "app-1"): - self.status = status - self.app_id = app_id - - def model_dump(self, mode: str = "json"): - return {"status": self.status, "app_id": self.app_id} - - -class _SessionContext: - def __init__(self, session): - self._session = session - - def __enter__(self): - return self._session - - def __exit__(self, exc_type, exc, tb): - return False - - -def _install_session(monkeypatch: pytest.MonkeyPatch, session: MagicMock) -> None: - monkeypatch.setattr(app_import_module, "Session", lambda *_: _SessionContext(session)) - monkeypatch.setattr(app_import_module, "db", SimpleNamespace(engine=object())) - - -def _install_features(monkeypatch: pytest.MonkeyPatch, enabled: bool) -> None: - features = SimpleNamespace(webapp_auth=SimpleNamespace(enabled=enabled)) - monkeypatch.setattr(app_import_module.FeatureService, "get_system_features", lambda: features) - - -def test_import_post_returns_failed_status(app, monkeypatch: pytest.MonkeyPatch) -> None: - api = app_import_module.AppImportApi() - method = _unwrap(api.post) - - session = MagicMock() - _install_session(monkeypatch, session) - _install_features(monkeypatch, enabled=False) - monkeypatch.setattr( - app_import_module.AppDslService, - "import_app", - lambda *_args, **_kwargs: _Result(ImportStatus.FAILED, app_id=None), - ) - monkeypatch.setattr(app_import_module, "current_account_with_tenant", lambda: (SimpleNamespace(id="u1"), "t1")) - - with app.test_request_context("/console/api/apps/imports", method="POST", json={"mode": "yaml-content"}): - response, status = method() - - session.commit.assert_called_once() - assert status == 400 - assert response["status"] == ImportStatus.FAILED - - -def test_import_post_returns_pending_status(app, monkeypatch: pytest.MonkeyPatch) -> None: - api = app_import_module.AppImportApi() - method = _unwrap(api.post) - - session = MagicMock() - _install_session(monkeypatch, session) - _install_features(monkeypatch, enabled=False) - monkeypatch.setattr( - app_import_module.AppDslService, - "import_app", - lambda *_args, **_kwargs: _Result(ImportStatus.PENDING), - ) - monkeypatch.setattr(app_import_module, "current_account_with_tenant", lambda: (SimpleNamespace(id="u1"), "t1")) - - with app.test_request_context("/console/api/apps/imports", method="POST", json={"mode": "yaml-content"}): - response, status = method() - - session.commit.assert_called_once() - assert status == 202 - assert response["status"] == ImportStatus.PENDING - - -def test_import_post_updates_webapp_auth_when_enabled(app, monkeypatch: pytest.MonkeyPatch) -> None: - api = app_import_module.AppImportApi() - method = _unwrap(api.post) - - session = MagicMock() - _install_session(monkeypatch, session) - _install_features(monkeypatch, enabled=True) - monkeypatch.setattr( - app_import_module.AppDslService, - "import_app", - lambda *_args, **_kwargs: _Result(ImportStatus.COMPLETED, app_id="app-123"), - ) - update_access = MagicMock() - monkeypatch.setattr(app_import_module.EnterpriseService.WebAppAuth, "update_app_access_mode", update_access) - monkeypatch.setattr(app_import_module, "current_account_with_tenant", lambda: (SimpleNamespace(id="u1"), "t1")) - - with app.test_request_context("/console/api/apps/imports", method="POST", json={"mode": "yaml-content"}): - response, status = method() - - session.commit.assert_called_once() - update_access.assert_called_once_with("app-123", "private") - assert status == 200 - assert response["status"] == ImportStatus.COMPLETED - - -def test_import_confirm_returns_failed_status(app, monkeypatch: pytest.MonkeyPatch) -> None: - api = app_import_module.AppImportConfirmApi() - method = _unwrap(api.post) - - session = MagicMock() - _install_session(monkeypatch, session) - monkeypatch.setattr( - app_import_module.AppDslService, - "confirm_import", - lambda *_args, **_kwargs: _Result(ImportStatus.FAILED), - ) - monkeypatch.setattr(app_import_module, "current_account_with_tenant", lambda: (SimpleNamespace(id="u1"), "t1")) - - with app.test_request_context("/console/api/apps/imports/import-1/confirm", method="POST"): - response, status = method(import_id="import-1") - - session.commit.assert_called_once() - assert status == 400 - assert response["status"] == ImportStatus.FAILED - - -def test_import_check_dependencies_returns_result(app, monkeypatch: pytest.MonkeyPatch) -> None: - api = app_import_module.AppImportCheckDependenciesApi() - method = _unwrap(api.get) - - session = MagicMock() - _install_session(monkeypatch, session) - monkeypatch.setattr( - app_import_module.AppDslService, - "check_dependencies", - lambda *_args, **_kwargs: SimpleNamespace(model_dump=lambda mode="json": {"leaked_dependencies": []}), - ) - - with app.test_request_context("/console/api/apps/imports/app-1/check-dependencies", method="GET"): - response, status = method(app_model=SimpleNamespace(id="app-1")) - - assert status == 200 - assert response["leaked_dependencies"] == [] From daebe26089a2b4dd4fd6dde86021a606246d4e9b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 31 Mar 2026 09:27:12 +0900 Subject: [PATCH 18/40] chore(deps): bump pygments from 2.19.2 to 2.20.0 in /api (#34301) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- api/uv.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/uv.lock b/api/uv.lock index 3e8d794866..39c362eda0 100644 --- a/api/uv.lock +++ b/api/uv.lock @@ -5255,11 +5255,11 @@ wheels = [ [[package]] name = "pygments" -version = "2.19.2" +version = "2.20.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, ] [[package]] From 097095a69bd85c6c4c98ed07467ec78634a1fe26 Mon Sep 17 00:00:00 2001 From: YBoy Date: Tue, 31 Mar 2026 03:28:04 +0300 Subject: [PATCH 19/40] test: migrate tool provider controller tests to testcontainers (#34293) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- .../console/workspace/test_tool_provider.py | 56 +++++++++++++------ 1 file changed, 39 insertions(+), 17 deletions(-) rename api/tests/{unit_tests => test_containers_integration_tests}/controllers/console/workspace/test_tool_provider.py (95%) diff --git a/api/tests/unit_tests/controllers/console/workspace/test_tool_provider.py b/api/tests/test_containers_integration_tests/controllers/console/workspace/test_tool_provider.py similarity index 95% rename from api/tests/unit_tests/controllers/console/workspace/test_tool_provider.py rename to api/tests/test_containers_integration_tests/controllers/console/workspace/test_tool_provider.py index 16ea1bf509..e36bd213d9 100644 --- a/api/tests/unit_tests/controllers/console/workspace/test_tool_provider.py +++ b/api/tests/test_containers_integration_tests/controllers/console/workspace/test_tool_provider.py @@ -1,9 +1,11 @@ +"""Testcontainers integration tests for controllers.console.workspace.tool_providers endpoints.""" + +from __future__ import annotations + import json from unittest.mock import MagicMock, patch import pytest -from flask import Flask -from flask_restx import Api from werkzeug.exceptions import Forbidden from controllers.console.workspace.tool_providers import ( @@ -31,7 +33,6 @@ from controllers.console.workspace.tool_providers import ( ToolOAuthCustomClient, ToolPluginOAuthApi, ToolProviderListApi, - ToolProviderMCPApi, ToolWorkflowListApi, ToolWorkflowProviderCreateApi, ToolWorkflowProviderDeleteApi, @@ -39,8 +40,6 @@ from controllers.console.workspace.tool_providers import ( ToolWorkflowProviderUpdateApi, is_valid_url, ) -from core.db.session_factory import configure_session_factory -from extensions.ext_database import db from services.tools.mcp_tools_manage_service import ReconnectResult @@ -61,17 +60,8 @@ def _mock_user_tenant(): @pytest.fixture -def client(): - app = Flask(__name__) - app.config["TESTING"] = True - app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///:memory:" - api = Api(app) - api.add_resource(ToolProviderMCPApi, "/console/api/workspaces/current/tool-provider/mcp") - db.init_app(app) - # Configure session factory used by controller code - with app.app_context(): - configure_session_factory(db.engine) - return app.test_client() +def client(flask_app_with_containers): + return flask_app_with_containers.test_client() @patch( @@ -152,10 +142,14 @@ class TestUtils: assert not is_valid_url("") assert not is_valid_url("ftp://example.com") assert not is_valid_url("not-a-url") - assert not is_valid_url(None) + assert not is_valid_url(None) # type: ignore[arg-type] class TestToolProviderListApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_get_success(self, app): api = ToolProviderListApi() method = unwrap(api.get) @@ -175,6 +169,10 @@ class TestToolProviderListApi: class TestBuiltinProviderApis: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_list_tools(self, app): api = ToolBuiltinProviderListToolsApi() method = unwrap(api.get) @@ -379,6 +377,10 @@ class TestBuiltinProviderApis: class TestApiProviderApis: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_add(self, app): api = ToolApiProviderAddApi() method = unwrap(api.post) @@ -502,6 +504,10 @@ class TestApiProviderApis: class TestWorkflowApis: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_create(self, app): api = ToolWorkflowProviderCreateApi() method = unwrap(api.post) @@ -587,6 +593,10 @@ class TestWorkflowApis: class TestLists: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_builtin_list(self, app): api = ToolBuiltinListApi() method = unwrap(api.get) @@ -649,6 +659,10 @@ class TestLists: class TestLabels: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_labels(self, app): api = ToolLabelsApi() method = unwrap(api.get) @@ -664,6 +678,10 @@ class TestLabels: class TestOAuth: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_oauth_no_client(self, app): api = ToolPluginOAuthApi() method = unwrap(api.get) @@ -692,6 +710,10 @@ class TestOAuth: class TestOAuthCustomClient: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_save_custom_client(self, app): api = ToolOAuthCustomClient() method = unwrap(api.post) From 15aa8071f89a005dc3c68f4e3d9edd39fb5f66cb Mon Sep 17 00:00:00 2001 From: YBoy Date: Tue, 31 Mar 2026 03:28:44 +0300 Subject: [PATCH 20/40] test: migrate mcp controller tests to testcontainers (#34297) --- .../controllers/mcp/test_mcp.py | 35 ++++++++----------- 1 file changed, 14 insertions(+), 21 deletions(-) rename api/tests/{unit_tests => test_containers_integration_tests}/controllers/mcp/test_mcp.py (96%) diff --git a/api/tests/unit_tests/controllers/mcp/test_mcp.py b/api/tests/test_containers_integration_tests/controllers/mcp/test_mcp.py similarity index 96% rename from api/tests/unit_tests/controllers/mcp/test_mcp.py rename to api/tests/test_containers_integration_tests/controllers/mcp/test_mcp.py index b93770e9c2..90670a9db5 100644 --- a/api/tests/unit_tests/controllers/mcp/test_mcp.py +++ b/api/tests/test_containers_integration_tests/controllers/mcp/test_mcp.py @@ -1,5 +1,10 @@ +"""Testcontainers integration tests for controllers.mcp.mcp endpoints.""" + +from __future__ import annotations + import types from unittest.mock import MagicMock, patch +from uuid import uuid4 import pytest from flask import Response @@ -14,24 +19,6 @@ def unwrap(func): return func -@pytest.fixture(autouse=True) -def mock_db(): - module.db = types.SimpleNamespace(engine=object()) - - -@pytest.fixture -def fake_session(): - session = MagicMock() - session.__enter__.return_value = session - session.__exit__.return_value = False - return session - - -@pytest.fixture(autouse=True) -def mock_session(fake_session): - module.Session = MagicMock(return_value=fake_session) - - @pytest.fixture(autouse=True) def mock_mcp_ns(): fake_ns = types.SimpleNamespace() @@ -44,8 +31,13 @@ def fake_payload(data): module.mcp_ns.payload = data +_TENANT_ID = str(uuid4()) +_APP_ID = str(uuid4()) +_SERVER_ID = str(uuid4()) + + class DummyServer: - def __init__(self, status, app_id="app-1", tenant_id="tenant-1", server_id="srv-1"): + def __init__(self, status, app_id=_APP_ID, tenant_id=_TENANT_ID, server_id=_SERVER_ID): self.status = status self.app_id = app_id self.tenant_id = tenant_id @@ -54,8 +46,8 @@ class DummyServer: class DummyApp: def __init__(self, mode, workflow=None, app_model_config=None): - self.id = "app-1" - self.tenant_id = "tenant-1" + self.id = _APP_ID + self.tenant_id = _TENANT_ID self.mode = mode self.workflow = workflow self.app_model_config = app_model_config @@ -76,6 +68,7 @@ class DummyResult: return {"jsonrpc": "2.0", "result": "ok", "id": 1} +@pytest.mark.usefixtures("flask_req_ctx_with_containers") class TestMCPAppApi: @patch.object(module, "handle_mcp_request", return_value=DummyResult(), autospec=True) def test_success_request(self, mock_handle): From 5897b28355f11e15cc590024d8c7a60b453deae7 Mon Sep 17 00:00:00 2001 From: tmimmanuel <14046872+tmimmanuel@users.noreply.github.com> Date: Tue, 31 Mar 2026 02:29:57 +0200 Subject: [PATCH 21/40] refactor: use EnumText for Provider.quota_type and consolidate ProviderQuotaType (#34299) --- api/core/app/llm/quota.py | 2 +- api/core/provider_manager.py | 12 ++++------ .../update_provider_when_message_created.py | 2 +- api/models/provider.py | 24 ++++--------------- api/models/types.py | 4 ++-- .../unit_tests/models/test_provider_models.py | 2 +- 6 files changed, 14 insertions(+), 32 deletions(-) diff --git a/api/core/app/llm/quota.py b/api/core/app/llm/quota.py index 63d2235358..182f1b767d 100644 --- a/api/core/app/llm/quota.py +++ b/api/core/app/llm/quota.py @@ -81,7 +81,7 @@ def deduct_llm_quota(*, tenant_id: str, model_instance: ModelInstance, usage: LL # TODO: Use provider name with prefix after the data migration. Provider.provider_name == ModelProviderID(model_instance.provider).provider_name, Provider.provider_type == ProviderType.SYSTEM.value, - Provider.quota_type == system_configuration.current_quota_type.value, + Provider.quota_type == system_configuration.current_quota_type, Provider.quota_limit > Provider.quota_used, ) .values( diff --git a/api/core/provider_manager.py b/api/core/provider_manager.py index 30933239f6..b2a8e9c114 100644 --- a/api/core/provider_manager.py +++ b/api/core/provider_manager.py @@ -626,9 +626,8 @@ class ProviderManager: if provider_record.provider_type != ProviderType.SYSTEM: continue - provider_quota_to_provider_record_dict[ProviderQuotaType.value_of(provider_record.quota_type)] = ( - provider_record - ) + if provider_record.quota_type is not None: + provider_quota_to_provider_record_dict[provider_record.quota_type] = provider_record for quota in configuration.quotas: if quota.quota_type in (ProviderQuotaType.TRIAL, ProviderQuotaType.PAID): @@ -641,7 +640,7 @@ class ProviderManager: # TODO: Use provider name with prefix after the data migration. provider_name=ModelProviderID(provider_name).provider_name, provider_type=ProviderType.SYSTEM, - quota_type=quota.quota_type, + quota_type=quota.quota_type, # type: ignore[arg-type] quota_limit=0, # type: ignore quota_used=0, is_valid=True, @@ -921,9 +920,8 @@ class ProviderManager: if provider_record.provider_type != ProviderType.SYSTEM: continue - quota_type_to_provider_records_dict[ProviderQuotaType.value_of(provider_record.quota_type)] = ( - provider_record - ) + if provider_record.quota_type is not None: + quota_type_to_provider_records_dict[provider_record.quota_type] = provider_record # type: ignore[index] quota_configurations = [] if dify_config.EDITION == "CLOUD": diff --git a/api/events/event_handlers/update_provider_when_message_created.py b/api/events/event_handlers/update_provider_when_message_created.py index 1ddcc8f792..f68cdaadde 100644 --- a/api/events/event_handlers/update_provider_when_message_created.py +++ b/api/events/event_handlers/update_provider_when_message_created.py @@ -157,7 +157,7 @@ def handle(sender: Message, **kwargs): tenant_id=tenant_id, provider_name=ModelProviderID(model_config.provider).provider_name, provider_type=ProviderType.SYSTEM.value, - quota_type=provider_configuration.system_configuration.current_quota_type.value, + quota_type=provider_configuration.system_configuration.current_quota_type, ), values=_ProviderUpdateValues(quota_used=Provider.quota_used + used_quota, last_used=current_time), additional_filters=_ProviderUpdateAdditionalFilters( diff --git a/api/models/provider.py b/api/models/provider.py index afeee20b1e..bdcfb7aa0d 100644 --- a/api/models/provider.py +++ b/api/models/provider.py @@ -13,7 +13,7 @@ from libs.uuid_utils import uuidv7 from .base import TypeBase from .engine import db -from .enums import CredentialSourceType, PaymentStatus +from .enums import CredentialSourceType, PaymentStatus, ProviderQuotaType from .types import EnumText, LongText, StringUUID @@ -29,24 +29,6 @@ class ProviderType(StrEnum): raise ValueError(f"No matching enum found for value '{value}'") -class ProviderQuotaType(StrEnum): - PAID = auto() - """hosted paid quota""" - - FREE = auto() - """third-party free quota""" - - TRIAL = auto() - """hosted trial quota""" - - @staticmethod - def value_of(value: str) -> ProviderQuotaType: - for member in ProviderQuotaType: - if member.value == value: - return member - raise ValueError(f"No matching enum found for value '{value}'") - - class Provider(TypeBase): """ Provider model representing the API providers and their configurations. @@ -77,7 +59,9 @@ class Provider(TypeBase): last_used: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, init=False) credential_id: Mapped[str | None] = mapped_column(StringUUID, nullable=True, default=None) - quota_type: Mapped[str | None] = mapped_column(String(40), nullable=True, server_default=text("''"), default="") + quota_type: Mapped[ProviderQuotaType | None] = mapped_column( + EnumText(ProviderQuotaType, length=40), nullable=True, server_default=text("''"), default=None + ) quota_limit: Mapped[int | None] = mapped_column(sa.BigInteger, nullable=True, default=None) quota_used: Mapped[int | None] = mapped_column(sa.BigInteger, nullable=True, default=0) diff --git a/api/models/types.py b/api/models/types.py index f8369dab9e..98084563be 100644 --- a/api/models/types.py +++ b/api/models/types.py @@ -144,8 +144,8 @@ class EnumText(TypeDecorator[_E | None], Generic[_E]): return dialect.type_descriptor(VARCHAR(self._length)) def process_result_value(self, value: str | None, dialect: Dialect) -> _E | None: - if value is None: - return value + if value is None or value == "": + return None # Type annotation guarantees value is str at this point return self._enum_class(value) diff --git a/api/tests/unit_tests/models/test_provider_models.py b/api/tests/unit_tests/models/test_provider_models.py index f628e54a4d..d7b597e5fb 100644 --- a/api/tests/unit_tests/models/test_provider_models.py +++ b/api/tests/unit_tests/models/test_provider_models.py @@ -202,7 +202,7 @@ class TestProviderModel: # Assert assert provider.provider_type == ProviderType.CUSTOM assert provider.is_valid is False - assert provider.quota_type == "" + assert provider.quota_type is None assert provider.quota_limit is None assert provider.quota_used == 0 assert provider.credential_id is None From 1344c3b280b582761e8a700c5914f219337826b6 Mon Sep 17 00:00:00 2001 From: tmimmanuel <14046872+tmimmanuel@users.noreply.github.com> Date: Tue, 31 Mar 2026 02:31:33 +0200 Subject: [PATCH 22/40] refactor: use EnumText for model_type in provider models (#34300) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- api/controllers/console/workspace/models.py | 4 +- api/core/entities/provider_configuration.py | 38 +++++++++---------- api/core/provider_manager.py | 12 +++--- api/models/provider.py | 11 +++--- api/services/model_load_balancing_service.py | 16 ++++---- .../test_model_load_balancing_service.py | 6 +-- .../unit_tests/core/test_provider_manager.py | 22 +++++------ .../test_model_load_balancing_service.py | 2 +- 8 files changed, 55 insertions(+), 56 deletions(-) diff --git a/api/controllers/console/workspace/models.py b/api/controllers/console/workspace/models.py index 2ec1a9435a..9182dbb510 100644 --- a/api/controllers/console/workspace/models.py +++ b/api/controllers/console/workspace/models.py @@ -287,12 +287,10 @@ class ModelProviderModelCredentialApi(Resource): provider=provider, ) else: - # Normalize model_type to the origin value stored in DB (e.g., "text-generation" for LLM) - normalized_model_type = args.model_type.to_origin_model_type() available_credentials = model_provider_service.get_provider_model_available_credentials( tenant_id=tenant_id, provider=provider, - model_type=normalized_model_type, + model_type=args.model_type, model=args.model, ) diff --git a/api/core/entities/provider_configuration.py b/api/core/entities/provider_configuration.py index 8b48aa2660..782897aea9 100644 --- a/api/core/entities/provider_configuration.py +++ b/api/core/entities/provider_configuration.py @@ -403,7 +403,7 @@ class ProviderConfiguration(BaseModel): ProviderModelCredential.tenant_id == self.tenant_id, ProviderModelCredential.provider_name.in_(self._get_provider_names()), ProviderModelCredential.model_name == model, - ProviderModelCredential.model_type == model_type.to_origin_model_type(), + ProviderModelCredential.model_type == model_type, ), ) @@ -753,7 +753,7 @@ class ProviderConfiguration(BaseModel): ProviderModel.tenant_id == self.tenant_id, ProviderModel.provider_name.in_(provider_names), ProviderModel.model_name == model, - ProviderModel.model_type == model_type.to_origin_model_type(), + ProviderModel.model_type == model_type, ) return session.execute(stmt).scalar_one_or_none() @@ -778,7 +778,7 @@ class ProviderConfiguration(BaseModel): ProviderModelCredential.tenant_id == self.tenant_id, ProviderModelCredential.provider_name.in_(self._get_provider_names()), ProviderModelCredential.model_name == model, - ProviderModelCredential.model_type == model_type.to_origin_model_type(), + ProviderModelCredential.model_type == model_type, ) credential_record = session.execute(stmt).scalar_one_or_none() @@ -825,7 +825,7 @@ class ProviderConfiguration(BaseModel): ProviderModelCredential.tenant_id == self.tenant_id, ProviderModelCredential.provider_name.in_(self._get_provider_names()), ProviderModelCredential.model_name == model, - ProviderModelCredential.model_type == model_type.to_origin_model_type(), + ProviderModelCredential.model_type == model_type, ProviderModelCredential.credential_name == credential_name, ) if exclude_id: @@ -901,7 +901,7 @@ class ProviderConfiguration(BaseModel): ProviderModelCredential.tenant_id == self.tenant_id, ProviderModelCredential.provider_name.in_(self._get_provider_names()), ProviderModelCredential.model_name == model, - ProviderModelCredential.model_type == model_type.to_origin_model_type(), + ProviderModelCredential.model_type == model_type, ) credential_record = s.execute(stmt).scalar_one_or_none() original_credentials = ( @@ -970,7 +970,7 @@ class ProviderConfiguration(BaseModel): tenant_id=self.tenant_id, provider_name=self.provider.provider, model_name=model, - model_type=model_type.to_origin_model_type(), + model_type=model_type, encrypted_config=json.dumps(credentials), credential_name=credential_name, ) @@ -983,7 +983,7 @@ class ProviderConfiguration(BaseModel): tenant_id=self.tenant_id, provider_name=self.provider.provider, model_name=model, - model_type=model_type.to_origin_model_type(), + model_type=model_type, credential_id=credential.id, is_valid=True, ) @@ -1038,7 +1038,7 @@ class ProviderConfiguration(BaseModel): ProviderModelCredential.tenant_id == self.tenant_id, ProviderModelCredential.provider_name.in_(self._get_provider_names()), ProviderModelCredential.model_name == model, - ProviderModelCredential.model_type == model_type.to_origin_model_type(), + ProviderModelCredential.model_type == model_type, ) credential_record = session.execute(stmt).scalar_one_or_none() if not credential_record: @@ -1083,7 +1083,7 @@ class ProviderConfiguration(BaseModel): ProviderModelCredential.tenant_id == self.tenant_id, ProviderModelCredential.provider_name.in_(self._get_provider_names()), ProviderModelCredential.model_name == model, - ProviderModelCredential.model_type == model_type.to_origin_model_type(), + ProviderModelCredential.model_type == model_type, ) credential_record = session.execute(stmt).scalar_one_or_none() if not credential_record: @@ -1116,7 +1116,7 @@ class ProviderConfiguration(BaseModel): ProviderModelCredential.tenant_id == self.tenant_id, ProviderModelCredential.provider_name.in_(self._get_provider_names()), ProviderModelCredential.model_name == model, - ProviderModelCredential.model_type == model_type.to_origin_model_type(), + ProviderModelCredential.model_type == model_type, ) available_credentials_count = session.execute(count_stmt).scalar() or 0 session.delete(credential_record) @@ -1156,7 +1156,7 @@ class ProviderConfiguration(BaseModel): ProviderModelCredential.tenant_id == self.tenant_id, ProviderModelCredential.provider_name.in_(self._get_provider_names()), ProviderModelCredential.model_name == model, - ProviderModelCredential.model_type == model_type.to_origin_model_type(), + ProviderModelCredential.model_type == model_type, ) credential_record = session.execute(stmt).scalar_one_or_none() if not credential_record: @@ -1171,7 +1171,7 @@ class ProviderConfiguration(BaseModel): tenant_id=self.tenant_id, provider_name=self.provider.provider, model_name=model, - model_type=model_type.to_origin_model_type(), + model_type=model_type, is_valid=True, credential_id=credential_id, ) @@ -1207,7 +1207,7 @@ class ProviderConfiguration(BaseModel): ProviderModelCredential.tenant_id == self.tenant_id, ProviderModelCredential.provider_name.in_(self._get_provider_names()), ProviderModelCredential.model_name == model, - ProviderModelCredential.model_type == model_type.to_origin_model_type(), + ProviderModelCredential.model_type == model_type, ) credential_record = session.execute(stmt).scalar_one_or_none() if not credential_record: @@ -1263,7 +1263,7 @@ class ProviderConfiguration(BaseModel): stmt = select(ProviderModelSetting).where( ProviderModelSetting.tenant_id == self.tenant_id, ProviderModelSetting.provider_name.in_(self._get_provider_names()), - ProviderModelSetting.model_type == model_type.to_origin_model_type(), + ProviderModelSetting.model_type == model_type, ProviderModelSetting.model_name == model, ) return session.execute(stmt).scalars().first() @@ -1286,7 +1286,7 @@ class ProviderConfiguration(BaseModel): model_setting = ProviderModelSetting( tenant_id=self.tenant_id, provider_name=self.provider.provider, - model_type=model_type.to_origin_model_type(), + model_type=model_type, model_name=model, enabled=True, ) @@ -1312,7 +1312,7 @@ class ProviderConfiguration(BaseModel): model_setting = ProviderModelSetting( tenant_id=self.tenant_id, provider_name=self.provider.provider, - model_type=model_type.to_origin_model_type(), + model_type=model_type, model_name=model, enabled=False, ) @@ -1348,7 +1348,7 @@ class ProviderConfiguration(BaseModel): stmt = select(func.count(LoadBalancingModelConfig.id)).where( LoadBalancingModelConfig.tenant_id == self.tenant_id, LoadBalancingModelConfig.provider_name.in_(provider_names), - LoadBalancingModelConfig.model_type == model_type.to_origin_model_type(), + LoadBalancingModelConfig.model_type == model_type, LoadBalancingModelConfig.model_name == model, ) load_balancing_config_count = session.execute(stmt).scalar() or 0 @@ -1364,7 +1364,7 @@ class ProviderConfiguration(BaseModel): model_setting = ProviderModelSetting( tenant_id=self.tenant_id, provider_name=self.provider.provider, - model_type=model_type.to_origin_model_type(), + model_type=model_type, model_name=model, load_balancing_enabled=True, ) @@ -1391,7 +1391,7 @@ class ProviderConfiguration(BaseModel): model_setting = ProviderModelSetting( tenant_id=self.tenant_id, provider_name=self.provider.provider, - model_type=model_type.to_origin_model_type(), + model_type=model_type, model_name=model, load_balancing_enabled=False, ) diff --git a/api/core/provider_manager.py b/api/core/provider_manager.py index b2a8e9c114..5d536e0e32 100644 --- a/api/core/provider_manager.py +++ b/api/core/provider_manager.py @@ -306,7 +306,7 @@ class ProviderManager: """ stmt = select(TenantDefaultModel).where( TenantDefaultModel.tenant_id == tenant_id, - TenantDefaultModel.model_type == model_type.to_origin_model_type(), + TenantDefaultModel.model_type == model_type, ) default_model = db.session.scalar(stmt) @@ -324,7 +324,7 @@ class ProviderManager: default_model = TenantDefaultModel( tenant_id=tenant_id, - model_type=model_type.to_origin_model_type(), + model_type=model_type, provider_name=available_model.provider.provider, model_name=available_model.model, ) @@ -391,7 +391,7 @@ class ProviderManager: raise ValueError(f"Model {model} does not exist.") stmt = select(TenantDefaultModel).where( TenantDefaultModel.tenant_id == tenant_id, - TenantDefaultModel.model_type == model_type.to_origin_model_type(), + TenantDefaultModel.model_type == model_type, ) default_model = db.session.scalar(stmt) @@ -405,7 +405,7 @@ class ProviderManager: # create default model default_model = TenantDefaultModel( tenant_id=tenant_id, - model_type=model_type.to_origin_model_type(), + model_type=model_type, provider_name=provider, model_name=model, ) @@ -822,7 +822,7 @@ class ProviderManager: custom_model_configurations.append( CustomModelConfiguration( model=provider_model_record.model_name, - model_type=ModelType.value_of(provider_model_record.model_type), + model_type=provider_model_record.model_type, credentials=provider_model_credentials, current_credential_id=provider_model_record.credential_id, current_credential_name=provider_model_record.credential_name, @@ -1201,7 +1201,7 @@ class ProviderManager: model_settings.append( ModelSettings( model=provider_model_setting.model_name, - model_type=ModelType.value_of(provider_model_setting.model_type), + model_type=provider_model_setting.model_type, enabled=provider_model_setting.enabled, load_balancing_enabled=provider_model_setting.load_balancing_enabled, load_balancing_configs=load_balancing_configs if len(load_balancing_configs) > 1 else [], diff --git a/api/models/provider.py b/api/models/provider.py index bdcfb7aa0d..8270961b31 100644 --- a/api/models/provider.py +++ b/api/models/provider.py @@ -6,6 +6,7 @@ from functools import cached_property from uuid import uuid4 import sqlalchemy as sa +from graphon.model_runtime.entities.model_entities import ModelType from sqlalchemy import DateTime, String, func, select, text from sqlalchemy.orm import Mapped, mapped_column @@ -131,7 +132,7 @@ class ProviderModel(TypeBase): tenant_id: Mapped[str] = mapped_column(StringUUID, nullable=False) provider_name: Mapped[str] = mapped_column(String(255), nullable=False) model_name: Mapped[str] = mapped_column(String(255), nullable=False) - model_type: Mapped[str] = mapped_column(String(40), nullable=False) + model_type: Mapped[ModelType] = mapped_column(EnumText(ModelType, length=40), nullable=False) credential_id: Mapped[str | None] = mapped_column(StringUUID, nullable=True, default=None) is_valid: Mapped[bool] = mapped_column(sa.Boolean, nullable=False, server_default=text("false"), default=False) created_at: Mapped[datetime] = mapped_column( @@ -173,7 +174,7 @@ class TenantDefaultModel(TypeBase): tenant_id: Mapped[str] = mapped_column(StringUUID, nullable=False) provider_name: Mapped[str] = mapped_column(String(255), nullable=False) model_name: Mapped[str] = mapped_column(String(255), nullable=False) - model_type: Mapped[str] = mapped_column(String(40), nullable=False) + model_type: Mapped[ModelType] = mapped_column(EnumText(ModelType, length=40), nullable=False) created_at: Mapped[datetime] = mapped_column( DateTime, nullable=False, server_default=func.current_timestamp(), init=False ) @@ -253,7 +254,7 @@ class ProviderModelSetting(TypeBase): tenant_id: Mapped[str] = mapped_column(StringUUID, nullable=False) provider_name: Mapped[str] = mapped_column(String(255), nullable=False) model_name: Mapped[str] = mapped_column(String(255), nullable=False) - model_type: Mapped[str] = mapped_column(String(40), nullable=False) + model_type: Mapped[ModelType] = mapped_column(EnumText(ModelType, length=40), nullable=False) enabled: Mapped[bool] = mapped_column(sa.Boolean, nullable=False, server_default=text("true"), default=True) load_balancing_enabled: Mapped[bool] = mapped_column( sa.Boolean, nullable=False, server_default=text("false"), default=False @@ -283,7 +284,7 @@ class LoadBalancingModelConfig(TypeBase): tenant_id: Mapped[str] = mapped_column(StringUUID, nullable=False) provider_name: Mapped[str] = mapped_column(String(255), nullable=False) model_name: Mapped[str] = mapped_column(String(255), nullable=False) - model_type: Mapped[str] = mapped_column(String(40), nullable=False) + model_type: Mapped[ModelType] = mapped_column(EnumText(ModelType, length=40), nullable=False) name: Mapped[str] = mapped_column(String(255), nullable=False) encrypted_config: Mapped[str | None] = mapped_column(LongText, nullable=True, default=None) credential_id: Mapped[str | None] = mapped_column(StringUUID, nullable=True, default=None) @@ -348,7 +349,7 @@ class ProviderModelCredential(TypeBase): tenant_id: Mapped[str] = mapped_column(StringUUID, nullable=False) provider_name: Mapped[str] = mapped_column(String(255), nullable=False) model_name: Mapped[str] = mapped_column(String(255), nullable=False) - model_type: Mapped[str] = mapped_column(String(40), nullable=False) + model_type: Mapped[ModelType] = mapped_column(EnumText(ModelType, length=40), nullable=False) credential_name: Mapped[str] = mapped_column(String(255), nullable=False) encrypted_config: Mapped[str] = mapped_column(LongText, nullable=False) created_at: Mapped[datetime] = mapped_column( diff --git a/api/services/model_load_balancing_service.py b/api/services/model_load_balancing_service.py index 25de411e43..752d3002d9 100644 --- a/api/services/model_load_balancing_service.py +++ b/api/services/model_load_balancing_service.py @@ -115,7 +115,7 @@ class ModelLoadBalancingService: .where( LoadBalancingModelConfig.tenant_id == tenant_id, LoadBalancingModelConfig.provider_name == provider_configuration.provider.provider, - LoadBalancingModelConfig.model_type == model_type_enum.to_origin_model_type(), + LoadBalancingModelConfig.model_type == model_type_enum, LoadBalancingModelConfig.model_name == model, or_( LoadBalancingModelConfig.credential_source_type == credential_source_type, @@ -240,7 +240,7 @@ class ModelLoadBalancingService: .where( LoadBalancingModelConfig.tenant_id == tenant_id, LoadBalancingModelConfig.provider_name == provider_configuration.provider.provider, - LoadBalancingModelConfig.model_type == model_type_enum.to_origin_model_type(), + LoadBalancingModelConfig.model_type == model_type_enum, LoadBalancingModelConfig.model_name == model, LoadBalancingModelConfig.id == config_id, ) @@ -288,7 +288,7 @@ class ModelLoadBalancingService: inherit_config = LoadBalancingModelConfig( tenant_id=tenant_id, provider_name=provider, - model_type=model_type.to_origin_model_type(), + model_type=model_type, model_name=model, name="__inherit__", ) @@ -328,7 +328,7 @@ class ModelLoadBalancingService: select(LoadBalancingModelConfig).where( LoadBalancingModelConfig.tenant_id == tenant_id, LoadBalancingModelConfig.provider_name == provider_configuration.provider.provider, - LoadBalancingModelConfig.model_type == model_type_enum.to_origin_model_type(), + LoadBalancingModelConfig.model_type == model_type_enum, LoadBalancingModelConfig.model_name == model, ) ).all() @@ -368,7 +368,7 @@ class ModelLoadBalancingService: tenant_id=tenant_id, provider_name=provider_configuration.provider.provider, model_name=model, - model_type=model_type_enum.to_origin_model_type(), + model_type=model_type_enum, ) .first() ) @@ -432,7 +432,7 @@ class ModelLoadBalancingService: load_balancing_model_config = LoadBalancingModelConfig( tenant_id=tenant_id, provider_name=provider_configuration.provider.provider, - model_type=model_type_enum.to_origin_model_type(), + model_type=model_type_enum, model_name=model, name=credential_record.credential_name, encrypted_config=credential_record.encrypted_config, @@ -460,7 +460,7 @@ class ModelLoadBalancingService: load_balancing_model_config = LoadBalancingModelConfig( tenant_id=tenant_id, provider_name=provider_configuration.provider.provider, - model_type=model_type_enum.to_origin_model_type(), + model_type=model_type_enum, model_name=model, name=name, encrypted_config=json.dumps(credentials), @@ -515,7 +515,7 @@ class ModelLoadBalancingService: .where( LoadBalancingModelConfig.tenant_id == tenant_id, LoadBalancingModelConfig.provider_name == provider, - LoadBalancingModelConfig.model_type == model_type_enum.to_origin_model_type(), + LoadBalancingModelConfig.model_type == model_type_enum, LoadBalancingModelConfig.model_name == model, LoadBalancingModelConfig.id == config_id, ) diff --git a/api/tests/test_containers_integration_tests/services/test_model_load_balancing_service.py b/api/tests/test_containers_integration_tests/services/test_model_load_balancing_service.py index ca6e7afeab..aca3839135 100644 --- a/api/tests/test_containers_integration_tests/services/test_model_load_balancing_service.py +++ b/api/tests/test_containers_integration_tests/services/test_model_load_balancing_service.py @@ -141,7 +141,7 @@ class TestModelLoadBalancingService: tenant_id=tenant_id, provider_name="openai", model_name="gpt-3.5-turbo", - model_type="text-generation", # Use the origin model type that matches the query + model_type="llm", enabled=True, load_balancing_enabled=False, ) @@ -298,7 +298,7 @@ class TestModelLoadBalancingService: tenant_id=tenant.id, provider_name="openai", model_name="gpt-3.5-turbo", - model_type="text-generation", # Use the origin model type that matches the query + model_type="llm", name="config1", encrypted_config='{"api_key": "test_key"}', enabled=True, @@ -417,7 +417,7 @@ class TestModelLoadBalancingService: tenant_id=tenant.id, provider_name="openai", model_name="gpt-3.5-turbo", - model_type="text-generation", # Use the origin model type that matches the query + model_type="llm", name="config1", encrypted_config='{"api_key": "test_key"}', enabled=True, diff --git a/api/tests/unit_tests/core/test_provider_manager.py b/api/tests/unit_tests/core/test_provider_manager.py index 259cb5fdd0..ee26172459 100644 --- a/api/tests/unit_tests/core/test_provider_manager.py +++ b/api/tests/unit_tests/core/test_provider_manager.py @@ -48,7 +48,7 @@ def test__to_model_settings(mocker: MockerFixture, mock_provider_entity): tenant_id="tenant_id", provider_name="openai", model_name="gpt-4", - model_type="text-generation", + model_type="llm", enabled=True, load_balancing_enabled=True, ) @@ -61,7 +61,7 @@ def test__to_model_settings(mocker: MockerFixture, mock_provider_entity): tenant_id="tenant_id", provider_name="openai", model_name="gpt-4", - model_type="text-generation", + model_type="llm", name="__inherit__", encrypted_config=None, enabled=True, @@ -70,7 +70,7 @@ def test__to_model_settings(mocker: MockerFixture, mock_provider_entity): tenant_id="tenant_id", provider_name="openai", model_name="gpt-4", - model_type="text-generation", + model_type="llm", name="first", encrypted_config='{"openai_api_key": "fake_key"}', enabled=True, @@ -110,7 +110,7 @@ def test__to_model_settings_only_one_lb(mocker: MockerFixture, mock_provider_ent tenant_id="tenant_id", provider_name="openai", model_name="gpt-4", - model_type="text-generation", + model_type="llm", enabled=True, load_balancing_enabled=True, ) @@ -121,7 +121,7 @@ def test__to_model_settings_only_one_lb(mocker: MockerFixture, mock_provider_ent tenant_id="tenant_id", provider_name="openai", model_name="gpt-4", - model_type="text-generation", + model_type="llm", name="__inherit__", encrypted_config=None, enabled=True, @@ -157,7 +157,7 @@ def test__to_model_settings_lb_disabled(mocker: MockerFixture, mock_provider_ent tenant_id="tenant_id", provider_name="openai", model_name="gpt-4", - model_type="text-generation", + model_type="llm", enabled=True, load_balancing_enabled=False, ) @@ -168,7 +168,7 @@ def test__to_model_settings_lb_disabled(mocker: MockerFixture, mock_provider_ent tenant_id="tenant_id", provider_name="openai", model_name="gpt-4", - model_type="text-generation", + model_type="llm", name="__inherit__", encrypted_config=None, enabled=True, @@ -177,7 +177,7 @@ def test__to_model_settings_lb_disabled(mocker: MockerFixture, mock_provider_ent tenant_id="tenant_id", provider_name="openai", model_name="gpt-4", - model_type="text-generation", + model_type="llm", name="first", encrypted_config='{"openai_api_key": "fake_key"}', enabled=True, @@ -270,7 +270,7 @@ def test_get_default_model_uses_injected_runtime_for_existing_default_record(moc tenant_id="tenant-id", provider_name="openai", model_name="gpt-4", - model_type=ModelType.LLM.to_origin_model_type(), + model_type=ModelType.LLM, ) mock_session = Mock() mock_session.scalar.return_value = existing_default_model @@ -449,7 +449,7 @@ def test_update_default_model_record_updates_existing_record(mocker: MockerFixtu tenant_id="tenant-id", provider_name="anthropic", model_name="claude-3-sonnet", - model_type=ModelType.LLM.to_origin_model_type(), + model_type=ModelType.LLM, ) mock_session = Mock() mock_session.scalar.return_value = existing_default_model @@ -487,7 +487,7 @@ def test_update_default_model_record_creates_record_with_origin_model_type(mocke assert created_default_model.tenant_id == "tenant-id" assert created_default_model.provider_name == "openai" assert created_default_model.model_name == "gpt-4" - assert created_default_model.model_type == ModelType.LLM.to_origin_model_type() + assert created_default_model.model_type == ModelType.LLM mock_session.commit.assert_called_once() diff --git a/api/tests/unit_tests/services/test_model_load_balancing_service.py b/api/tests/unit_tests/services/test_model_load_balancing_service.py index b43e79dff5..f85f1ace16 100644 --- a/api/tests/unit_tests/services/test_model_load_balancing_service.py +++ b/api/tests/unit_tests/services/test_model_load_balancing_service.py @@ -317,7 +317,7 @@ def test_init_inherit_config_should_create_and_persist_inherit_configuration( assert inherit_config.tenant_id == "tenant-1" assert inherit_config.provider_name == "openai" assert inherit_config.model_name == "gpt-4o-mini" - assert inherit_config.model_type == "text-generation" + assert inherit_config.model_type == "llm" assert inherit_config.name == "__inherit__" mock_db.session.add.assert_called_once_with(inherit_config) mock_db.session.commit.assert_called_once() From bbc3f90928bd167f9cfd5eb3a3001b228fd5d0e0 Mon Sep 17 00:00:00 2001 From: -LAN- Date: Tue, 31 Mar 2026 09:51:38 +0800 Subject: [PATCH 23/40] chore(ci): move full VDB matrix off the PR path (#34216) Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .github/workflows/vdb-tests-full.yml | 95 ++++++++++++++++++++++++++++ .github/workflows/vdb-tests.yml | 25 ++++---- 2 files changed, 109 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/vdb-tests-full.yml diff --git a/.github/workflows/vdb-tests-full.yml b/.github/workflows/vdb-tests-full.yml new file mode 100644 index 0000000000..01d25902f6 --- /dev/null +++ b/.github/workflows/vdb-tests-full.yml @@ -0,0 +1,95 @@ +name: Run Full VDB Tests + +on: + schedule: + - cron: '0 3 * * 1' + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: vdb-tests-full-${{ github.ref || github.run_id }} + cancel-in-progress: true + +jobs: + test: + name: Full VDB Tests + if: github.repository == 'langgenius/dify' + runs-on: ubuntu-latest + strategy: + matrix: + python-version: + - "3.12" + + steps: + - name: Checkout code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Free Disk Space + uses: endersonmenezes/free-disk-space@7901478139cff6e9d44df5972fd8ab8fcade4db1 # v3.2.2 + with: + remove_dotnet: true + remove_haskell: true + remove_tool_cache: true + + - name: Setup UV and Python + uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 + with: + enable-cache: true + python-version: ${{ matrix.python-version }} + cache-dependency-glob: api/uv.lock + + - name: Check UV lockfile + run: uv lock --project api --check + + - name: Install dependencies + run: uv sync --project api --dev + + - name: Set up dotenvs + run: | + cp docker/.env.example docker/.env + cp docker/middleware.env.example docker/middleware.env + + - name: Expose Service Ports + run: sh .github/workflows/expose_service_ports.sh + +# - name: Set up Vector Store (TiDB) +# uses: hoverkraft-tech/compose-action@v2.0.2 +# with: +# compose-file: docker/tidb/docker-compose.yaml +# services: | +# tidb +# tiflash + + - name: Set up Full Vector Store Matrix + uses: hoverkraft-tech/compose-action@4894d2492015c1774ee5a13a95b1072093087ec3 # v2.5.0 + with: + compose-file: | + docker/docker-compose.yaml + services: | + weaviate + qdrant + couchbase-server + etcd + minio + milvus-standalone + pgvecto-rs + pgvector + chroma + elasticsearch + oceanbase + + - name: setup test config + run: | + echo $(pwd) + ls -lah . + cp api/tests/integration_tests/.env.example api/tests/integration_tests/.env + +# - name: Check VDB Ready (TiDB) +# run: uv run --project api python api/tests/integration_tests/vdb/tidb_vector/check_tiflash_ready.py + + - name: Test Vector Stores + run: uv run --project api bash dev/pytest/pytest_vdb.sh diff --git a/.github/workflows/vdb-tests.yml b/.github/workflows/vdb-tests.yml index 026ff0fe57..47ec70f603 100644 --- a/.github/workflows/vdb-tests.yml +++ b/.github/workflows/vdb-tests.yml @@ -1,15 +1,18 @@ -name: Run VDB Tests +name: Run VDB Smoke Tests on: workflow_call: +permissions: + contents: read + concurrency: group: vdb-tests-${{ github.head_ref || github.run_id }} cancel-in-progress: true jobs: test: - name: VDB Tests + name: VDB Smoke Tests runs-on: ubuntu-latest strategy: matrix: @@ -58,23 +61,18 @@ jobs: # tidb # tiflash - - name: Set up Vector Stores (Weaviate, Qdrant, PGVector, Milvus, PgVecto-RS, Chroma, MyScale, ElasticSearch, Couchbase, OceanBase) + - name: Set up Vector Stores for Smoke Coverage uses: hoverkraft-tech/compose-action@4894d2492015c1774ee5a13a95b1072093087ec3 # v2.5.0 with: compose-file: | docker/docker-compose.yaml services: | + db_postgres + redis weaviate qdrant - couchbase-server - etcd - minio - milvus-standalone - pgvecto-rs pgvector chroma - elasticsearch - oceanbase - name: setup test config run: | @@ -86,4 +84,9 @@ jobs: # run: uv run --project api python api/tests/integration_tests/vdb/tidb_vector/check_tiflash_ready.py - name: Test Vector Stores - run: uv run --project api bash dev/pytest/pytest_vdb.sh + run: | + uv run --project api pytest --timeout "${PYTEST_TIMEOUT:-180}" \ + api/tests/integration_tests/vdb/chroma \ + api/tests/integration_tests/vdb/pgvector \ + api/tests/integration_tests/vdb/qdrant \ + api/tests/integration_tests/vdb/weaviate From 323c51e095a81ec0e12d4391aa3eb14b98ed92f4 Mon Sep 17 00:00:00 2001 From: Linchengyi Date: Tue, 31 Mar 2026 09:52:45 +0800 Subject: [PATCH 24/40] fix: bridge Dify design tokens for streamdown table fullscreen (#34224) --- web/app/styles/markdown.css | 38 +++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/web/app/styles/markdown.css b/web/app/styles/markdown.css index 368c3718af..48aaf965ab 100644 --- a/web/app/styles/markdown.css +++ b/web/app/styles/markdown.css @@ -582,6 +582,44 @@ background-color: var(--color-components-menu-item-bg-hover); } +[data-streamdown="table-fullscreen"] { + background-color: var(--color-components-panel-bg); + color: var(--color-text-primary); +} + +[data-streamdown="table-fullscreen"] button { + color: var(--color-text-tertiary); +} + +[data-streamdown="table-fullscreen"] button:hover { + color: var(--color-text-primary); + background-color: var(--color-background-section-burn); +} + +[data-streamdown="table-fullscreen"] table[data-streamdown="table"] { + border-color: var(--color-divider-regular); +} + +[data-streamdown="table-fullscreen"] [data-streamdown="table-header"] { + background-color: var(--color-background-section-burn); +} + +[data-streamdown="table-fullscreen"] [data-streamdown="table-header"] th { + color: var(--color-text-tertiary); +} + +[data-streamdown="table-fullscreen"] [data-streamdown="table-body"] { + border-color: var(--color-divider-subtle); +} + +[data-streamdown="table-fullscreen"] [data-streamdown="table-body"] > tr { + border-color: var(--color-divider-subtle); +} + +[data-streamdown="table-fullscreen"] [data-streamdown="table-body"] td { + color: var(--color-text-secondary); +} + .markdown-body table img { background-color: transparent; } From a19243068b7de40fbd52f50046fd19bb575adbcd Mon Sep 17 00:00:00 2001 From: fisherOne1 Date: Tue, 31 Mar 2026 10:07:37 +0800 Subject: [PATCH 25/40] fix(web): fix document detail page status inconsistency with list page (#33740) Co-authored-by: fisher <1186907891@qq.com> Co-authored-by: Wu Tianwei <30284043+WTW0313@users.noreply.github.com> Co-authored-by: Crazywoola <100913391+crazywoola@users.noreply.github.com> --- .../datasets/documents/detail/index.tsx | 105 +++++++++++------- web/service/knowledge/use-document.ts | 6 +- 2 files changed, 69 insertions(+), 42 deletions(-) diff --git a/web/app/components/datasets/documents/detail/index.tsx b/web/app/components/datasets/documents/detail/index.tsx index 891c177169..cf9aa62fab 100644 --- a/web/app/components/datasets/documents/detail/index.tsx +++ b/web/app/components/datasets/documents/detail/index.tsx @@ -1,8 +1,8 @@ 'use client' import type { FC } from 'react' -import type { DataSourceInfo, FileItem, FullDocumentDetail, LegacyDataSourceInfo } from '@/models/datasets' +import type { DataSourceInfo, DocumentDisplayStatus, FileItem, FullDocumentDetail, LegacyDataSourceInfo } from '@/models/datasets' import * as React from 'react' -import { useMemo, useState } from 'react' +import { useCallback, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import Divider from '@/app/components/base/divider' import FloatRightContainer from '@/app/components/base/float-right-container' @@ -11,7 +11,7 @@ import Toast from '@/app/components/base/toast' import Metadata from '@/app/components/datasets/metadata/metadata-document' import { useDatasetDetailContextWithSelector } from '@/context/dataset-detail' import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' -import { ChunkingMode } from '@/models/datasets' +import { ChunkingMode, DisplayStatusList } from '@/models/datasets' import { useRouter, useSearchParams } from '@/next/navigation' import { useDocumentDetail, useDocumentMetadata, useInvalidDocumentList } from '@/service/knowledge/use-document' import { useCheckSegmentBatchImportProgress, useChildSegmentListKey, useSegmentBatchImport, useSegmentListKey } from '@/service/knowledge/use-segment' @@ -32,6 +32,14 @@ type DocumentDetailProps = { documentId: string } +const NON_TERMINAL_DISPLAY_STATUSES = new Set( + DisplayStatusList.filter(s => s === 'queuing' || s === 'indexing' || s === 'paused'), +) + +const isLegacyDataSourceInfo = (info?: DataSourceInfo): info is LegacyDataSourceInfo => { + return !!info && 'upload_file' in info +} + const DocumentDetail: FC = ({ datasetId, documentId }) => { const router = useRouter() const searchParams = useSearchParams() @@ -89,6 +97,12 @@ const DocumentDetail: FC = ({ datasetId, documentId }) => { datasetId, documentId, params: { metadata: 'without' }, + refetchInterval: (query) => { + const status = query.state.data?.display_status + if (!status || NON_TERMINAL_DISPLAY_STATUSES.has(status)) + return 2500 + return false + }, }) const { data: documentMetadata } = useDocumentMetadata({ @@ -97,19 +111,15 @@ const DocumentDetail: FC = ({ datasetId, documentId }) => { params: { metadata: 'only' }, }) - const backToPrev = () => { + const backToPrev = useCallback(() => { const queryString = searchParams.toString() const backPath = `/datasets/${datasetId}/documents${queryString ? `?${queryString}` : ''}` router.push(backPath) - } + }, [searchParams, datasetId, router]) const isDetailLoading = !documentDetail && !error - const embedding = ['queuing', 'indexing', 'paused'].includes((documentDetail?.display_status || '').toLowerCase()) - - const isLegacyDataSourceInfo = (info?: DataSourceInfo): info is LegacyDataSourceInfo => { - return !!info && 'upload_file' in info - } + const embedding = NON_TERMINAL_DISPLAY_STATUSES.has(documentDetail?.display_status as DocumentDisplayStatus) const documentUploadFile = useMemo(() => { if (!documentDetail?.data_source_info) @@ -123,7 +133,7 @@ const DocumentDetail: FC = ({ datasetId, documentId }) => { const invalidChildChunkList = useInvalid(useChildSegmentListKey) const invalidDocumentList = useInvalidDocumentList(datasetId) - const handleOperate = (operateName?: string) => { + const handleOperate = useCallback((operateName?: string) => { invalidDocumentList() if (operateName === 'delete') { backToPrev() @@ -138,7 +148,7 @@ const DocumentDetail: FC = ({ datasetId, documentId }) => { }, 5000) } } - } + }, [invalidDocumentList, backToPrev, detailMutate, invalidChunkList, invalidChildChunkList]) const parentMode = useMemo(() => { return documentDetail?.document_process_rule?.rules?.parent_mode || documentDetail?.dataset_process_rule?.rules?.parent_mode || 'paragraph' @@ -149,19 +159,41 @@ const DocumentDetail: FC = ({ datasetId, documentId }) => { return chunkMode === ChunkingMode.parentChild && parentMode === 'full-doc' }, [documentDetail?.doc_form, parentMode]) + const contextValue = useMemo(() => ({ + datasetId, + documentId, + docForm: documentDetail?.doc_form as ChunkingMode, + parentMode, + }), [datasetId, documentId, documentDetail?.doc_form, parentMode]) + + const statusDetail = useMemo(() => ({ + enabled: documentDetail?.enabled || false, + archived: documentDetail?.archived || false, + id: documentId, + }), [documentDetail?.enabled, documentDetail?.archived, documentId]) + + const operationsDetail = useMemo(() => ({ + name: documentDetail?.name || '', + enabled: documentDetail?.enabled || false, + archived: documentDetail?.archived || false, + id: documentId, + data_source_type: documentDetail?.data_source_type || '', + doc_form: documentDetail?.doc_form || '', + }), [documentDetail?.name, documentDetail?.enabled, documentDetail?.archived, documentId, documentDetail?.data_source_type, documentDetail?.doc_form]) + + const docDetail = useMemo(() => ({ + ...documentDetail, + ...documentMetadata, + doc_type: documentMetadata?.doc_type === 'others' ? '' : documentMetadata?.doc_type, + } as FullDocumentDetail), [documentDetail, documentMetadata]) + const backButtonLabel = t('operation.back', { ns: 'common' }) const metadataToggleLabel = `${showMetadata ? t('operation.close', { ns: 'common' }) : t('operation.view', { ns: 'common' })} ${t('metadata.title', { ns: 'datasetDocuments' })}` return ( - +
diff --git a/web/service/knowledge/use-document.ts b/web/service/knowledge/use-document.ts index 4eb2b7d282..6e48d7b6f4 100644 --- a/web/service/knowledge/use-document.ts +++ b/web/service/knowledge/use-document.ts @@ -133,15 +133,19 @@ export const useSyncWebsite = () => { } const useDocumentDetailKey = [NAME_SPACE, 'documentDetail', 'withoutMetaData'] +type DocumentDetailRefetchInterval = UseQueryOptions['refetchInterval'] + export const useDocumentDetail = (payload: { datasetId: string documentId: string params: { metadata: MetadataType } + refetchInterval?: DocumentDetailRefetchInterval }) => { - const { datasetId, documentId, params } = payload + const { datasetId, documentId, params, refetchInterval } = payload return useQuery({ queryKey: [...useDocumentDetailKey, 'withoutMetaData', datasetId, documentId, params], queryFn: () => get(`/datasets/${datasetId}/documents/${documentId}`, { params }), + refetchInterval, }) } From f0e6f11c1c871d794b124c2bc41c9099d7508df2 Mon Sep 17 00:00:00 2001 From: Asuka Minato Date: Tue, 31 Mar 2026 11:11:21 +0900 Subject: [PATCH 26/40] fix: silent diff when number count are the same (#34097) --- .github/workflows/pyrefly-diff.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pyrefly-diff.yml b/.github/workflows/pyrefly-diff.yml index 0b2a7b8e9e..8623d35b04 100644 --- a/.github/workflows/pyrefly-diff.yml +++ b/.github/workflows/pyrefly-diff.yml @@ -50,6 +50,17 @@ jobs: run: | diff -u /tmp/pyrefly_base.txt /tmp/pyrefly_pr.txt > pyrefly_diff.txt || true + - name: Check if line counts match + id: line_count_check + run: | + base_lines=$(wc -l < /tmp/pyrefly_base.txt) + pr_lines=$(wc -l < /tmp/pyrefly_pr.txt) + if [ "$base_lines" -eq "$pr_lines" ]; then + echo "same=true" >> $GITHUB_OUTPUT + else + echo "same=false" >> $GITHUB_OUTPUT + fi + - name: Save PR number run: | echo ${{ github.event.pull_request.number }} > pr_number.txt @@ -63,7 +74,7 @@ jobs: pr_number.txt - name: Comment PR with pyrefly diff - if: ${{ github.event.pull_request.head.repo.full_name == github.repository }} + if: ${{ github.event.pull_request.head.repo.full_name == github.repository && steps.line_count_check.outputs.same == 'false' }} uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} From f7b78b08fd2adc12980606a4a975aae840ae5e7e Mon Sep 17 00:00:00 2001 From: wangji0923 Date: Tue, 31 Mar 2026 10:13:31 +0800 Subject: [PATCH 27/40] refactor(api): narrow otel instrumentor typing (#33853) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 复试资料 Co-authored-by: Asuka Minato --- api/extensions/otel/instrumentation.py | 44 +++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/api/extensions/otel/instrumentation.py b/api/extensions/otel/instrumentation.py index b73ba8df8c..0a70f6ebe9 100644 --- a/api/extensions/otel/instrumentation.py +++ b/api/extensions/otel/instrumentation.py @@ -1,5 +1,7 @@ import contextlib import logging +from collections.abc import Callable +from typing import Protocol, cast import flask from opentelemetry.instrumentation.celery import CeleryInstrumentor @@ -21,6 +23,38 @@ from extensions.otel.runtime import is_celery_worker logger = logging.getLogger(__name__) +class SupportsInstrument(Protocol): + def instrument(self, **kwargs: object) -> None: ... + + +class SupportsFlaskInstrumentor(Protocol): + def instrument_app( + self, app: DifyApp, response_hook: Callable[[Span, str, list], None] | None = None, **kwargs: object + ) -> None: ... + + +# Some OpenTelemetry instrumentor constructors are typed loosely enough that +# pyrefly infers `NoneType`. Narrow the instances to just the methods we use +# while leaving runtime behavior unchanged. +def _new_celery_instrumentor() -> SupportsInstrument: + return cast( + SupportsInstrument, + CeleryInstrumentor(tracer_provider=get_tracer_provider(), meter_provider=get_meter_provider()), + ) + + +def _new_httpx_instrumentor() -> SupportsInstrument: + return cast(SupportsInstrument, HTTPXClientInstrumentor()) + + +def _new_redis_instrumentor() -> SupportsInstrument: + return cast(SupportsInstrument, RedisInstrumentor()) + + +def _new_sqlalchemy_instrumentor() -> SupportsInstrument: + return cast(SupportsInstrument, SQLAlchemyInstrumentor()) + + class ExceptionLoggingHandler(logging.Handler): """ Handler that records exceptions to the current OpenTelemetry span. @@ -97,7 +131,7 @@ def init_flask_instrumentor(app: DifyApp) -> None: from opentelemetry.instrumentation.flask import FlaskInstrumentor - instrumentor = FlaskInstrumentor() + instrumentor = cast(SupportsFlaskInstrumentor, FlaskInstrumentor()) if dify_config.DEBUG: logger.info("Initializing Flask instrumentor") instrumentor.instrument_app(app, response_hook=response_hook) @@ -106,21 +140,21 @@ def init_flask_instrumentor(app: DifyApp) -> None: def init_sqlalchemy_instrumentor(app: DifyApp) -> None: with app.app_context(): engines = list(app.extensions["sqlalchemy"].engines.values()) - SQLAlchemyInstrumentor().instrument(enable_commenter=True, engines=engines) + _new_sqlalchemy_instrumentor().instrument(enable_commenter=True, engines=engines) def init_redis_instrumentor() -> None: - RedisInstrumentor().instrument() + _new_redis_instrumentor().instrument() def init_httpx_instrumentor() -> None: - HTTPXClientInstrumentor().instrument() + _new_httpx_instrumentor().instrument() def init_instruments(app: DifyApp) -> None: if not is_celery_worker(): init_flask_instrumentor(app) - CeleryInstrumentor(tracer_provider=get_tracer_provider(), meter_provider=get_meter_provider()).instrument() + _new_celery_instrumentor().instrument() instrument_exception_logging() init_sqlalchemy_instrumentor(app) From 2c2cc72150af67410426f66b491200a9b25c7ab7 Mon Sep 17 00:00:00 2001 From: Jordan Date: Tue, 31 Mar 2026 11:20:21 +0900 Subject: [PATCH 28/40] fix(http): expose structured vars in HTTP body selector (#34185) Co-authored-by: Jordan <175169034+owldev127@users.noreply.github.com> --- .../http/components/edit-body/index.spec.tsx | 30 +++++++++++++++++++ .../nodes/http/components/edit-body/index.tsx | 3 +- .../edit-body/supported-body-vars.ts | 15 ++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 web/app/components/workflow/nodes/http/components/edit-body/index.spec.tsx create mode 100644 web/app/components/workflow/nodes/http/components/edit-body/supported-body-vars.ts diff --git a/web/app/components/workflow/nodes/http/components/edit-body/index.spec.tsx b/web/app/components/workflow/nodes/http/components/edit-body/index.spec.tsx new file mode 100644 index 0000000000..a3078464b8 --- /dev/null +++ b/web/app/components/workflow/nodes/http/components/edit-body/index.spec.tsx @@ -0,0 +1,30 @@ +import { describe, expect, it } from 'vitest' +import { VarType } from '@/app/components/workflow/types' +import { + HTTP_BODY_VARIABLE_TYPES, + isSupportedHttpBodyVariable, +} from './supported-body-vars' + +describe('HTTP body variable support', () => { + it('should include structured variables in the selector', () => { + expect(HTTP_BODY_VARIABLE_TYPES).toEqual([ + VarType.string, + VarType.number, + VarType.secret, + VarType.object, + VarType.arrayNumber, + VarType.arrayString, + VarType.arrayObject, + ]) + }) + + it('should accept object and array object variables', () => { + expect(isSupportedHttpBodyVariable(VarType.object)).toBe(true) + expect(isSupportedHttpBodyVariable(VarType.arrayObject)).toBe(true) + }) + + it('should keep unsupported file variables excluded', () => { + expect(isSupportedHttpBodyVariable(VarType.file)).toBe(false) + expect(isSupportedHttpBodyVariable(VarType.arrayFile)).toBe(false) + }) +}) diff --git a/web/app/components/workflow/nodes/http/components/edit-body/index.tsx b/web/app/components/workflow/nodes/http/components/edit-body/index.tsx index 90c230b6bb..7e44ad5aeb 100644 --- a/web/app/components/workflow/nodes/http/components/edit-body/index.tsx +++ b/web/app/components/workflow/nodes/http/components/edit-body/index.tsx @@ -13,6 +13,7 @@ import VarReferencePicker from '../../../_base/components/variable/var-reference import useAvailableVarList from '../../../_base/hooks/use-available-var-list' import { BodyPayloadValueType, BodyType } from '../../types' import KeyValue from '../key-value' +import { isSupportedHttpBodyVariable } from './supported-body-vars' const UNIQUE_ID_PREFIX = 'key-value-' @@ -58,7 +59,7 @@ const EditBody: FC = ({ const { availableVars, availableNodes } = useAvailableVarList(nodeId, { onlyLeafNodeVar: false, filterVar: (varPayload: Var) => { - return [VarType.string, VarType.number, VarType.secret, VarType.arrayNumber, VarType.arrayString].includes(varPayload.type) + return isSupportedHttpBodyVariable(varPayload.type) }, }) diff --git a/web/app/components/workflow/nodes/http/components/edit-body/supported-body-vars.ts b/web/app/components/workflow/nodes/http/components/edit-body/supported-body-vars.ts new file mode 100644 index 0000000000..416777abfa --- /dev/null +++ b/web/app/components/workflow/nodes/http/components/edit-body/supported-body-vars.ts @@ -0,0 +1,15 @@ +import { VarType } from '@/app/components/workflow/types' + +export const HTTP_BODY_VARIABLE_TYPES: VarType[] = [ + VarType.string, + VarType.number, + VarType.secret, + VarType.object, + VarType.arrayNumber, + VarType.arrayString, + VarType.arrayObject, +] + +export const isSupportedHttpBodyVariable = (type: VarType) => { + return HTTP_BODY_VARIABLE_TYPES.includes(type) +} From 01c857a67ab74e70af35b85d84bb5a093d76d083 Mon Sep 17 00:00:00 2001 From: Dominic <161279854+dominciyue@users.noreply.github.com> Date: Tue, 31 Mar 2026 10:20:45 +0800 Subject: [PATCH 29/40] fix(dev): load middleware env in start-docker-compose (#33927) --- dev/start-docker-compose | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dev/start-docker-compose b/dev/start-docker-compose index 9652be169d..aa4f66a6cf 100755 --- a/dev/start-docker-compose +++ b/dev/start-docker-compose @@ -1,8 +1,8 @@ -#!/usr/bin/env bash -set -euo pipefail - -SCRIPT_DIR="$(dirname "$(realpath "$0")")" -ROOT="$(dirname "$SCRIPT_DIR")" - -cd "$ROOT/docker" -docker compose -f docker-compose.middleware.yaml --profile postgresql --profile weaviate -p dify up -d +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(dirname "$(realpath "$0")")" +ROOT="$(dirname "$SCRIPT_DIR")" + +cd "$ROOT/docker" +docker compose --env-file middleware.env -f docker-compose.middleware.yaml -p dify up -d From 7e4754392d74dcfbf976cac16b3c2ead1b9aaace Mon Sep 17 00:00:00 2001 From: Weichen Zhao <61238101+SeasonPilot@users.noreply.github.com> Date: Tue, 31 Mar 2026 10:17:47 +0800 Subject: [PATCH 30/40] feat: increase default celery worker concurrency to 4 (#33105) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Crazywoola <100913391+crazywoola@users.noreply.github.com> --- docker/.env.example | 6 ++++-- docker/docker-compose.yaml | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docker/.env.example b/docker/.env.example index 9fbf9a9e72..b2d6244b46 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -186,8 +186,10 @@ CELERY_WORKER_CLASS= # it is recommended to set it to 360 to support a longer sse connection time. GUNICORN_TIMEOUT=360 -# The number of Celery workers. The default is 1, and can be set as needed. -CELERY_WORKER_AMOUNT= +# The number of Celery workers. The default is 4 for development environments +# to allow parallel processing of workflows, document indexing, and other async tasks. +# Adjust based on your system resources and workload requirements. +CELERY_WORKER_AMOUNT=4 # Flag indicating whether to enable autoscaling of Celery workers. # diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index 737a62020c..ed68107f46 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -46,7 +46,7 @@ x-shared-env: &shared-api-worker-env SERVER_WORKER_CONNECTIONS: ${SERVER_WORKER_CONNECTIONS:-10} CELERY_WORKER_CLASS: ${CELERY_WORKER_CLASS:-} GUNICORN_TIMEOUT: ${GUNICORN_TIMEOUT:-360} - CELERY_WORKER_AMOUNT: ${CELERY_WORKER_AMOUNT:-} + CELERY_WORKER_AMOUNT: ${CELERY_WORKER_AMOUNT:-4} CELERY_AUTO_SCALE: ${CELERY_AUTO_SCALE:-false} CELERY_MAX_WORKERS: ${CELERY_MAX_WORKERS:-} CELERY_MIN_WORKERS: ${CELERY_MIN_WORKERS:-} From 2de818530bf384dff43d473456a2e09ea60190f1 Mon Sep 17 00:00:00 2001 From: Dev Sharma <50591491+cryptus-neoxys@users.noreply.github.com> Date: Tue, 31 Mar 2026 08:46:42 +0530 Subject: [PATCH 31/40] test: add tests for api/services retention, enterprise, plugin (#32648) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: QuantumGhost --- .../services/plugin/__init__.py | 0 .../services/plugin/test_plugin_lifecycle.py | 182 ++++++ .../services/retention/__init__.py | 0 .../retention/test_messages_clean_service.py | 348 ++++++++++ .../retention/test_workflow_run_archiver.py | 177 ++++++ .../enterprise/test_enterprise_service.py | 170 +++++ .../enterprise/test_plugin_manager_service.py | 49 ++ .../test_plugin_auto_upgrade_service.py | 183 ++++++ .../plugin/test_plugin_permission_service.py | 75 +++ .../unit_tests/services/retention/__init__.py | 0 .../retention/test_messages_clean_policy.py | 135 ++++ .../tools/test_tools_transform_service.py | 598 ++++++++++++++++++ 12 files changed, 1917 insertions(+) create mode 100644 api/tests/integration_tests/services/plugin/__init__.py create mode 100644 api/tests/integration_tests/services/plugin/test_plugin_lifecycle.py create mode 100644 api/tests/integration_tests/services/retention/__init__.py create mode 100644 api/tests/integration_tests/services/retention/test_messages_clean_service.py create mode 100644 api/tests/integration_tests/services/retention/test_workflow_run_archiver.py create mode 100644 api/tests/unit_tests/services/plugin/test_plugin_auto_upgrade_service.py create mode 100644 api/tests/unit_tests/services/plugin/test_plugin_permission_service.py create mode 100644 api/tests/unit_tests/services/retention/__init__.py create mode 100644 api/tests/unit_tests/services/retention/test_messages_clean_policy.py create mode 100644 api/tests/unit_tests/services/tools/test_tools_transform_service.py diff --git a/api/tests/integration_tests/services/plugin/__init__.py b/api/tests/integration_tests/services/plugin/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/api/tests/integration_tests/services/plugin/test_plugin_lifecycle.py b/api/tests/integration_tests/services/plugin/test_plugin_lifecycle.py new file mode 100644 index 0000000000..951a5ab4b4 --- /dev/null +++ b/api/tests/integration_tests/services/plugin/test_plugin_lifecycle.py @@ -0,0 +1,182 @@ +import pytest +from sqlalchemy import delete + +from core.db.session_factory import session_factory +from models import Tenant +from models.account import TenantPluginAutoUpgradeStrategy, TenantPluginPermission +from services.plugin.plugin_auto_upgrade_service import PluginAutoUpgradeService +from services.plugin.plugin_permission_service import PluginPermissionService + + +@pytest.fixture +def tenant(flask_req_ctx): + with session_factory.create_session() as session: + t = Tenant(name="plugin_it_tenant") + session.add(t) + session.commit() + tenant_id = t.id + + yield tenant_id + + with session_factory.create_session() as session: + session.execute(delete(TenantPluginPermission).where(TenantPluginPermission.tenant_id == tenant_id)) + session.execute( + delete(TenantPluginAutoUpgradeStrategy).where(TenantPluginAutoUpgradeStrategy.tenant_id == tenant_id) + ) + session.execute(delete(Tenant).where(Tenant.id == tenant_id)) + session.commit() + + +class TestPluginPermissionLifecycle: + def test_get_returns_none_for_new_tenant(self, tenant): + assert PluginPermissionService.get_permission(tenant) is None + + def test_change_creates_row(self, tenant): + result = PluginPermissionService.change_permission( + tenant, + TenantPluginPermission.InstallPermission.ADMINS, + TenantPluginPermission.DebugPermission.EVERYONE, + ) + assert result is True + + perm = PluginPermissionService.get_permission(tenant) + assert perm is not None + assert perm.install_permission == TenantPluginPermission.InstallPermission.ADMINS + assert perm.debug_permission == TenantPluginPermission.DebugPermission.EVERYONE + + def test_change_updates_existing_row(self, tenant): + PluginPermissionService.change_permission( + tenant, + TenantPluginPermission.InstallPermission.ADMINS, + TenantPluginPermission.DebugPermission.NOBODY, + ) + PluginPermissionService.change_permission( + tenant, + TenantPluginPermission.InstallPermission.EVERYONE, + TenantPluginPermission.DebugPermission.ADMINS, + ) + perm = PluginPermissionService.get_permission(tenant) + assert perm is not None + assert perm.install_permission == TenantPluginPermission.InstallPermission.EVERYONE + assert perm.debug_permission == TenantPluginPermission.DebugPermission.ADMINS + + with session_factory.create_session() as session: + count = session.query(TenantPluginPermission).where(TenantPluginPermission.tenant_id == tenant).count() + assert count == 1 + + +class TestPluginAutoUpgradeLifecycle: + def test_get_returns_none_for_new_tenant(self, tenant): + assert PluginAutoUpgradeService.get_strategy(tenant) is None + + def test_change_creates_row(self, tenant): + result = PluginAutoUpgradeService.change_strategy( + tenant, + strategy_setting=TenantPluginAutoUpgradeStrategy.StrategySetting.LATEST, + upgrade_time_of_day=3, + upgrade_mode=TenantPluginAutoUpgradeStrategy.UpgradeMode.ALL, + exclude_plugins=[], + include_plugins=[], + ) + assert result is True + + strategy = PluginAutoUpgradeService.get_strategy(tenant) + assert strategy is not None + assert strategy.strategy_setting == TenantPluginAutoUpgradeStrategy.StrategySetting.LATEST + assert strategy.upgrade_time_of_day == 3 + + def test_change_updates_existing_row(self, tenant): + PluginAutoUpgradeService.change_strategy( + tenant, + strategy_setting=TenantPluginAutoUpgradeStrategy.StrategySetting.FIX_ONLY, + upgrade_time_of_day=0, + upgrade_mode=TenantPluginAutoUpgradeStrategy.UpgradeMode.ALL, + exclude_plugins=[], + include_plugins=[], + ) + PluginAutoUpgradeService.change_strategy( + tenant, + strategy_setting=TenantPluginAutoUpgradeStrategy.StrategySetting.LATEST, + upgrade_time_of_day=12, + upgrade_mode=TenantPluginAutoUpgradeStrategy.UpgradeMode.PARTIAL, + exclude_plugins=[], + include_plugins=["plugin-a"], + ) + + strategy = PluginAutoUpgradeService.get_strategy(tenant) + assert strategy is not None + assert strategy.strategy_setting == TenantPluginAutoUpgradeStrategy.StrategySetting.LATEST + assert strategy.upgrade_time_of_day == 12 + assert strategy.upgrade_mode == TenantPluginAutoUpgradeStrategy.UpgradeMode.PARTIAL + assert strategy.include_plugins == ["plugin-a"] + + def test_exclude_plugin_creates_strategy_when_none_exists(self, tenant): + PluginAutoUpgradeService.exclude_plugin(tenant, "my-plugin") + + strategy = PluginAutoUpgradeService.get_strategy(tenant) + assert strategy is not None + assert strategy.upgrade_mode == TenantPluginAutoUpgradeStrategy.UpgradeMode.EXCLUDE + assert "my-plugin" in strategy.exclude_plugins + + def test_exclude_plugin_appends_in_exclude_mode(self, tenant): + PluginAutoUpgradeService.change_strategy( + tenant, + strategy_setting=TenantPluginAutoUpgradeStrategy.StrategySetting.FIX_ONLY, + upgrade_time_of_day=0, + upgrade_mode=TenantPluginAutoUpgradeStrategy.UpgradeMode.EXCLUDE, + exclude_plugins=["existing"], + include_plugins=[], + ) + PluginAutoUpgradeService.exclude_plugin(tenant, "new-plugin") + + strategy = PluginAutoUpgradeService.get_strategy(tenant) + assert strategy is not None + assert "existing" in strategy.exclude_plugins + assert "new-plugin" in strategy.exclude_plugins + + def test_exclude_plugin_dedup_in_exclude_mode(self, tenant): + PluginAutoUpgradeService.change_strategy( + tenant, + strategy_setting=TenantPluginAutoUpgradeStrategy.StrategySetting.FIX_ONLY, + upgrade_time_of_day=0, + upgrade_mode=TenantPluginAutoUpgradeStrategy.UpgradeMode.EXCLUDE, + exclude_plugins=["same-plugin"], + include_plugins=[], + ) + PluginAutoUpgradeService.exclude_plugin(tenant, "same-plugin") + + strategy = PluginAutoUpgradeService.get_strategy(tenant) + assert strategy is not None + assert strategy.exclude_plugins.count("same-plugin") == 1 + + def test_exclude_from_partial_mode_removes_from_include(self, tenant): + PluginAutoUpgradeService.change_strategy( + tenant, + strategy_setting=TenantPluginAutoUpgradeStrategy.StrategySetting.FIX_ONLY, + upgrade_time_of_day=0, + upgrade_mode=TenantPluginAutoUpgradeStrategy.UpgradeMode.PARTIAL, + exclude_plugins=[], + include_plugins=["p1", "p2"], + ) + PluginAutoUpgradeService.exclude_plugin(tenant, "p1") + + strategy = PluginAutoUpgradeService.get_strategy(tenant) + assert strategy is not None + assert "p1" not in strategy.include_plugins + assert "p2" in strategy.include_plugins + + def test_exclude_from_all_mode_switches_to_exclude(self, tenant): + PluginAutoUpgradeService.change_strategy( + tenant, + strategy_setting=TenantPluginAutoUpgradeStrategy.StrategySetting.LATEST, + upgrade_time_of_day=0, + upgrade_mode=TenantPluginAutoUpgradeStrategy.UpgradeMode.ALL, + exclude_plugins=[], + include_plugins=[], + ) + PluginAutoUpgradeService.exclude_plugin(tenant, "excluded-plugin") + + strategy = PluginAutoUpgradeService.get_strategy(tenant) + assert strategy is not None + assert strategy.upgrade_mode == TenantPluginAutoUpgradeStrategy.UpgradeMode.EXCLUDE + assert "excluded-plugin" in strategy.exclude_plugins diff --git a/api/tests/integration_tests/services/retention/__init__.py b/api/tests/integration_tests/services/retention/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/api/tests/integration_tests/services/retention/test_messages_clean_service.py b/api/tests/integration_tests/services/retention/test_messages_clean_service.py new file mode 100644 index 0000000000..348bb0af4a --- /dev/null +++ b/api/tests/integration_tests/services/retention/test_messages_clean_service.py @@ -0,0 +1,348 @@ +import datetime +import math +import uuid + +import pytest +from sqlalchemy import delete + +from core.db.session_factory import session_factory +from models import Tenant +from models.enums import FeedbackFromSource, FeedbackRating +from models.model import ( + App, + Conversation, + Message, + MessageAnnotation, + MessageFeedback, +) +from services.retention.conversation.messages_clean_policy import BillingDisabledPolicy +from services.retention.conversation.messages_clean_service import MessagesCleanService + +_NOW = datetime.datetime(2026, 1, 15, 12, 0, 0, tzinfo=datetime.UTC) +_OLD = _NOW - datetime.timedelta(days=60) +_VERY_OLD = _NOW - datetime.timedelta(days=90) +_RECENT = _NOW - datetime.timedelta(days=5) + +_WINDOW_START = _VERY_OLD - datetime.timedelta(hours=1) +_WINDOW_END = _RECENT + datetime.timedelta(hours=1) + +_DEFAULT_BATCH_SIZE = 100 +_PAGINATION_MESSAGE_COUNT = 25 +_PAGINATION_BATCH_SIZE = 8 + + +@pytest.fixture +def tenant_and_app(flask_req_ctx): + """Creates a Tenant, App and Conversation for the test and cleans up after.""" + with session_factory.create_session() as session: + tenant = Tenant(name="retention_it_tenant") + session.add(tenant) + session.flush() + + app = App( + tenant_id=tenant.id, + name="Retention IT App", + mode="chat", + enable_site=True, + enable_api=True, + ) + session.add(app) + session.flush() + + conv = Conversation( + app_id=app.id, + mode="chat", + name="test_conv", + status="normal", + from_source="console", + _inputs={}, + ) + session.add(conv) + session.commit() + + tenant_id = tenant.id + app_id = app.id + conv_id = conv.id + + yield {"tenant_id": tenant_id, "app_id": app_id, "conversation_id": conv_id} + + with session_factory.create_session() as session: + session.execute(delete(Conversation).where(Conversation.id == conv_id)) + session.execute(delete(App).where(App.id == app_id)) + session.execute(delete(Tenant).where(Tenant.id == tenant_id)) + session.commit() + + +def _make_message(app_id: str, conversation_id: str, created_at: datetime.datetime) -> Message: + return Message( + app_id=app_id, + conversation_id=conversation_id, + query="test", + message=[{"text": "hello"}], + answer="world", + message_tokens=1, + message_unit_price=0, + answer_tokens=1, + answer_unit_price=0, + from_source="console", + currency="USD", + _inputs={}, + created_at=created_at, + ) + + +class TestMessagesCleanServiceIntegration: + @pytest.fixture + def seed_messages(self, tenant_and_app): + """Seeds one message at each of _VERY_OLD, _OLD, and _RECENT. + Yields a semantic mapping keyed by age label. + """ + data = tenant_and_app + app_id = data["app_id"] + conv_id = data["conversation_id"] + # Ordered tuple of (label, timestamp) for deterministic seeding + timestamps = [ + ("very_old", _VERY_OLD), + ("old", _OLD), + ("recent", _RECENT), + ] + msg_ids: dict[str, str] = {} + + with session_factory.create_session() as session: + for label, ts in timestamps: + msg = _make_message(app_id, conv_id, ts) + session.add(msg) + session.flush() + msg_ids[label] = msg.id + session.commit() + + yield {"msg_ids": msg_ids, **data} + + with session_factory.create_session() as session: + session.execute( + delete(Message) + .where(Message.id.in_(list(msg_ids.values()))) + .execution_options(synchronize_session=False) + ) + session.commit() + + @pytest.fixture + def paginated_seed_messages(self, tenant_and_app): + """Seeds multiple messages separated by 1-second increments starting at _OLD.""" + data = tenant_and_app + app_id = data["app_id"] + conv_id = data["conversation_id"] + msg_ids: list[str] = [] + + with session_factory.create_session() as session: + for i in range(_PAGINATION_MESSAGE_COUNT): + ts = _OLD + datetime.timedelta(seconds=i) + msg = _make_message(app_id, conv_id, ts) + session.add(msg) + session.flush() + msg_ids.append(msg.id) + session.commit() + + yield {"msg_ids": msg_ids, **data} + + with session_factory.create_session() as session: + session.execute(delete(Message).where(Message.id.in_(msg_ids)).execution_options(synchronize_session=False)) + session.commit() + + @pytest.fixture + def cascade_test_data(self, tenant_and_app): + """Seeds one Message with an associated Feedback and Annotation.""" + data = tenant_and_app + app_id = data["app_id"] + conv_id = data["conversation_id"] + + with session_factory.create_session() as session: + msg = _make_message(app_id, conv_id, _OLD) + session.add(msg) + session.flush() + + feedback = MessageFeedback( + app_id=app_id, + conversation_id=conv_id, + message_id=msg.id, + rating=FeedbackRating.LIKE, + from_source=FeedbackFromSource.USER, + ) + annotation = MessageAnnotation( + app_id=app_id, + conversation_id=conv_id, + message_id=msg.id, + question="q", + content="a", + account_id=str(uuid.uuid4()), + ) + session.add_all([feedback, annotation]) + session.commit() + + msg_id = msg.id + fb_id = feedback.id + ann_id = annotation.id + + yield {"msg_id": msg_id, "fb_id": fb_id, "ann_id": ann_id, **data} + + with session_factory.create_session() as session: + session.execute(delete(MessageAnnotation).where(MessageAnnotation.id == ann_id)) + session.execute(delete(MessageFeedback).where(MessageFeedback.id == fb_id)) + session.execute(delete(Message).where(Message.id == msg_id)) + session.commit() + + def test_dry_run_does_not_delete(self, seed_messages): + """Dry-run must count eligible rows without deleting any of them.""" + data = seed_messages + msg_ids = data["msg_ids"] + all_ids = list(msg_ids.values()) + + svc = MessagesCleanService.from_time_range( + policy=BillingDisabledPolicy(), + start_from=_WINDOW_START, + end_before=_WINDOW_END, + batch_size=_DEFAULT_BATCH_SIZE, + dry_run=True, + ) + stats = svc.run() + + assert stats["filtered_messages"] == len(all_ids) + assert stats["total_deleted"] == 0 + + with session_factory.create_session() as session: + remaining = session.query(Message).where(Message.id.in_(all_ids)).count() + assert remaining == len(all_ids) + + def test_billing_disabled_deletes_all_in_range(self, seed_messages): + """All 3 seeded messages fall within the window and must be deleted.""" + data = seed_messages + msg_ids = data["msg_ids"] + all_ids = list(msg_ids.values()) + + svc = MessagesCleanService.from_time_range( + policy=BillingDisabledPolicy(), + start_from=_WINDOW_START, + end_before=_WINDOW_END, + batch_size=_DEFAULT_BATCH_SIZE, + dry_run=False, + ) + stats = svc.run() + + assert stats["total_deleted"] == len(all_ids) + + with session_factory.create_session() as session: + remaining = session.query(Message).where(Message.id.in_(all_ids)).count() + assert remaining == 0 + + def test_start_from_filters_correctly(self, seed_messages): + """Only the message at _OLD falls within the narrow ±1 h window.""" + data = seed_messages + msg_ids = data["msg_ids"] + + start = _OLD - datetime.timedelta(hours=1) + end = _OLD + datetime.timedelta(hours=1) + + svc = MessagesCleanService.from_time_range( + policy=BillingDisabledPolicy(), + start_from=start, + end_before=end, + batch_size=_DEFAULT_BATCH_SIZE, + ) + stats = svc.run() + + assert stats["total_deleted"] == 1 + + with session_factory.create_session() as session: + all_ids = list(msg_ids.values()) + remaining_ids = {r[0] for r in session.query(Message.id).where(Message.id.in_(all_ids)).all()} + + assert msg_ids["old"] not in remaining_ids + assert msg_ids["very_old"] in remaining_ids + assert msg_ids["recent"] in remaining_ids + + def test_cursor_pagination_across_batches(self, paginated_seed_messages): + """Messages must be deleted across multiple batches.""" + data = paginated_seed_messages + msg_ids = data["msg_ids"] + + # _OLD is the earliest; the last one is _OLD + (_PAGINATION_MESSAGE_COUNT - 1) s. + pagination_window_start = _OLD - datetime.timedelta(seconds=1) + pagination_window_end = _OLD + datetime.timedelta(seconds=_PAGINATION_MESSAGE_COUNT) + + svc = MessagesCleanService.from_time_range( + policy=BillingDisabledPolicy(), + start_from=pagination_window_start, + end_before=pagination_window_end, + batch_size=_PAGINATION_BATCH_SIZE, + ) + stats = svc.run() + + assert stats["total_deleted"] == _PAGINATION_MESSAGE_COUNT + expected_batches = math.ceil(_PAGINATION_MESSAGE_COUNT / _PAGINATION_BATCH_SIZE) + assert stats["batches"] >= expected_batches + + with session_factory.create_session() as session: + remaining = session.query(Message).where(Message.id.in_(msg_ids)).count() + assert remaining == 0 + + def test_no_messages_in_range_returns_empty_stats(self, seed_messages): + """A window entirely in the future must yield zero matches.""" + far_future = _NOW + datetime.timedelta(days=365) + even_further = far_future + datetime.timedelta(days=1) + + svc = MessagesCleanService.from_time_range( + policy=BillingDisabledPolicy(), + start_from=far_future, + end_before=even_further, + batch_size=_DEFAULT_BATCH_SIZE, + ) + stats = svc.run() + + assert stats["total_messages"] == 0 + assert stats["total_deleted"] == 0 + + def test_relation_cascade_deletes(self, cascade_test_data): + """Deleting a Message must cascade to its Feedback and Annotation rows.""" + data = cascade_test_data + msg_id = data["msg_id"] + fb_id = data["fb_id"] + ann_id = data["ann_id"] + + svc = MessagesCleanService.from_time_range( + policy=BillingDisabledPolicy(), + start_from=_OLD - datetime.timedelta(hours=1), + end_before=_OLD + datetime.timedelta(hours=1), + batch_size=_DEFAULT_BATCH_SIZE, + ) + stats = svc.run() + + assert stats["total_deleted"] == 1 + + with session_factory.create_session() as session: + assert session.query(Message).where(Message.id == msg_id).count() == 0 + assert session.query(MessageFeedback).where(MessageFeedback.id == fb_id).count() == 0 + assert session.query(MessageAnnotation).where(MessageAnnotation.id == ann_id).count() == 0 + + def test_factory_from_time_range_validation(self): + with pytest.raises(ValueError, match="start_from"): + MessagesCleanService.from_time_range( + policy=BillingDisabledPolicy(), + start_from=_NOW, + end_before=_OLD, + ) + + def test_factory_from_days_validation(self): + with pytest.raises(ValueError, match="days"): + MessagesCleanService.from_days( + policy=BillingDisabledPolicy(), + days=-1, + ) + + def test_factory_batch_size_validation(self): + with pytest.raises(ValueError, match="batch_size"): + MessagesCleanService.from_time_range( + policy=BillingDisabledPolicy(), + start_from=_OLD, + end_before=_NOW, + batch_size=0, + ) diff --git a/api/tests/integration_tests/services/retention/test_workflow_run_archiver.py b/api/tests/integration_tests/services/retention/test_workflow_run_archiver.py new file mode 100644 index 0000000000..5728eacdfb --- /dev/null +++ b/api/tests/integration_tests/services/retention/test_workflow_run_archiver.py @@ -0,0 +1,177 @@ +import datetime +import io +import json +import uuid +import zipfile +from unittest.mock import MagicMock, patch + +import pytest + +from services.retention.workflow_run.archive_paid_plan_workflow_run import ( + ArchiveSummary, + WorkflowRunArchiver, +) +from services.retention.workflow_run.constants import ARCHIVE_SCHEMA_VERSION + + +class TestWorkflowRunArchiverInit: + def test_start_from_without_end_before_raises(self): + with pytest.raises(ValueError, match="start_from and end_before must be provided together"): + WorkflowRunArchiver(start_from=datetime.datetime(2025, 1, 1)) + + def test_end_before_without_start_from_raises(self): + with pytest.raises(ValueError, match="start_from and end_before must be provided together"): + WorkflowRunArchiver(end_before=datetime.datetime(2025, 1, 1)) + + def test_start_equals_end_raises(self): + ts = datetime.datetime(2025, 1, 1) + with pytest.raises(ValueError, match="start_from must be earlier than end_before"): + WorkflowRunArchiver(start_from=ts, end_before=ts) + + def test_start_after_end_raises(self): + with pytest.raises(ValueError, match="start_from must be earlier than end_before"): + WorkflowRunArchiver( + start_from=datetime.datetime(2025, 6, 1), + end_before=datetime.datetime(2025, 1, 1), + ) + + def test_workers_zero_raises(self): + with pytest.raises(ValueError, match="workers must be at least 1"): + WorkflowRunArchiver(workers=0) + + def test_valid_init_defaults(self): + archiver = WorkflowRunArchiver(days=30, batch_size=50) + assert archiver.days == 30 + assert archiver.batch_size == 50 + assert archiver.dry_run is False + assert archiver.delete_after_archive is False + assert archiver.start_from is None + + def test_valid_init_with_time_range(self): + start = datetime.datetime(2025, 1, 1) + end = datetime.datetime(2025, 6, 1) + archiver = WorkflowRunArchiver(start_from=start, end_before=end, workers=2) + assert archiver.start_from is not None + assert archiver.end_before is not None + assert archiver.workers == 2 + + +class TestBuildArchiveBundle: + def test_bundle_contains_manifest_and_all_tables(self): + archiver = WorkflowRunArchiver(days=90) + + manifest_data = json.dumps({"schema_version": ARCHIVE_SCHEMA_VERSION}).encode("utf-8") + table_payloads = dict.fromkeys(archiver.ARCHIVED_TABLES, b"") + + bundle_bytes = archiver._build_archive_bundle(manifest_data, table_payloads) + + with zipfile.ZipFile(io.BytesIO(bundle_bytes), "r") as zf: + names = set(zf.namelist()) + assert "manifest.json" in names + for table in archiver.ARCHIVED_TABLES: + assert f"{table}.jsonl" in names, f"Missing {table}.jsonl in bundle" + + def test_bundle_missing_table_payload_raises(self): + archiver = WorkflowRunArchiver(days=90) + manifest_data = b"{}" + incomplete_payloads = {archiver.ARCHIVED_TABLES[0]: b"data"} + + with pytest.raises(ValueError, match="Missing archive payload"): + archiver._build_archive_bundle(manifest_data, incomplete_payloads) + + +class TestGenerateManifest: + def test_manifest_structure(self): + archiver = WorkflowRunArchiver(days=90) + from services.retention.workflow_run.archive_paid_plan_workflow_run import TableStats + + run = MagicMock() + run.id = str(uuid.uuid4()) + run.tenant_id = str(uuid.uuid4()) + run.app_id = str(uuid.uuid4()) + run.workflow_id = str(uuid.uuid4()) + run.created_at = datetime.datetime(2025, 3, 15, 10, 0, 0) + + stats = [ + TableStats(table_name="workflow_runs", row_count=1, checksum="abc123", size_bytes=512), + TableStats(table_name="workflow_app_logs", row_count=2, checksum="def456", size_bytes=1024), + ] + + manifest = archiver._generate_manifest(run, stats) + + assert manifest["schema_version"] == ARCHIVE_SCHEMA_VERSION + assert manifest["workflow_run_id"] == run.id + assert manifest["tenant_id"] == run.tenant_id + assert manifest["app_id"] == run.app_id + assert "tables" in manifest + assert manifest["tables"]["workflow_runs"]["row_count"] == 1 + assert manifest["tables"]["workflow_runs"]["checksum"] == "abc123" + assert manifest["tables"]["workflow_app_logs"]["row_count"] == 2 + + +class TestFilterPaidTenants: + def test_all_tenants_paid_when_billing_disabled(self): + archiver = WorkflowRunArchiver(days=90) + tenant_ids = {"t1", "t2", "t3"} + + with patch("services.retention.workflow_run.archive_paid_plan_workflow_run.dify_config") as cfg: + cfg.BILLING_ENABLED = False + result = archiver._filter_paid_tenants(tenant_ids) + + assert result == tenant_ids + + def test_empty_tenants_returns_empty(self): + archiver = WorkflowRunArchiver(days=90) + + with patch("services.retention.workflow_run.archive_paid_plan_workflow_run.dify_config") as cfg: + cfg.BILLING_ENABLED = True + result = archiver._filter_paid_tenants(set()) + + assert result == set() + + def test_only_paid_plans_returned(self): + archiver = WorkflowRunArchiver(days=90) + + mock_bulk = { + "t1": {"plan": "professional"}, + "t2": {"plan": "sandbox"}, + "t3": {"plan": "team"}, + } + + with ( + patch("services.retention.workflow_run.archive_paid_plan_workflow_run.dify_config") as cfg, + patch("services.retention.workflow_run.archive_paid_plan_workflow_run.BillingService") as billing, + ): + cfg.BILLING_ENABLED = True + billing.get_plan_bulk_with_cache.return_value = mock_bulk + result = archiver._filter_paid_tenants({"t1", "t2", "t3"}) + + assert "t1" in result + assert "t3" in result + assert "t2" not in result + + def test_billing_api_failure_returns_empty(self): + archiver = WorkflowRunArchiver(days=90) + + with ( + patch("services.retention.workflow_run.archive_paid_plan_workflow_run.dify_config") as cfg, + patch("services.retention.workflow_run.archive_paid_plan_workflow_run.BillingService") as billing, + ): + cfg.BILLING_ENABLED = True + billing.get_plan_bulk_with_cache.side_effect = RuntimeError("API down") + result = archiver._filter_paid_tenants({"t1"}) + + assert result == set() + + +class TestDryRunArchive: + @patch("services.retention.workflow_run.archive_paid_plan_workflow_run.get_archive_storage") + def test_dry_run_does_not_call_storage(self, mock_get_storage, flask_req_ctx): + archiver = WorkflowRunArchiver(days=90, dry_run=True) + + with patch.object(archiver, "_get_runs_batch", return_value=[]): + summary = archiver.run() + + mock_get_storage.assert_not_called() + assert isinstance(summary, ArchiveSummary) + assert summary.runs_failed == 0 diff --git a/api/tests/unit_tests/services/enterprise/test_enterprise_service.py b/api/tests/unit_tests/services/enterprise/test_enterprise_service.py index 59c07bfb37..6ad6a490b0 100644 --- a/api/tests/unit_tests/services/enterprise/test_enterprise_service.py +++ b/api/tests/unit_tests/services/enterprise/test_enterprise_service.py @@ -5,6 +5,7 @@ Covers: - License status caching (get_cached_license_status) """ +from datetime import datetime from unittest.mock import patch import pytest @@ -15,9 +16,178 @@ from services.enterprise.enterprise_service import ( VALID_LICENSE_CACHE_TTL, DefaultWorkspaceJoinResult, EnterpriseService, + WebAppSettings, + WorkspacePermission, try_join_default_workspace, ) +MODULE = "services.enterprise.enterprise_service" + + +class TestEnterpriseServiceInfo: + def test_get_info_delegates(self): + with patch(f"{MODULE}.EnterpriseRequest") as req: + req.send_request.return_value = {"version": "1.0"} + result = EnterpriseService.get_info() + + req.send_request.assert_called_once_with("GET", "/info") + assert result == {"version": "1.0"} + + def test_get_workspace_info_delegates(self): + with patch(f"{MODULE}.EnterpriseRequest") as req: + req.send_request.return_value = {"name": "ws"} + result = EnterpriseService.get_workspace_info("tenant-1") + + req.send_request.assert_called_once_with("GET", "/workspace/tenant-1/info") + assert result == {"name": "ws"} + + +class TestSsoSettingsLastUpdateTime: + def test_app_sso_parses_valid_timestamp(self): + with patch(f"{MODULE}.EnterpriseRequest") as req: + req.send_request.return_value = "2025-01-15T10:30:00+00:00" + result = EnterpriseService.get_app_sso_settings_last_update_time() + + assert isinstance(result, datetime) + assert result.year == 2025 + + def test_app_sso_raises_on_empty(self): + with patch(f"{MODULE}.EnterpriseRequest") as req: + req.send_request.return_value = "" + with pytest.raises(ValueError, match="No data found"): + EnterpriseService.get_app_sso_settings_last_update_time() + + def test_app_sso_raises_on_invalid_format(self): + with patch(f"{MODULE}.EnterpriseRequest") as req: + req.send_request.return_value = "not-a-date" + with pytest.raises(ValueError, match="Invalid date format"): + EnterpriseService.get_app_sso_settings_last_update_time() + + def test_workspace_sso_parses_valid_timestamp(self): + with patch(f"{MODULE}.EnterpriseRequest") as req: + req.send_request.return_value = "2025-06-01T00:00:00+00:00" + result = EnterpriseService.get_workspace_sso_settings_last_update_time() + + assert isinstance(result, datetime) + + def test_workspace_sso_raises_on_empty(self): + with patch(f"{MODULE}.EnterpriseRequest") as req: + req.send_request.return_value = None + with pytest.raises(ValueError, match="No data found"): + EnterpriseService.get_workspace_sso_settings_last_update_time() + + +class TestWorkspacePermissionService: + def test_raises_on_empty_workspace_id(self): + with pytest.raises(ValueError, match="workspace_id must be provided"): + EnterpriseService.WorkspacePermissionService.get_permission("") + + def test_raises_on_missing_data(self): + with patch(f"{MODULE}.EnterpriseRequest") as req: + req.send_request.return_value = None + with pytest.raises(ValueError, match="No data found"): + EnterpriseService.WorkspacePermissionService.get_permission("ws-1") + + def test_raises_on_missing_permission_key(self): + with patch(f"{MODULE}.EnterpriseRequest") as req: + req.send_request.return_value = {"other": "data"} + with pytest.raises(ValueError, match="No data found"): + EnterpriseService.WorkspacePermissionService.get_permission("ws-1") + + def test_returns_parsed_permission(self): + with patch(f"{MODULE}.EnterpriseRequest") as req: + req.send_request.return_value = { + "permission": { + "workspaceId": "ws-1", + "allowMemberInvite": True, + "allowOwnerTransfer": False, + } + } + result = EnterpriseService.WorkspacePermissionService.get_permission("ws-1") + + assert isinstance(result, WorkspacePermission) + assert result.workspace_id == "ws-1" + assert result.allow_member_invite is True + assert result.allow_owner_transfer is False + + +class TestWebAppAuth: + def test_is_user_allowed_returns_result_field(self): + with patch(f"{MODULE}.EnterpriseRequest") as req: + req.send_request.return_value = {"result": True} + assert EnterpriseService.WebAppAuth.is_user_allowed_to_access_webapp("u1", "a1") is True + + def test_is_user_allowed_defaults_false(self): + with patch(f"{MODULE}.EnterpriseRequest") as req: + req.send_request.return_value = {} + assert EnterpriseService.WebAppAuth.is_user_allowed_to_access_webapp("u1", "a1") is False + + def test_batch_is_user_allowed_returns_empty_for_no_apps(self): + assert EnterpriseService.WebAppAuth.batch_is_user_allowed_to_access_webapps("u1", []) == {} + + def test_batch_is_user_allowed_raises_on_empty_response(self): + with patch(f"{MODULE}.EnterpriseRequest") as req: + req.send_request.return_value = None + with pytest.raises(ValueError, match="No data found"): + EnterpriseService.WebAppAuth.batch_is_user_allowed_to_access_webapps("u1", ["a1"]) + + def test_get_app_access_mode_raises_on_empty_app_id(self): + with pytest.raises(ValueError, match="app_id must be provided"): + EnterpriseService.WebAppAuth.get_app_access_mode_by_id("") + + def test_get_app_access_mode_returns_settings(self): + with patch(f"{MODULE}.EnterpriseRequest") as req: + req.send_request.return_value = {"accessMode": "public"} + result = EnterpriseService.WebAppAuth.get_app_access_mode_by_id("a1") + + assert isinstance(result, WebAppSettings) + assert result.access_mode == "public" + + def test_batch_get_returns_empty_for_no_apps(self): + assert EnterpriseService.WebAppAuth.batch_get_app_access_mode_by_id([]) == {} + + def test_batch_get_maps_access_modes(self): + with patch(f"{MODULE}.EnterpriseRequest") as req: + req.send_request.return_value = {"accessModes": {"a1": "public", "a2": "private"}} + result = EnterpriseService.WebAppAuth.batch_get_app_access_mode_by_id(["a1", "a2"]) + + assert result["a1"].access_mode == "public" + assert result["a2"].access_mode == "private" + + def test_batch_get_raises_on_invalid_format(self): + with patch(f"{MODULE}.EnterpriseRequest") as req: + req.send_request.return_value = {"accessModes": "not-a-dict"} + with pytest.raises(ValueError, match="Invalid data format"): + EnterpriseService.WebAppAuth.batch_get_app_access_mode_by_id(["a1"]) + + def test_update_access_mode_raises_on_empty_app_id(self): + with pytest.raises(ValueError, match="app_id must be provided"): + EnterpriseService.WebAppAuth.update_app_access_mode("", "public") + + def test_update_access_mode_raises_on_invalid_mode(self): + with pytest.raises(ValueError, match="access_mode must be"): + EnterpriseService.WebAppAuth.update_app_access_mode("a1", "invalid") + + def test_update_access_mode_delegates_and_returns(self): + with patch(f"{MODULE}.EnterpriseRequest") as req: + req.send_request.return_value = {"result": True} + result = EnterpriseService.WebAppAuth.update_app_access_mode("a1", "public") + + assert result is True + req.send_request.assert_called_once_with( + "POST", "/webapp/access-mode", json={"appId": "a1", "accessMode": "public"} + ) + + def test_cleanup_webapp_raises_on_empty_app_id(self): + with pytest.raises(ValueError, match="app_id must be provided"): + EnterpriseService.WebAppAuth.cleanup_webapp("") + + def test_cleanup_webapp_delegates(self): + with patch(f"{MODULE}.EnterpriseRequest") as req: + EnterpriseService.WebAppAuth.cleanup_webapp("a1") + + req.send_request.assert_called_once_with("DELETE", "/webapp/clean", params={"appId": "a1"}) + class TestJoinDefaultWorkspace: def test_join_default_workspace_success(self): diff --git a/api/tests/unit_tests/services/enterprise/test_plugin_manager_service.py b/api/tests/unit_tests/services/enterprise/test_plugin_manager_service.py index 6ee328ae2c..759d907934 100644 --- a/api/tests/unit_tests/services/enterprise/test_plugin_manager_service.py +++ b/api/tests/unit_tests/services/enterprise/test_plugin_manager_service.py @@ -7,14 +7,20 @@ This module covers the pre-uninstall plugin hook behavior: from unittest.mock import patch +import pytest from httpx import HTTPStatusError from configs import dify_config from services.enterprise.plugin_manager_service import ( + CheckCredentialPolicyComplianceRequest, + CredentialPolicyViolationError, + PluginCredentialType, PluginManagerService, PreUninstallPluginRequest, ) +MODULE = "services.enterprise.plugin_manager_service" + class TestTryPreUninstallPlugin: def test_try_pre_uninstall_plugin_success(self): @@ -88,3 +94,46 @@ class TestTryPreUninstallPlugin: timeout=dify_config.ENTERPRISE_REQUEST_TIMEOUT, ) mock_logger.exception.assert_called_once() + + +class TestCheckCredentialPolicyCompliance: + def _request(self, cred_type=PluginCredentialType.MODEL): + return CheckCredentialPolicyComplianceRequest( + dify_credential_id="cred-1", provider="openai", credential_type=cred_type + ) + + def test_passes_when_result_true(self): + with patch(f"{MODULE}.EnterprisePluginManagerRequest") as req: + req.send_request.return_value = {"result": True} + PluginManagerService.check_credential_policy_compliance(self._request()) + + req.send_request.assert_called_once() + + def test_raises_violation_when_result_false(self): + with patch(f"{MODULE}.EnterprisePluginManagerRequest") as req: + req.send_request.return_value = {"result": False} + with pytest.raises(CredentialPolicyViolationError, match="Credentials not available"): + PluginManagerService.check_credential_policy_compliance(self._request()) + + def test_raises_violation_on_invalid_response_format(self): + with patch(f"{MODULE}.EnterprisePluginManagerRequest") as req: + req.send_request.return_value = "not-a-dict" + with pytest.raises(CredentialPolicyViolationError, match="error occurred"): + PluginManagerService.check_credential_policy_compliance(self._request()) + + def test_raises_violation_on_api_exception(self): + with patch(f"{MODULE}.EnterprisePluginManagerRequest") as req: + req.send_request.side_effect = ConnectionError("network fail") + with pytest.raises(CredentialPolicyViolationError, match="error occurred"): + PluginManagerService.check_credential_policy_compliance(self._request()) + + def test_model_dump_serializes_credential_type_as_number(self): + body = self._request(PluginCredentialType.TOOL) + data = body.model_dump() + + assert data["credential_type"] == 1 + assert data["dify_credential_id"] == "cred-1" + + def test_model_credential_type_values(self): + assert PluginCredentialType.MODEL.to_number() == 0 + assert PluginCredentialType.TOOL.to_number() == 1 diff --git a/api/tests/unit_tests/services/plugin/test_plugin_auto_upgrade_service.py b/api/tests/unit_tests/services/plugin/test_plugin_auto_upgrade_service.py new file mode 100644 index 0000000000..edb50d09a6 --- /dev/null +++ b/api/tests/unit_tests/services/plugin/test_plugin_auto_upgrade_service.py @@ -0,0 +1,183 @@ +from unittest.mock import MagicMock, patch + +from models.account import TenantPluginAutoUpgradeStrategy + +MODULE = "services.plugin.plugin_auto_upgrade_service" + + +def _patched_session(): + """Patch Session(db.engine) to return a mock session as context manager.""" + session = MagicMock() + session_cls = MagicMock() + session_cls.return_value.__enter__ = MagicMock(return_value=session) + session_cls.return_value.__exit__ = MagicMock(return_value=False) + patcher = patch(f"{MODULE}.Session", session_cls) + db_patcher = patch(f"{MODULE}.db") + return patcher, db_patcher, session + + +class TestGetStrategy: + def test_returns_strategy_when_found(self): + p1, p2, session = _patched_session() + strategy = MagicMock() + session.query.return_value.where.return_value.first.return_value = strategy + + with p1, p2: + from services.plugin.plugin_auto_upgrade_service import PluginAutoUpgradeService + + result = PluginAutoUpgradeService.get_strategy("t1") + + assert result is strategy + + def test_returns_none_when_not_found(self): + p1, p2, session = _patched_session() + session.query.return_value.where.return_value.first.return_value = None + + with p1, p2: + from services.plugin.plugin_auto_upgrade_service import PluginAutoUpgradeService + + result = PluginAutoUpgradeService.get_strategy("t1") + + assert result is None + + +class TestChangeStrategy: + def test_creates_new_strategy(self): + p1, p2, session = _patched_session() + session.query.return_value.where.return_value.first.return_value = None + + with p1, p2, patch(f"{MODULE}.TenantPluginAutoUpgradeStrategy") as strat_cls: + strat_cls.return_value = MagicMock() + from services.plugin.plugin_auto_upgrade_service import PluginAutoUpgradeService + + result = PluginAutoUpgradeService.change_strategy( + "t1", + TenantPluginAutoUpgradeStrategy.StrategySetting.FIX_ONLY, + 3, + TenantPluginAutoUpgradeStrategy.UpgradeMode.ALL, + [], + [], + ) + + assert result is True + session.add.assert_called_once() + session.commit.assert_called_once() + + def test_updates_existing_strategy(self): + p1, p2, session = _patched_session() + existing = MagicMock() + session.query.return_value.where.return_value.first.return_value = existing + + with p1, p2: + from services.plugin.plugin_auto_upgrade_service import PluginAutoUpgradeService + + result = PluginAutoUpgradeService.change_strategy( + "t1", + TenantPluginAutoUpgradeStrategy.StrategySetting.LATEST, + 5, + TenantPluginAutoUpgradeStrategy.UpgradeMode.PARTIAL, + ["p1"], + ["p2"], + ) + + assert result is True + assert existing.strategy_setting == TenantPluginAutoUpgradeStrategy.StrategySetting.LATEST + assert existing.upgrade_time_of_day == 5 + assert existing.upgrade_mode == TenantPluginAutoUpgradeStrategy.UpgradeMode.PARTIAL + assert existing.exclude_plugins == ["p1"] + assert existing.include_plugins == ["p2"] + session.commit.assert_called_once() + + +class TestExcludePlugin: + def test_creates_default_strategy_when_none_exists(self): + p1, p2, session = _patched_session() + session.query.return_value.where.return_value.first.return_value = None + + with ( + p1, + p2, + patch(f"{MODULE}.TenantPluginAutoUpgradeStrategy") as strat_cls, + patch(f"{MODULE}.PluginAutoUpgradeService.change_strategy") as cs, + ): + strat_cls.StrategySetting.FIX_ONLY = "fix_only" + strat_cls.UpgradeMode.EXCLUDE = "exclude" + cs.return_value = True + from services.plugin.plugin_auto_upgrade_service import PluginAutoUpgradeService + + result = PluginAutoUpgradeService.exclude_plugin("t1", "plugin-1") + + assert result is True + cs.assert_called_once() + + def test_appends_to_exclude_list_in_exclude_mode(self): + p1, p2, session = _patched_session() + existing = MagicMock() + existing.upgrade_mode = "exclude" + existing.exclude_plugins = ["p-existing"] + session.query.return_value.where.return_value.first.return_value = existing + + with p1, p2, patch(f"{MODULE}.TenantPluginAutoUpgradeStrategy") as strat_cls: + strat_cls.UpgradeMode.EXCLUDE = "exclude" + strat_cls.UpgradeMode.PARTIAL = "partial" + strat_cls.UpgradeMode.ALL = "all" + from services.plugin.plugin_auto_upgrade_service import PluginAutoUpgradeService + + result = PluginAutoUpgradeService.exclude_plugin("t1", "p-new") + + assert result is True + assert existing.exclude_plugins == ["p-existing", "p-new"] + session.commit.assert_called_once() + + def test_removes_from_include_list_in_partial_mode(self): + p1, p2, session = _patched_session() + existing = MagicMock() + existing.upgrade_mode = "partial" + existing.include_plugins = ["p1", "p2"] + session.query.return_value.where.return_value.first.return_value = existing + + with p1, p2, patch(f"{MODULE}.TenantPluginAutoUpgradeStrategy") as strat_cls: + strat_cls.UpgradeMode.EXCLUDE = "exclude" + strat_cls.UpgradeMode.PARTIAL = "partial" + strat_cls.UpgradeMode.ALL = "all" + from services.plugin.plugin_auto_upgrade_service import PluginAutoUpgradeService + + result = PluginAutoUpgradeService.exclude_plugin("t1", "p1") + + assert result is True + assert existing.include_plugins == ["p2"] + + def test_switches_to_exclude_mode_from_all(self): + p1, p2, session = _patched_session() + existing = MagicMock() + existing.upgrade_mode = "all" + session.query.return_value.where.return_value.first.return_value = existing + + with p1, p2, patch(f"{MODULE}.TenantPluginAutoUpgradeStrategy") as strat_cls: + strat_cls.UpgradeMode.EXCLUDE = "exclude" + strat_cls.UpgradeMode.PARTIAL = "partial" + strat_cls.UpgradeMode.ALL = "all" + from services.plugin.plugin_auto_upgrade_service import PluginAutoUpgradeService + + result = PluginAutoUpgradeService.exclude_plugin("t1", "p1") + + assert result is True + assert existing.upgrade_mode == "exclude" + assert existing.exclude_plugins == ["p1"] + + def test_no_duplicate_in_exclude_list(self): + p1, p2, session = _patched_session() + existing = MagicMock() + existing.upgrade_mode = "exclude" + existing.exclude_plugins = ["p1"] + session.query.return_value.where.return_value.first.return_value = existing + + with p1, p2, patch(f"{MODULE}.TenantPluginAutoUpgradeStrategy") as strat_cls: + strat_cls.UpgradeMode.EXCLUDE = "exclude" + strat_cls.UpgradeMode.PARTIAL = "partial" + strat_cls.UpgradeMode.ALL = "all" + from services.plugin.plugin_auto_upgrade_service import PluginAutoUpgradeService + + PluginAutoUpgradeService.exclude_plugin("t1", "p1") + + assert existing.exclude_plugins == ["p1"] diff --git a/api/tests/unit_tests/services/plugin/test_plugin_permission_service.py b/api/tests/unit_tests/services/plugin/test_plugin_permission_service.py new file mode 100644 index 0000000000..69091110db --- /dev/null +++ b/api/tests/unit_tests/services/plugin/test_plugin_permission_service.py @@ -0,0 +1,75 @@ +from unittest.mock import MagicMock, patch + +from models.account import TenantPluginPermission + +MODULE = "services.plugin.plugin_permission_service" + + +def _patched_session(): + """Patch Session(db.engine) to return a mock session as context manager.""" + session = MagicMock() + session_cls = MagicMock() + session_cls.return_value.__enter__ = MagicMock(return_value=session) + session_cls.return_value.__exit__ = MagicMock(return_value=False) + patcher = patch(f"{MODULE}.Session", session_cls) + db_patcher = patch(f"{MODULE}.db") + return patcher, db_patcher, session + + +class TestGetPermission: + def test_returns_permission_when_found(self): + p1, p2, session = _patched_session() + permission = MagicMock() + session.query.return_value.where.return_value.first.return_value = permission + + with p1, p2: + from services.plugin.plugin_permission_service import PluginPermissionService + + result = PluginPermissionService.get_permission("t1") + + assert result is permission + + def test_returns_none_when_not_found(self): + p1, p2, session = _patched_session() + session.query.return_value.where.return_value.first.return_value = None + + with p1, p2: + from services.plugin.plugin_permission_service import PluginPermissionService + + result = PluginPermissionService.get_permission("t1") + + assert result is None + + +class TestChangePermission: + def test_creates_new_permission_when_not_exists(self): + p1, p2, session = _patched_session() + session.query.return_value.where.return_value.first.return_value = None + + with p1, p2, patch(f"{MODULE}.TenantPluginPermission") as perm_cls: + perm_cls.return_value = MagicMock() + from services.plugin.plugin_permission_service import PluginPermissionService + + result = PluginPermissionService.change_permission( + "t1", TenantPluginPermission.InstallPermission.EVERYONE, TenantPluginPermission.DebugPermission.EVERYONE + ) + + session.add.assert_called_once() + session.commit.assert_called_once() + + def test_updates_existing_permission(self): + p1, p2, session = _patched_session() + existing = MagicMock() + session.query.return_value.where.return_value.first.return_value = existing + + with p1, p2: + from services.plugin.plugin_permission_service import PluginPermissionService + + result = PluginPermissionService.change_permission( + "t1", TenantPluginPermission.InstallPermission.ADMINS, TenantPluginPermission.DebugPermission.ADMINS + ) + + assert existing.install_permission == TenantPluginPermission.InstallPermission.ADMINS + assert existing.debug_permission == TenantPluginPermission.DebugPermission.ADMINS + session.commit.assert_called_once() + session.add.assert_not_called() diff --git a/api/tests/unit_tests/services/retention/__init__.py b/api/tests/unit_tests/services/retention/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/api/tests/unit_tests/services/retention/test_messages_clean_policy.py b/api/tests/unit_tests/services/retention/test_messages_clean_policy.py new file mode 100644 index 0000000000..79c079c683 --- /dev/null +++ b/api/tests/unit_tests/services/retention/test_messages_clean_policy.py @@ -0,0 +1,135 @@ +import datetime +from unittest.mock import MagicMock, patch + +from services.retention.conversation.messages_clean_policy import ( + BillingDisabledPolicy, + BillingSandboxPolicy, + SimpleMessage, + create_message_clean_policy, +) + +MODULE = "services.retention.conversation.messages_clean_policy" + + +def _msg(msg_id: str, app_id: str, days_ago: int = 0) -> SimpleMessage: + return SimpleMessage( + id=msg_id, + app_id=app_id, + created_at=datetime.datetime.now(datetime.UTC) - datetime.timedelta(days=days_ago), + ) + + +class TestBillingDisabledPolicy: + def test_returns_all_message_ids(self): + policy = BillingDisabledPolicy() + msgs = [_msg("m1", "app1"), _msg("m2", "app2"), _msg("m3", "app1")] + + result = policy.filter_message_ids(msgs, {"app1": "t1", "app2": "t2"}) + + assert set(result) == {"m1", "m2", "m3"} + + def test_empty_messages_returns_empty(self): + assert BillingDisabledPolicy().filter_message_ids([], {}) == [] + + +class TestBillingSandboxPolicy: + def _policy(self, plans, *, graceful_days=21, whitelist=None, now=1_000_000_000): + return BillingSandboxPolicy( + plan_provider=lambda _ids: plans, + graceful_period_days=graceful_days, + tenant_whitelist=whitelist, + current_timestamp=now, + ) + + def test_empty_messages_returns_empty(self): + policy = self._policy({}) + assert policy.filter_message_ids([], {"app1": "t1"}) == [] + + def test_empty_app_to_tenant_returns_empty(self): + policy = self._policy({}) + assert policy.filter_message_ids([_msg("m1", "app1")], {}) == [] + + def test_empty_plans_returns_empty(self): + policy = self._policy({}) + msgs = [_msg("m1", "app1")] + assert policy.filter_message_ids(msgs, {"app1": "t1"}) == [] + + def test_non_sandbox_tenant_skipped(self): + plans = {"t1": {"plan": "professional", "expiration_date": 0}} + policy = self._policy(plans) + msgs = [_msg("m1", "app1")] + + assert policy.filter_message_ids(msgs, {"app1": "t1"}) == [] + + def test_sandbox_no_previous_subscription_deletes(self): + plans = {"t1": {"plan": "sandbox", "expiration_date": -1}} + policy = self._policy(plans) + msgs = [_msg("m1", "app1")] + + assert policy.filter_message_ids(msgs, {"app1": "t1"}) == ["m1"] + + def test_sandbox_expired_beyond_grace_period_deletes(self): + now = 1_000_000_000 + expired_long_ago = now - (22 * 24 * 60 * 60) # 22 days ago > 21 day grace + plans = {"t1": {"plan": "sandbox", "expiration_date": expired_long_ago}} + policy = self._policy(plans, now=now) + msgs = [_msg("m1", "app1")] + + assert policy.filter_message_ids(msgs, {"app1": "t1"}) == ["m1"] + + def test_sandbox_within_grace_period_kept(self): + now = 1_000_000_000 + expired_recently = now - (10 * 24 * 60 * 60) # 10 days ago < 21 day grace + plans = {"t1": {"plan": "sandbox", "expiration_date": expired_recently}} + policy = self._policy(plans, now=now) + msgs = [_msg("m1", "app1")] + + assert policy.filter_message_ids(msgs, {"app1": "t1"}) == [] + + def test_whitelisted_tenant_skipped(self): + plans = {"t1": {"plan": "sandbox", "expiration_date": -1}} + policy = self._policy(plans, whitelist=["t1"]) + msgs = [_msg("m1", "app1")] + + assert policy.filter_message_ids(msgs, {"app1": "t1"}) == [] + + def test_message_without_tenant_mapping_skipped(self): + plans = {"t1": {"plan": "sandbox", "expiration_date": -1}} + policy = self._policy(plans) + msgs = [_msg("m1", "unmapped_app")] + + assert policy.filter_message_ids(msgs, {"app1": "t1"}) == [] + + def test_mixed_tenants_only_sandbox_deleted(self): + plans = { + "t_sandbox": {"plan": "sandbox", "expiration_date": -1}, + "t_pro": {"plan": "professional", "expiration_date": 0}, + } + policy = self._policy(plans) + msgs = [_msg("m1", "app_sandbox"), _msg("m2", "app_pro")] + app_map = {"app_sandbox": "t_sandbox", "app_pro": "t_pro"} + + result = policy.filter_message_ids(msgs, app_map) + + assert result == ["m1"] + + +class TestCreateMessageCleanPolicy: + def test_billing_disabled_returns_disabled_policy(self): + with patch(f"{MODULE}.dify_config") as cfg: + cfg.BILLING_ENABLED = False + policy = create_message_clean_policy() + + assert isinstance(policy, BillingDisabledPolicy) + + def test_billing_enabled_returns_sandbox_policy(self): + with ( + patch(f"{MODULE}.dify_config") as cfg, + patch(f"{MODULE}.BillingService") as bs, + ): + cfg.BILLING_ENABLED = True + bs.get_expired_subscription_cleanup_whitelist.return_value = ["wl1"] + bs.get_plan_bulk_with_cache = MagicMock() + policy = create_message_clean_policy(graceful_period_days=30) + + assert isinstance(policy, BillingSandboxPolicy) diff --git a/api/tests/unit_tests/services/tools/test_tools_transform_service.py b/api/tests/unit_tests/services/tools/test_tools_transform_service.py new file mode 100644 index 0000000000..32c1a00d30 --- /dev/null +++ b/api/tests/unit_tests/services/tools/test_tools_transform_service.py @@ -0,0 +1,598 @@ +from unittest.mock import MagicMock, Mock, patch + +from core.tools.__base.tool import Tool +from core.tools.entities.api_entities import ToolApiEntity, ToolProviderApiEntity +from core.tools.entities.common_entities import I18nObject +from core.tools.entities.tool_entities import ApiProviderAuthType, ToolParameter, ToolProviderType +from services.tools.tools_transform_service import ToolTransformService + +MODULE = "services.tools.tools_transform_service" + + +class TestToolTransformService: + """Test cases for ToolTransformService.convert_tool_entity_to_api_entity method""" + + def test_convert_tool_with_parameter_override(self): + """Test that runtime parameters correctly override base parameters""" + # Create mock base parameters + base_param1 = Mock(spec=ToolParameter) + base_param1.name = "param1" + base_param1.form = ToolParameter.ToolParameterForm.FORM + base_param1.type = "string" + base_param1.label = "Base Param 1" + + base_param2 = Mock(spec=ToolParameter) + base_param2.name = "param2" + base_param2.form = ToolParameter.ToolParameterForm.FORM + base_param2.type = "string" + base_param2.label = "Base Param 2" + + # Create mock runtime parameters that override base parameters + runtime_param1 = Mock(spec=ToolParameter) + runtime_param1.name = "param1" + runtime_param1.form = ToolParameter.ToolParameterForm.FORM + runtime_param1.type = "string" + runtime_param1.label = "Runtime Param 1" # Different label to verify override + + # Create mock tool + mock_tool = Mock(spec=Tool) + mock_tool.entity = Mock() + mock_tool.entity.parameters = [base_param1, base_param2] + mock_tool.entity.identity = Mock() + mock_tool.entity.identity.author = "test_author" + mock_tool.entity.identity.name = "test_tool" + mock_tool.entity.identity.label = I18nObject(en_US="Test Tool") + mock_tool.entity.description = Mock() + mock_tool.entity.description.human = I18nObject(en_US="Test description") + mock_tool.entity.output_schema = {} + mock_tool.get_runtime_parameters.return_value = [runtime_param1] + + # Mock fork_tool_runtime to return the same tool + mock_tool.fork_tool_runtime.return_value = mock_tool + + # Call the method + result = ToolTransformService.convert_tool_entity_to_api_entity(mock_tool, "test_tenant", None) + + # Verify the result + assert isinstance(result, ToolApiEntity) + assert result.author == "test_author" + assert result.name == "test_tool" + assert result.parameters is not None + assert len(result.parameters) == 2 + + # Find the overridden parameter + overridden_param = next((p for p in result.parameters if p.name == "param1"), None) + assert overridden_param is not None + assert overridden_param.label == "Runtime Param 1" # Should be runtime version + + # Find the non-overridden parameter + original_param = next((p for p in result.parameters if p.name == "param2"), None) + assert original_param is not None + assert original_param.label == "Base Param 2" # Should be base version + + def test_convert_tool_with_additional_runtime_parameters(self): + """Test that additional runtime parameters are added to the final list""" + # Create mock base parameters + base_param1 = Mock(spec=ToolParameter) + base_param1.name = "param1" + base_param1.form = ToolParameter.ToolParameterForm.FORM + base_param1.type = "string" + base_param1.label = "Base Param 1" + + # Create mock runtime parameters - one that overrides and one that's new + runtime_param1 = Mock(spec=ToolParameter) + runtime_param1.name = "param1" + runtime_param1.form = ToolParameter.ToolParameterForm.FORM + runtime_param1.type = "string" + runtime_param1.label = "Runtime Param 1" + + runtime_param2 = Mock(spec=ToolParameter) + runtime_param2.name = "runtime_only" + runtime_param2.form = ToolParameter.ToolParameterForm.FORM + runtime_param2.type = "string" + runtime_param2.label = "Runtime Only Param" + + # Create mock tool + mock_tool = Mock(spec=Tool) + mock_tool.entity = Mock() + mock_tool.entity.parameters = [base_param1] + mock_tool.entity.identity = Mock() + mock_tool.entity.identity.author = "test_author" + mock_tool.entity.identity.name = "test_tool" + mock_tool.entity.identity.label = I18nObject(en_US="Test Tool") + mock_tool.entity.description = Mock() + mock_tool.entity.description.human = I18nObject(en_US="Test description") + mock_tool.entity.output_schema = {} + mock_tool.get_runtime_parameters.return_value = [runtime_param1, runtime_param2] + + # Mock fork_tool_runtime to return the same tool + mock_tool.fork_tool_runtime.return_value = mock_tool + + # Call the method + result = ToolTransformService.convert_tool_entity_to_api_entity(mock_tool, "test_tenant", None) + + # Verify the result + assert isinstance(result, ToolApiEntity) + assert result.parameters is not None + assert len(result.parameters) == 2 + + # Check that both parameters are present + param_names = [p.name for p in result.parameters] + assert "param1" in param_names + assert "runtime_only" in param_names + + # Verify the overridden parameter has runtime version + overridden_param = next((p for p in result.parameters if p.name == "param1"), None) + assert overridden_param is not None + assert overridden_param.label == "Runtime Param 1" + + # Verify the new runtime parameter is included + new_param = next((p for p in result.parameters if p.name == "runtime_only"), None) + assert new_param is not None + assert new_param.label == "Runtime Only Param" + + def test_convert_tool_with_non_form_runtime_parameters(self): + """Test that non-FORM runtime parameters are not added as new parameters""" + # Create mock base parameters + base_param1 = Mock(spec=ToolParameter) + base_param1.name = "param1" + base_param1.form = ToolParameter.ToolParameterForm.FORM + base_param1.type = "string" + base_param1.label = "Base Param 1" + + # Create mock runtime parameters with different forms + runtime_param1 = Mock(spec=ToolParameter) + runtime_param1.name = "param1" + runtime_param1.form = ToolParameter.ToolParameterForm.FORM + runtime_param1.type = "string" + runtime_param1.label = "Runtime Param 1" + + runtime_param2 = Mock(spec=ToolParameter) + runtime_param2.name = "llm_param" + runtime_param2.form = ToolParameter.ToolParameterForm.LLM + runtime_param2.type = "string" + runtime_param2.label = "LLM Param" + + # Create mock tool + mock_tool = Mock(spec=Tool) + mock_tool.entity = Mock() + mock_tool.entity.parameters = [base_param1] + mock_tool.entity.identity = Mock() + mock_tool.entity.identity.author = "test_author" + mock_tool.entity.identity.name = "test_tool" + mock_tool.entity.identity.label = I18nObject(en_US="Test Tool") + mock_tool.entity.description = Mock() + mock_tool.entity.description.human = I18nObject(en_US="Test description") + mock_tool.entity.output_schema = {} + mock_tool.get_runtime_parameters.return_value = [runtime_param1, runtime_param2] + + # Mock fork_tool_runtime to return the same tool + mock_tool.fork_tool_runtime.return_value = mock_tool + + # Call the method + result = ToolTransformService.convert_tool_entity_to_api_entity(mock_tool, "test_tenant", None) + + # Verify the result + assert isinstance(result, ToolApiEntity) + assert result.parameters is not None + assert len(result.parameters) == 1 # Only the FORM parameter should be present + + # Check that only the FORM parameter is present + param_names = [p.name for p in result.parameters] + assert "param1" in param_names + assert "llm_param" not in param_names + + def test_convert_tool_with_empty_parameters(self): + """Test conversion with empty base and runtime parameters""" + # Create mock tool with no parameters + mock_tool = Mock(spec=Tool) + mock_tool.entity = Mock() + mock_tool.entity.parameters = [] + mock_tool.entity.identity = Mock() + mock_tool.entity.identity.author = "test_author" + mock_tool.entity.identity.name = "test_tool" + mock_tool.entity.identity.label = I18nObject(en_US="Test Tool") + mock_tool.entity.description = Mock() + mock_tool.entity.description.human = I18nObject(en_US="Test description") + mock_tool.entity.output_schema = {} + mock_tool.get_runtime_parameters.return_value = [] + + # Mock fork_tool_runtime to return the same tool + mock_tool.fork_tool_runtime.return_value = mock_tool + + # Call the method + result = ToolTransformService.convert_tool_entity_to_api_entity(mock_tool, "test_tenant", None) + + # Verify the result + assert isinstance(result, ToolApiEntity) + assert result.parameters is not None + assert len(result.parameters) == 0 + + def test_convert_tool_with_none_parameters(self): + """Test conversion when base parameters is None""" + # Create mock tool with None parameters + mock_tool = Mock(spec=Tool) + mock_tool.entity = Mock() + mock_tool.entity.parameters = None + mock_tool.entity.identity = Mock() + mock_tool.entity.identity.author = "test_author" + mock_tool.entity.identity.name = "test_tool" + mock_tool.entity.identity.label = I18nObject(en_US="Test Tool") + mock_tool.entity.description = Mock() + mock_tool.entity.description.human = I18nObject(en_US="Test description") + mock_tool.entity.output_schema = {} + mock_tool.get_runtime_parameters.return_value = [] + + # Mock fork_tool_runtime to return the same tool + mock_tool.fork_tool_runtime.return_value = mock_tool + + # Call the method + result = ToolTransformService.convert_tool_entity_to_api_entity(mock_tool, "test_tenant", None) + + # Verify the result + assert isinstance(result, ToolApiEntity) + assert result.parameters is not None + assert len(result.parameters) == 0 + + def test_convert_tool_parameter_order_preserved(self): + """Test that parameter order is preserved correctly""" + # Create mock base parameters in specific order + base_param1 = Mock(spec=ToolParameter) + base_param1.name = "param1" + base_param1.form = ToolParameter.ToolParameterForm.FORM + base_param1.type = "string" + base_param1.label = "Base Param 1" + + base_param2 = Mock(spec=ToolParameter) + base_param2.name = "param2" + base_param2.form = ToolParameter.ToolParameterForm.FORM + base_param2.type = "string" + base_param2.label = "Base Param 2" + + base_param3 = Mock(spec=ToolParameter) + base_param3.name = "param3" + base_param3.form = ToolParameter.ToolParameterForm.FORM + base_param3.type = "string" + base_param3.label = "Base Param 3" + + # Create runtime parameter that overrides middle parameter + runtime_param2 = Mock(spec=ToolParameter) + runtime_param2.name = "param2" + runtime_param2.form = ToolParameter.ToolParameterForm.FORM + runtime_param2.type = "string" + runtime_param2.label = "Runtime Param 2" + + # Create new runtime parameter + runtime_param4 = Mock(spec=ToolParameter) + runtime_param4.name = "param4" + runtime_param4.form = ToolParameter.ToolParameterForm.FORM + runtime_param4.type = "string" + runtime_param4.label = "Runtime Param 4" + + # Create mock tool + mock_tool = Mock(spec=Tool) + mock_tool.entity = Mock() + mock_tool.entity.parameters = [base_param1, base_param2, base_param3] + mock_tool.entity.identity = Mock() + mock_tool.entity.identity.author = "test_author" + mock_tool.entity.identity.name = "test_tool" + mock_tool.entity.identity.label = I18nObject(en_US="Test Tool") + mock_tool.entity.description = Mock() + mock_tool.entity.description.human = I18nObject(en_US="Test description") + mock_tool.entity.output_schema = {} + mock_tool.get_runtime_parameters.return_value = [runtime_param2, runtime_param4] + + # Mock fork_tool_runtime to return the same tool + mock_tool.fork_tool_runtime.return_value = mock_tool + + # Call the method + result = ToolTransformService.convert_tool_entity_to_api_entity(mock_tool, "test_tenant", None) + + # Verify the result + assert isinstance(result, ToolApiEntity) + assert result.parameters is not None + assert len(result.parameters) == 4 + + # Check that order is maintained: base parameters first, then new runtime parameters + param_names = [p.name for p in result.parameters] + assert param_names == ["param1", "param2", "param3", "param4"] + + # Verify that param2 was overridden with runtime version + param2 = result.parameters[1] + assert param2.name == "param2" + assert param2.label == "Runtime Param 2" + + +class TestWorkflowProviderToUserProvider: + """Test cases for ToolTransformService.workflow_provider_to_user_provider method""" + + def test_workflow_provider_to_user_provider_with_workflow_app_id(self): + """Test that workflow_provider_to_user_provider correctly sets workflow_app_id.""" + from core.tools.workflow_as_tool.provider import WorkflowToolProviderController + + # Create mock workflow tool provider controller + workflow_app_id = "app_123" + provider_id = "provider_123" + mock_controller = Mock(spec=WorkflowToolProviderController) + mock_controller.provider_id = provider_id + mock_controller.entity = Mock() + mock_controller.entity.identity = Mock() + mock_controller.entity.identity.author = "test_author" + mock_controller.entity.identity.name = "test_workflow_tool" + mock_controller.entity.identity.description = I18nObject(en_US="Test description") + mock_controller.entity.identity.icon = {"type": "emoji", "content": "🔧"} + mock_controller.entity.identity.icon_dark = None + mock_controller.entity.identity.label = I18nObject(en_US="Test Workflow Tool") + + # Call the method + result = ToolTransformService.workflow_provider_to_user_provider( + provider_controller=mock_controller, + labels=["label1", "label2"], + workflow_app_id=workflow_app_id, + ) + + # Verify the result + assert isinstance(result, ToolProviderApiEntity) + assert result.id == provider_id + assert result.author == "test_author" + assert result.name == "test_workflow_tool" + assert result.type == ToolProviderType.WORKFLOW + assert result.workflow_app_id == workflow_app_id + assert result.labels == ["label1", "label2"] + assert result.is_team_authorization is True + assert result.plugin_id is None + assert result.plugin_unique_identifier is None + assert result.tools == [] + + def test_workflow_provider_to_user_provider_without_workflow_app_id(self): + """Test that workflow_provider_to_user_provider works when workflow_app_id is not provided.""" + from core.tools.workflow_as_tool.provider import WorkflowToolProviderController + + # Create mock workflow tool provider controller + provider_id = "provider_123" + mock_controller = Mock(spec=WorkflowToolProviderController) + mock_controller.provider_id = provider_id + mock_controller.entity = Mock() + mock_controller.entity.identity = Mock() + mock_controller.entity.identity.author = "test_author" + mock_controller.entity.identity.name = "test_workflow_tool" + mock_controller.entity.identity.description = I18nObject(en_US="Test description") + mock_controller.entity.identity.icon = {"type": "emoji", "content": "🔧"} + mock_controller.entity.identity.icon_dark = None + mock_controller.entity.identity.label = I18nObject(en_US="Test Workflow Tool") + + # Call the method without workflow_app_id + result = ToolTransformService.workflow_provider_to_user_provider( + provider_controller=mock_controller, + labels=["label1"], + ) + + # Verify the result + assert isinstance(result, ToolProviderApiEntity) + assert result.id == provider_id + assert result.workflow_app_id is None + assert result.labels == ["label1"] + + def test_workflow_provider_to_user_provider_workflow_app_id_none(self): + """Test that workflow_provider_to_user_provider handles None workflow_app_id explicitly.""" + from core.tools.workflow_as_tool.provider import WorkflowToolProviderController + + # Create mock workflow tool provider controller + provider_id = "provider_123" + mock_controller = Mock(spec=WorkflowToolProviderController) + mock_controller.provider_id = provider_id + mock_controller.entity = Mock() + mock_controller.entity.identity = Mock() + mock_controller.entity.identity.author = "test_author" + mock_controller.entity.identity.name = "test_workflow_tool" + mock_controller.entity.identity.description = I18nObject(en_US="Test description") + mock_controller.entity.identity.icon = {"type": "emoji", "content": "🔧"} + mock_controller.entity.identity.icon_dark = None + mock_controller.entity.identity.label = I18nObject(en_US="Test Workflow Tool") + + # Call the method with explicit None values + result = ToolTransformService.workflow_provider_to_user_provider( + provider_controller=mock_controller, + labels=None, + workflow_app_id=None, + ) + + # Verify the result + assert isinstance(result, ToolProviderApiEntity) + assert result.id == provider_id + assert result.workflow_app_id is None + assert result.labels == [] + + def test_workflow_provider_to_user_provider_preserves_other_fields(self): + """Test that workflow_provider_to_user_provider preserves all other entity fields.""" + from core.tools.workflow_as_tool.provider import WorkflowToolProviderController + + # Create mock workflow tool provider controller with various fields + workflow_app_id = "app_456" + provider_id = "provider_456" + mock_controller = Mock(spec=WorkflowToolProviderController) + mock_controller.provider_id = provider_id + mock_controller.entity = Mock() + mock_controller.entity.identity = Mock() + mock_controller.entity.identity.author = "another_author" + mock_controller.entity.identity.name = "another_workflow_tool" + mock_controller.entity.identity.description = I18nObject( + en_US="Another description", zh_Hans="Another description" + ) + mock_controller.entity.identity.icon = {"type": "emoji", "content": "⚙️"} + mock_controller.entity.identity.icon_dark = {"type": "emoji", "content": "🔧"} + mock_controller.entity.identity.label = I18nObject( + en_US="Another Workflow Tool", zh_Hans="Another Workflow Tool" + ) + + # Call the method + result = ToolTransformService.workflow_provider_to_user_provider( + provider_controller=mock_controller, + labels=["automation", "workflow"], + workflow_app_id=workflow_app_id, + ) + + # Verify all fields are preserved correctly + assert isinstance(result, ToolProviderApiEntity) + assert result.id == provider_id + assert result.author == "another_author" + assert result.name == "another_workflow_tool" + assert result.description.en_US == "Another description" + assert result.description.zh_Hans == "Another description" + assert result.icon == {"type": "emoji", "content": "⚙️"} + assert result.icon_dark == {"type": "emoji", "content": "🔧"} + assert result.label.en_US == "Another Workflow Tool" + assert result.label.zh_Hans == "Another Workflow Tool" + assert result.type == ToolProviderType.WORKFLOW + assert result.workflow_app_id == workflow_app_id + assert result.labels == ["automation", "workflow"] + assert result.masked_credentials == {} + assert result.is_team_authorization is True + assert result.allow_delete is True + assert result.plugin_id is None + assert result.plugin_unique_identifier is None + assert result.tools == [] + + +class TestGetToolProviderIconUrl: + def test_builtin_provider_returns_console_url(self): + with patch(f"{MODULE}.dify_config") as cfg: + cfg.CONSOLE_API_URL = "https://app.dify.ai" + url = ToolTransformService.get_tool_provider_icon_url("builtin", "google", "icon.png") + + assert "/builtin/google/icon" in url + assert url.startswith("https://app.dify.ai/console/api/workspaces/current/tool-provider") + + def test_builtin_provider_with_no_console_url(self): + with patch(f"{MODULE}.dify_config") as cfg: + cfg.CONSOLE_API_URL = None + url = ToolTransformService.get_tool_provider_icon_url("builtin", "slack", "icon.png") + + assert "/builtin/slack/icon" in url + + def test_api_provider_parses_json_icon(self): + icon_json = '{"background": "#fff", "content": "A"}' + result = ToolTransformService.get_tool_provider_icon_url("api", "my-api", icon_json) + assert result == {"background": "#fff", "content": "A"} + + def test_api_provider_returns_dict_icon_directly(self): + icon = {"background": "#000", "content": "B"} + result = ToolTransformService.get_tool_provider_icon_url("api", "my-api", icon) + assert result == icon + + def test_api_provider_returns_fallback_on_invalid_json(self): + result = ToolTransformService.get_tool_provider_icon_url("api", "my-api", "not-json") + assert result == {"background": "#252525", "content": "\ud83d\ude01"} + + def test_workflow_provider_behaves_like_api(self): + icon = {"background": "#123", "content": "W"} + assert ToolTransformService.get_tool_provider_icon_url("workflow", "wf", icon) == icon + + def test_mcp_returns_icon_as_is(self): + assert ToolTransformService.get_tool_provider_icon_url("mcp", "srv", "icon-value") == "icon-value" + + def test_unknown_type_returns_empty(self): + assert ToolTransformService.get_tool_provider_icon_url("unknown", "x", "i") == "" + + +class TestRepackProvider: + def test_repacks_dict_provider_icon(self): + provider = {"type": "builtin", "name": "google", "icon": "old"} + with patch.object(ToolTransformService, "get_tool_provider_icon_url", return_value="/new-url") as mock_fn: + ToolTransformService.repack_provider("t1", provider) + + assert provider["icon"] == "/new-url" + mock_fn.assert_called_once_with(provider_type="builtin", provider_name="google", icon="old") + + def test_repacks_tool_provider_api_entity_without_plugin(self): + entity = MagicMock(spec=ToolProviderApiEntity) + entity.plugin_id = None + entity.type = ToolProviderType.BUILT_IN + entity.name = "slack" + entity.icon = "icon.svg" + entity.icon_dark = "dark.svg" + + with patch.object(ToolTransformService, "get_tool_provider_icon_url", return_value="/url"): + ToolTransformService.repack_provider("t1", entity) + + assert entity.icon == "/url" + assert entity.icon_dark == "/url" + + +class TestConvertMcpSchemaToParameter: + def test_simple_object_schema(self): + schema = { + "type": "object", + "properties": { + "query": {"type": "string", "description": "Search query"}, + "count": {"type": "integer", "description": "Result count"}, + }, + "required": ["query"], + } + + params = ToolTransformService.convert_mcp_schema_to_parameter(schema) + + assert len(params) == 2 + query_param = next(p for p in params if p.name == "query") + count_param = next(p for p in params if p.name == "count") + assert query_param.required is True + assert count_param.required is False + assert count_param.type.value == "number" + + def test_float_maps_to_number(self): + schema = {"type": "object", "properties": {"rate": {"type": "float"}}, "required": []} + assert ToolTransformService.convert_mcp_schema_to_parameter(schema)[0].type.value == "number" + + def test_array_type_attaches_input_schema(self): + prop = {"type": "array", "description": "Items", "items": {"type": "string"}} + schema = {"type": "object", "properties": {"items": prop}, "required": []} + param = ToolTransformService.convert_mcp_schema_to_parameter(schema)[0] + assert param.input_schema is not None + + def test_non_object_schema_returns_empty(self): + assert ToolTransformService.convert_mcp_schema_to_parameter({"type": "string"}) == [] + + def test_missing_properties_returns_empty(self): + assert ToolTransformService.convert_mcp_schema_to_parameter({"type": "object"}) == [] + + def test_list_type_uses_first_element(self): + schema = {"type": "object", "properties": {"f": {"type": ["string", "null"]}}, "required": []} + assert ToolTransformService.convert_mcp_schema_to_parameter(schema)[0].type.value == "string" + + def test_missing_description_defaults_empty(self): + schema = {"type": "object", "properties": {"f": {"type": "string"}}, "required": []} + assert ToolTransformService.convert_mcp_schema_to_parameter(schema)[0].llm_description == "" + + +class TestApiProviderToController: + def test_api_key_header_auth(self): + db_provider = MagicMock() + db_provider.credentials = {"auth_type": "api_key_header"} + with patch(f"{MODULE}.ApiToolProviderController") as ctrl_cls: + ctrl_cls.from_db.return_value = MagicMock() + ToolTransformService.api_provider_to_controller(db_provider) + ctrl_cls.from_db.assert_called_once_with(db_provider=db_provider, auth_type=ApiProviderAuthType.API_KEY_HEADER) + + def test_api_key_query_auth(self): + db_provider = MagicMock() + db_provider.credentials = {"auth_type": "api_key_query"} + with patch(f"{MODULE}.ApiToolProviderController") as ctrl_cls: + ctrl_cls.from_db.return_value = MagicMock() + ToolTransformService.api_provider_to_controller(db_provider) + ctrl_cls.from_db.assert_called_once_with(db_provider=db_provider, auth_type=ApiProviderAuthType.API_KEY_QUERY) + + def test_legacy_api_key_maps_to_header(self): + db_provider = MagicMock() + db_provider.credentials = {"auth_type": "api_key"} + with patch(f"{MODULE}.ApiToolProviderController") as ctrl_cls: + ctrl_cls.from_db.return_value = MagicMock() + ToolTransformService.api_provider_to_controller(db_provider) + ctrl_cls.from_db.assert_called_once_with(db_provider=db_provider, auth_type=ApiProviderAuthType.API_KEY_HEADER) + + def test_unknown_auth_defaults_to_none(self): + db_provider = MagicMock() + db_provider.credentials = {"auth_type": "something_else"} + with patch(f"{MODULE}.ApiToolProviderController") as ctrl_cls: + ctrl_cls.from_db.return_value = MagicMock() + ToolTransformService.api_provider_to_controller(db_provider) + ctrl_cls.from_db.assert_called_once_with(db_provider=db_provider, auth_type=ApiProviderAuthType.NONE) From adc6c6c13b182216f4c53a077ffe996187610b1f Mon Sep 17 00:00:00 2001 From: Stephen Zhou Date: Tue, 31 Mar 2026 11:46:02 +0800 Subject: [PATCH 32/40] chore: try to avoid supply chain security (#34317) --- pnpm-lock.yaml | 6 ++---- pnpm-workspace.yaml | 19 +++++++++++-------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 01a96c5585..b6c234d8ad 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -249,9 +249,6 @@ catalogs: autoprefixer: specifier: 10.4.27 version: 10.4.27 - axios: - specifier: ^1.14.0 - version: 1.14.0 class-variance-authority: specifier: 0.7.1 version: 0.7.1 @@ -573,6 +570,7 @@ overrides: array.prototype.flatmap: npm:@nolyfill/array.prototype.flatmap@^1.0.44 array.prototype.tosorted: npm:@nolyfill/array.prototype.tosorted@^1.0.44 assert: npm:@nolyfill/assert@^1.0.26 + axios: 1.14.0 brace-expansion@<2.0.2: 2.0.2 canvas: ^3.2.2 devalue@<5.3.2: 5.3.2 @@ -652,7 +650,7 @@ importers: sdks/nodejs-client: dependencies: axios: - specifier: 'catalog:' + specifier: 1.14.0 version: 1.14.0 devDependencies: '@eslint/js': diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index dece6f3f4f..ae53a57832 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,12 @@ +trustPolicy: no-downgrade +minimumReleaseAge: 1440 +blockExoticSubdeps: true +strictDepBuilds: true +allowBuilds: + '@parcel/watcher': false + canvas: false + esbuild: false + sharp: false packages: - web - e2e @@ -13,6 +22,7 @@ overrides: array.prototype.flatmap: npm:@nolyfill/array.prototype.flatmap@^1.0.44 array.prototype.tosorted: npm:@nolyfill/array.prototype.tosorted@^1.0.44 assert: npm:@nolyfill/assert@^1.0.26 + axios: 1.14.0 brace-expansion@<2.0.2: 2.0.2 canvas: ^3.2.2 devalue@<5.3.2: 5.3.2 @@ -59,13 +69,6 @@ overrides: which-typed-array: npm:@nolyfill/which-typed-array@^1.0.44 yaml@>=2.0.0 <2.8.3: 2.8.3 yauzl@<3.2.1: 3.2.1 -ignoredBuiltDependencies: - - canvas - - core-js-pure -onlyBuiltDependencies: - - "@parcel/watcher" - - esbuild - - sharp catalog: "@amplitude/analytics-browser": 2.38.0 "@amplitude/plugin-session-replay-browser": 1.27.5 @@ -149,7 +152,7 @@ catalog: agentation: 3.0.2 ahooks: 3.9.7 autoprefixer: 10.4.27 - axios: ^1.14.0 + axios: 1.14.0 class-variance-authority: 0.7.1 clsx: 2.1.1 cmdk: 1.1.1 From 88863609e979d5eb080f6e61be6b1a406773cdcd Mon Sep 17 00:00:00 2001 From: YBoy Date: Tue, 31 Mar 2026 07:56:53 +0300 Subject: [PATCH 33/40] test: migrate rag pipeline controller tests to testcontainers (#34303) --- .../rag_pipeline/test_rag_pipeline.py | 91 +++++++++---------- 1 file changed, 44 insertions(+), 47 deletions(-) rename api/tests/{unit_tests => test_containers_integration_tests}/controllers/console/datasets/rag_pipeline/test_rag_pipeline.py (77%) diff --git a/api/tests/unit_tests/controllers/console/datasets/rag_pipeline/test_rag_pipeline.py b/api/tests/test_containers_integration_tests/controllers/console/datasets/rag_pipeline/test_rag_pipeline.py similarity index 77% rename from api/tests/unit_tests/controllers/console/datasets/rag_pipeline/test_rag_pipeline.py rename to api/tests/test_containers_integration_tests/controllers/console/datasets/rag_pipeline/test_rag_pipeline.py index ebbb34e069..d5ae95dfb7 100644 --- a/api/tests/unit_tests/controllers/console/datasets/rag_pipeline/test_rag_pipeline.py +++ b/api/tests/test_containers_integration_tests/controllers/console/datasets/rag_pipeline/test_rag_pipeline.py @@ -1,6 +1,12 @@ +"""Testcontainers integration tests for rag_pipeline controller endpoints.""" + +from __future__ import annotations + from unittest.mock import MagicMock, patch +from uuid import uuid4 import pytest +from sqlalchemy.orm import Session from controllers.console import console_ns from controllers.console.datasets.rag_pipeline.rag_pipeline import ( @@ -9,6 +15,7 @@ from controllers.console.datasets.rag_pipeline.rag_pipeline import ( PipelineTemplateListApi, PublishCustomizedPipelineTemplateApi, ) +from models.dataset import PipelineCustomizedTemplate def unwrap(func): @@ -18,6 +25,10 @@ def unwrap(func): class TestPipelineTemplateListApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_get_success(self, app): api = PipelineTemplateListApi() method = unwrap(api.get) @@ -38,6 +49,10 @@ class TestPipelineTemplateListApi: class TestPipelineTemplateDetailApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_get_success(self, app): api = PipelineTemplateDetailApi() method = unwrap(api.get) @@ -99,6 +114,10 @@ class TestPipelineTemplateDetailApi: class TestCustomizedPipelineTemplateApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_patch_success(self, app): api = CustomizedPipelineTemplateApi() method = unwrap(api.patch) @@ -136,35 +155,29 @@ class TestCustomizedPipelineTemplateApi: delete_mock.assert_called_once_with("tpl-1") assert response == 200 - def test_post_success(self, app): + def test_post_success(self, app, db_session_with_containers: Session): api = CustomizedPipelineTemplateApi() method = unwrap(api.post) - template = MagicMock() - template.yaml_content = "yaml-data" + tenant_id = str(uuid4()) + template = PipelineCustomizedTemplate( + tenant_id=tenant_id, + name="Test Template", + description="Test", + chunk_structure="hierarchical", + icon={"icon": "📘"}, + position=0, + yaml_content="yaml-data", + install_count=0, + language="en-US", + created_by=str(uuid4()), + ) + db_session_with_containers.add(template) + db_session_with_containers.commit() + db_session_with_containers.expire_all() - fake_db = MagicMock() - fake_db.engine = MagicMock() - - session = MagicMock() - session.query.return_value.where.return_value.first.return_value = template - - session_ctx = MagicMock() - session_ctx.__enter__.return_value = session - session_ctx.__exit__.return_value = None - - with ( - app.test_request_context("/"), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline.db", - fake_db, - ), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline.Session", - return_value=session_ctx, - ), - ): - response, status = method(api, "tpl-1") + with app.test_request_context("/"): + response, status = method(api, template.id) assert status == 200 assert response == {"data": "yaml-data"} @@ -173,32 +186,16 @@ class TestCustomizedPipelineTemplateApi: api = CustomizedPipelineTemplateApi() method = unwrap(api.post) - fake_db = MagicMock() - fake_db.engine = MagicMock() - - session = MagicMock() - session.query.return_value.where.return_value.first.return_value = None - - session_ctx = MagicMock() - session_ctx.__enter__.return_value = session - session_ctx.__exit__.return_value = None - - with ( - app.test_request_context("/"), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline.db", - fake_db, - ), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline.Session", - return_value=session_ctx, - ), - ): + with app.test_request_context("/"): with pytest.raises(ValueError): - method(api, "tpl-1") + method(api, str(uuid4())) class TestPublishCustomizedPipelineTemplateApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_post_success(self, app): api = PublishCustomizedPipelineTemplateApi() method = unwrap(api.post) From 9b7b432e0822c4fffd09d3166132dddd4ae969e7 Mon Sep 17 00:00:00 2001 From: YBoy Date: Tue, 31 Mar 2026 07:57:53 +0300 Subject: [PATCH 34/40] test: migrate rag pipeline import controller tests to testcontainers (#34305) --- .../rag_pipeline/test_rag_pipeline_import.py | 130 +++--------------- 1 file changed, 22 insertions(+), 108 deletions(-) rename api/tests/{unit_tests => test_containers_integration_tests}/controllers/console/datasets/rag_pipeline/test_rag_pipeline_import.py (66%) diff --git a/api/tests/unit_tests/controllers/console/datasets/rag_pipeline/test_rag_pipeline_import.py b/api/tests/test_containers_integration_tests/controllers/console/datasets/rag_pipeline/test_rag_pipeline_import.py similarity index 66% rename from api/tests/unit_tests/controllers/console/datasets/rag_pipeline/test_rag_pipeline_import.py rename to api/tests/test_containers_integration_tests/controllers/console/datasets/rag_pipeline/test_rag_pipeline_import.py index a72ad45110..cb67892878 100644 --- a/api/tests/unit_tests/controllers/console/datasets/rag_pipeline/test_rag_pipeline_import.py +++ b/api/tests/test_containers_integration_tests/controllers/console/datasets/rag_pipeline/test_rag_pipeline_import.py @@ -1,5 +1,11 @@ +"""Testcontainers integration tests for rag_pipeline_import controller endpoints.""" + +from __future__ import annotations + from unittest.mock import MagicMock, patch +import pytest + from controllers.console import console_ns from controllers.console.datasets.rag_pipeline.rag_pipeline_import import ( RagPipelineExportApi, @@ -18,6 +24,10 @@ def unwrap(func): class TestRagPipelineImportApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def _payload(self, mode="create"): return { "mode": mode, @@ -30,7 +40,6 @@ class TestRagPipelineImportApi: method = unwrap(api.post) payload = self._payload() - user = MagicMock() result = MagicMock() result.status = "completed" @@ -39,13 +48,6 @@ class TestRagPipelineImportApi: service = MagicMock() service.import_rag_pipeline.return_value = result - fake_db = MagicMock() - fake_db.engine = MagicMock() - - session_ctx = MagicMock() - session_ctx.__enter__.return_value = MagicMock() - session_ctx.__exit__.return_value = None - with ( app.test_request_context("/", json=payload), patch.object(type(console_ns), "payload", payload), @@ -53,14 +55,6 @@ class TestRagPipelineImportApi: "controllers.console.datasets.rag_pipeline.rag_pipeline_import.current_account_with_tenant", return_value=(user, "tenant"), ), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline_import.db", - fake_db, - ), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline_import.Session", - return_value=session_ctx, - ), patch( "controllers.console.datasets.rag_pipeline.rag_pipeline_import.RagPipelineDslService", return_value=service, @@ -76,7 +70,6 @@ class TestRagPipelineImportApi: method = unwrap(api.post) payload = self._payload() - user = MagicMock() result = MagicMock() result.status = ImportStatus.FAILED @@ -85,13 +78,6 @@ class TestRagPipelineImportApi: service = MagicMock() service.import_rag_pipeline.return_value = result - fake_db = MagicMock() - fake_db.engine = MagicMock() - - session_ctx = MagicMock() - session_ctx.__enter__.return_value = MagicMock() - session_ctx.__exit__.return_value = None - with ( app.test_request_context("/", json=payload), patch.object(type(console_ns), "payload", payload), @@ -99,14 +85,6 @@ class TestRagPipelineImportApi: "controllers.console.datasets.rag_pipeline.rag_pipeline_import.current_account_with_tenant", return_value=(user, "tenant"), ), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline_import.db", - fake_db, - ), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline_import.Session", - return_value=session_ctx, - ), patch( "controllers.console.datasets.rag_pipeline.rag_pipeline_import.RagPipelineDslService", return_value=service, @@ -122,7 +100,6 @@ class TestRagPipelineImportApi: method = unwrap(api.post) payload = self._payload() - user = MagicMock() result = MagicMock() result.status = ImportStatus.PENDING @@ -131,13 +108,6 @@ class TestRagPipelineImportApi: service = MagicMock() service.import_rag_pipeline.return_value = result - fake_db = MagicMock() - fake_db.engine = MagicMock() - - session_ctx = MagicMock() - session_ctx.__enter__.return_value = MagicMock() - session_ctx.__exit__.return_value = None - with ( app.test_request_context("/", json=payload), patch.object(type(console_ns), "payload", payload), @@ -145,14 +115,6 @@ class TestRagPipelineImportApi: "controllers.console.datasets.rag_pipeline.rag_pipeline_import.current_account_with_tenant", return_value=(user, "tenant"), ), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline_import.db", - fake_db, - ), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline_import.Session", - return_value=session_ctx, - ), patch( "controllers.console.datasets.rag_pipeline.rag_pipeline_import.RagPipelineDslService", return_value=service, @@ -165,6 +127,10 @@ class TestRagPipelineImportApi: class TestRagPipelineImportConfirmApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_confirm_success(self, app): api = RagPipelineImportConfirmApi() method = unwrap(api.post) @@ -177,27 +143,12 @@ class TestRagPipelineImportConfirmApi: service = MagicMock() service.confirm_import.return_value = result - fake_db = MagicMock() - fake_db.engine = MagicMock() - - session_ctx = MagicMock() - session_ctx.__enter__.return_value = MagicMock() - session_ctx.__exit__.return_value = None - with ( app.test_request_context("/"), patch( "controllers.console.datasets.rag_pipeline.rag_pipeline_import.current_account_with_tenant", return_value=(user, "tenant"), ), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline_import.db", - fake_db, - ), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline_import.Session", - return_value=session_ctx, - ), patch( "controllers.console.datasets.rag_pipeline.rag_pipeline_import.RagPipelineDslService", return_value=service, @@ -220,27 +171,12 @@ class TestRagPipelineImportConfirmApi: service = MagicMock() service.confirm_import.return_value = result - fake_db = MagicMock() - fake_db.engine = MagicMock() - - session_ctx = MagicMock() - session_ctx.__enter__.return_value = MagicMock() - session_ctx.__exit__.return_value = None - with ( app.test_request_context("/"), patch( "controllers.console.datasets.rag_pipeline.rag_pipeline_import.current_account_with_tenant", return_value=(user, "tenant"), ), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline_import.db", - fake_db, - ), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline_import.Session", - return_value=session_ctx, - ), patch( "controllers.console.datasets.rag_pipeline.rag_pipeline_import.RagPipelineDslService", return_value=service, @@ -253,6 +189,10 @@ class TestRagPipelineImportConfirmApi: class TestRagPipelineImportCheckDependenciesApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_get_success(self, app): api = RagPipelineImportCheckDependenciesApi() method = unwrap(api.get) @@ -264,23 +204,8 @@ class TestRagPipelineImportCheckDependenciesApi: service = MagicMock() service.check_dependencies.return_value = result - fake_db = MagicMock() - fake_db.engine = MagicMock() - - session_ctx = MagicMock() - session_ctx.__enter__.return_value = MagicMock() - session_ctx.__exit__.return_value = None - with ( app.test_request_context("/"), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline_import.db", - fake_db, - ), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline_import.Session", - return_value=session_ctx, - ), patch( "controllers.console.datasets.rag_pipeline.rag_pipeline_import.RagPipelineDslService", return_value=service, @@ -293,6 +218,10 @@ class TestRagPipelineImportCheckDependenciesApi: class TestRagPipelineExportApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_get_with_include_secret(self, app): api = RagPipelineExportApi() method = unwrap(api.get) @@ -301,23 +230,8 @@ class TestRagPipelineExportApi: service = MagicMock() service.export_rag_pipeline_dsl.return_value = {"yaml": "data"} - fake_db = MagicMock() - fake_db.engine = MagicMock() - - session_ctx = MagicMock() - session_ctx.__enter__.return_value = MagicMock() - session_ctx.__exit__.return_value = None - with ( app.test_request_context("/?include_secret=true"), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline_import.db", - fake_db, - ), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline_import.Session", - return_value=session_ctx, - ), patch( "controllers.console.datasets.rag_pipeline.rag_pipeline_import.RagPipelineDslService", return_value=service, From cc68f0e640f0932e4e037ab307e6dc7c4ae8b53f Mon Sep 17 00:00:00 2001 From: YBoy Date: Tue, 31 Mar 2026 07:58:14 +0300 Subject: [PATCH 35/40] test: migrate rag pipeline workflow controller tests to testcontainers (#34306) --- .../test_rag_pipeline_workflow.py | 145 +++++++++--------- 1 file changed, 70 insertions(+), 75 deletions(-) rename api/tests/{unit_tests => test_containers_integration_tests}/controllers/console/datasets/rag_pipeline/test_rag_pipeline_workflow.py (91%) diff --git a/api/tests/unit_tests/controllers/console/datasets/rag_pipeline/test_rag_pipeline_workflow.py b/api/tests/test_containers_integration_tests/controllers/console/datasets/rag_pipeline/test_rag_pipeline_workflow.py similarity index 91% rename from api/tests/unit_tests/controllers/console/datasets/rag_pipeline/test_rag_pipeline_workflow.py rename to api/tests/test_containers_integration_tests/controllers/console/datasets/rag_pipeline/test_rag_pipeline_workflow.py index a3c0592d76..c1f3122c2b 100644 --- a/api/tests/unit_tests/controllers/console/datasets/rag_pipeline/test_rag_pipeline_workflow.py +++ b/api/tests/test_containers_integration_tests/controllers/console/datasets/rag_pipeline/test_rag_pipeline_workflow.py @@ -1,7 +1,13 @@ +"""Testcontainers integration tests for rag_pipeline_workflow controller endpoints.""" + +from __future__ import annotations + from datetime import datetime from unittest.mock import MagicMock, patch +from uuid import uuid4 import pytest +from sqlalchemy.orm import Session from werkzeug.exceptions import BadRequest, Forbidden, HTTPException, NotFound import services @@ -38,6 +44,10 @@ def unwrap(func): class TestDraftWorkflowApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_get_draft_success(self, app): api = DraftRagPipelineApi() method = unwrap(api.get) @@ -200,6 +210,10 @@ class TestDraftWorkflowApi: class TestDraftRunNodes: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_iteration_node_success(self, app): api = RagPipelineDraftRunIterationNodeApi() method = unwrap(api.post) @@ -275,6 +289,10 @@ class TestDraftRunNodes: class TestPipelineRunApis: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_draft_run_success(self, app): api = DraftRagPipelineRunApi() method = unwrap(api.post) @@ -337,6 +355,10 @@ class TestPipelineRunApis: class TestDraftNodeRun: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_execution_not_found(self, app): api = RagPipelineDraftNodeRunApi() method = unwrap(api.post) @@ -364,45 +386,43 @@ class TestDraftNodeRun: class TestPublishedPipelineApis: - def test_publish_success(self, app): + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + + def test_publish_success(self, app, db_session_with_containers: Session): + from models.dataset import Pipeline + api = PublishedRagPipelineApi() method = unwrap(api.post) - pipeline = MagicMock() + tenant_id = str(uuid4()) + pipeline = Pipeline( + tenant_id=tenant_id, + name="test-pipeline", + description="test", + created_by=str(uuid4()), + ) + db_session_with_containers.add(pipeline) + db_session_with_containers.commit() + db_session_with_containers.expire_all() + user = MagicMock(id="u1") workflow = MagicMock( - id="w1", + id=str(uuid4()), created_at=naive_utc_now(), ) - session = MagicMock() - session.merge.return_value = pipeline - - session_ctx = MagicMock() - session_ctx.__enter__.return_value = session - session_ctx.__exit__.return_value = None - service = MagicMock() service.publish_workflow.return_value = workflow - fake_db = MagicMock() - fake_db.engine = MagicMock() - with ( app.test_request_context("/"), patch( "controllers.console.datasets.rag_pipeline.rag_pipeline_workflow.current_account_with_tenant", return_value=(user, "t"), ), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline_workflow.db", - fake_db, - ), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline_workflow.Session", - return_value=session_ctx, - ), patch( "controllers.console.datasets.rag_pipeline.rag_pipeline_workflow.RagPipelineService", return_value=service, @@ -415,6 +435,10 @@ class TestPublishedPipelineApis: class TestMiscApis: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_task_stop(self, app): api = RagPipelineTaskStopApi() method = unwrap(api.post) @@ -471,6 +495,10 @@ class TestMiscApis: class TestPublishedRagPipelineRunApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_published_run_success(self, app): api = PublishedRagPipelineRunApi() method = unwrap(api.post) @@ -536,6 +564,10 @@ class TestPublishedRagPipelineRunApi: class TestDefaultBlockConfigApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_get_block_config_success(self, app): api = DefaultRagPipelineBlockConfigApi() method = unwrap(api.get) @@ -567,6 +599,10 @@ class TestDefaultBlockConfigApi: class TestPublishedAllRagPipelineApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_get_published_workflows_success(self, app): api = PublishedAllRagPipelineApi() method = unwrap(api.get) @@ -577,28 +613,12 @@ class TestPublishedAllRagPipelineApi: service = MagicMock() service.get_all_published_workflow.return_value = ([{"id": "w1"}], False) - session = MagicMock() - session_ctx = MagicMock() - session_ctx.__enter__.return_value = session - session_ctx.__exit__.return_value = None - - fake_db = MagicMock() - fake_db.engine = MagicMock() - with ( app.test_request_context("/"), patch( "controllers.console.datasets.rag_pipeline.rag_pipeline_workflow.current_account_with_tenant", return_value=(user, "t"), ), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline_workflow.db", - fake_db, - ), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline_workflow.Session", - return_value=session_ctx, - ), patch( "controllers.console.datasets.rag_pipeline.rag_pipeline_workflow.RagPipelineService", return_value=service, @@ -628,6 +648,10 @@ class TestPublishedAllRagPipelineApi: class TestRagPipelineByIdApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_patch_success(self, app): api = RagPipelineByIdApi() method = unwrap(api.patch) @@ -640,14 +664,6 @@ class TestRagPipelineByIdApi: service = MagicMock() service.update_workflow.return_value = workflow - session = MagicMock() - session_ctx = MagicMock() - session_ctx.__enter__.return_value = session - session_ctx.__exit__.return_value = None - - fake_db = MagicMock() - fake_db.engine = MagicMock() - payload = {"marked_name": "test"} with ( @@ -657,14 +673,6 @@ class TestRagPipelineByIdApi: "controllers.console.datasets.rag_pipeline.rag_pipeline_workflow.current_account_with_tenant", return_value=(user, "t"), ), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline_workflow.db", - fake_db, - ), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline_workflow.Session", - return_value=session_ctx, - ), patch( "controllers.console.datasets.rag_pipeline.rag_pipeline_workflow.RagPipelineService", return_value=service, @@ -700,24 +708,8 @@ class TestRagPipelineByIdApi: workflow_service = MagicMock() - session = MagicMock() - session_ctx = MagicMock() - session_ctx.__enter__.return_value = session - session_ctx.__exit__.return_value = None - - fake_db = MagicMock() - fake_db.engine = MagicMock() - with ( app.test_request_context("/", method="DELETE"), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline_workflow.db", - fake_db, - ), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline_workflow.Session", - return_value=session_ctx, - ), patch( "controllers.console.datasets.rag_pipeline.rag_pipeline_workflow.WorkflowService", return_value=workflow_service, @@ -725,12 +717,7 @@ class TestRagPipelineByIdApi: ): result = method(api, pipeline, "old-workflow") - workflow_service.delete_workflow.assert_called_once_with( - session=session, - workflow_id="old-workflow", - tenant_id="t1", - ) - session.commit.assert_called_once() + workflow_service.delete_workflow.assert_called_once() assert result == (None, 204) def test_delete_active_workflow_rejected(self, app): @@ -745,6 +732,10 @@ class TestRagPipelineByIdApi: class TestRagPipelineWorkflowLastRunApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_last_run_success(self, app): api = RagPipelineWorkflowLastRunApi() method = unwrap(api.get) @@ -788,6 +779,10 @@ class TestRagPipelineWorkflowLastRunApi: class TestRagPipelineDatasourceVariableApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_set_datasource_variables_success(self, app): api = RagPipelineDatasourceVariableApi() method = unwrap(api.post) From 303f5484085b16a088d2a8d734cfa5d20749ddec Mon Sep 17 00:00:00 2001 From: YBoy Date: Tue, 31 Mar 2026 07:59:13 +0300 Subject: [PATCH 36/40] test: migrate rag pipeline datasets controller tests to testcontainers (#34304) --- .../test_rag_pipeline_datasets.py | 42 ++++++------------- 1 file changed, 12 insertions(+), 30 deletions(-) rename api/tests/{unit_tests => test_containers_integration_tests}/controllers/console/datasets/rag_pipeline/test_rag_pipeline_datasets.py (83%) diff --git a/api/tests/unit_tests/controllers/console/datasets/rag_pipeline/test_rag_pipeline_datasets.py b/api/tests/test_containers_integration_tests/controllers/console/datasets/rag_pipeline/test_rag_pipeline_datasets.py similarity index 83% rename from api/tests/unit_tests/controllers/console/datasets/rag_pipeline/test_rag_pipeline_datasets.py rename to api/tests/test_containers_integration_tests/controllers/console/datasets/rag_pipeline/test_rag_pipeline_datasets.py index fd38fcbb5e..64e3de2ca3 100644 --- a/api/tests/unit_tests/controllers/console/datasets/rag_pipeline/test_rag_pipeline_datasets.py +++ b/api/tests/test_containers_integration_tests/controllers/console/datasets/rag_pipeline/test_rag_pipeline_datasets.py @@ -1,3 +1,7 @@ +"""Testcontainers integration tests for rag_pipeline_datasets controller endpoints.""" + +from __future__ import annotations + from unittest.mock import MagicMock, patch import pytest @@ -19,6 +23,10 @@ def unwrap(func): class TestCreateRagPipelineDatasetApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def _valid_payload(self): return {"yaml_content": "name: test"} @@ -33,13 +41,6 @@ class TestCreateRagPipelineDatasetApi: mock_service = MagicMock() mock_service.create_rag_pipeline_dataset.return_value = import_info - mock_session_ctx = MagicMock() - mock_session_ctx.__enter__.return_value = MagicMock() - mock_session_ctx.__exit__.return_value = None - - fake_db = MagicMock() - fake_db.engine = MagicMock() - with ( app.test_request_context("/", json=payload), patch.object(type(console_ns), "payload", payload), @@ -47,14 +48,6 @@ class TestCreateRagPipelineDatasetApi: "controllers.console.datasets.rag_pipeline.rag_pipeline_datasets.current_account_with_tenant", return_value=(user, "tenant-1"), ), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline_datasets.db", - fake_db, - ), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline_datasets.Session", - return_value=mock_session_ctx, - ), patch( "controllers.console.datasets.rag_pipeline.rag_pipeline_datasets.RagPipelineDslService", return_value=mock_service, @@ -93,13 +86,6 @@ class TestCreateRagPipelineDatasetApi: mock_service = MagicMock() mock_service.create_rag_pipeline_dataset.side_effect = services.errors.dataset.DatasetNameDuplicateError() - mock_session_ctx = MagicMock() - mock_session_ctx.__enter__.return_value = MagicMock() - mock_session_ctx.__exit__.return_value = None - - fake_db = MagicMock() - fake_db.engine = MagicMock() - with ( app.test_request_context("/", json=payload), patch.object(type(console_ns), "payload", payload), @@ -107,14 +93,6 @@ class TestCreateRagPipelineDatasetApi: "controllers.console.datasets.rag_pipeline.rag_pipeline_datasets.current_account_with_tenant", return_value=(user, "tenant-1"), ), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline_datasets.db", - fake_db, - ), - patch( - "controllers.console.datasets.rag_pipeline.rag_pipeline_datasets.Session", - return_value=mock_session_ctx, - ), patch( "controllers.console.datasets.rag_pipeline.rag_pipeline_datasets.RagPipelineDslService", return_value=mock_service, @@ -143,6 +121,10 @@ class TestCreateRagPipelineDatasetApi: class TestCreateEmptyRagPipelineDatasetApi: + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + def test_post_success(self, app): api = CreateEmptyRagPipelineDatasetApi() method = unwrap(api.post) From 1063e021f237922541621a9741595788a389345d Mon Sep 17 00:00:00 2001 From: YBoy Date: Tue, 31 Mar 2026 08:00:22 +0300 Subject: [PATCH 37/40] test: migrate explore conversation controller tests to testcontainers (#34312) --- .../console/explore/test_conversation.py | 61 +++++++++++-------- 1 file changed, 34 insertions(+), 27 deletions(-) rename api/tests/{unit_tests => test_containers_integration_tests}/controllers/console/explore/test_conversation.py (82%) diff --git a/api/tests/unit_tests/controllers/console/explore/test_conversation.py b/api/tests/test_containers_integration_tests/controllers/console/explore/test_conversation.py similarity index 82% rename from api/tests/unit_tests/controllers/console/explore/test_conversation.py rename to api/tests/test_containers_integration_tests/controllers/console/explore/test_conversation.py index 65cc209725..83492048ef 100644 --- a/api/tests/unit_tests/controllers/console/explore/test_conversation.py +++ b/api/tests/test_containers_integration_tests/controllers/console/explore/test_conversation.py @@ -1,7 +1,10 @@ +"""Testcontainers integration tests for controllers.console.explore.conversation endpoints.""" + +from __future__ import annotations + from unittest.mock import MagicMock, patch import pytest -from flask import Flask from werkzeug.exceptions import NotFound import controllers.console.explore.conversation as conversation_module @@ -48,24 +51,12 @@ def user(): return user -@pytest.fixture(autouse=True) -def mock_db_and_session(): - with ( - patch.object( - conversation_module, - "db", - MagicMock(session=MagicMock(), engine=MagicMock()), - ), - patch( - "controllers.console.explore.conversation.Session", - MagicMock(), - ), - ): - yield - - class TestConversationListApi: - def test_get_success(self, app: Flask, chat_app, user): + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + + def test_get_success(self, app, chat_app, user): api = conversation_module.ConversationListApi() method = unwrap(api.get) @@ -90,7 +81,7 @@ class TestConversationListApi: assert result["has_more"] is False assert len(result["data"]) == 2 - def test_last_conversation_not_exists(self, app: Flask, chat_app, user): + def test_last_conversation_not_exists(self, app, chat_app, user): api = conversation_module.ConversationListApi() method = unwrap(api.get) @@ -106,7 +97,7 @@ class TestConversationListApi: with pytest.raises(NotFound): method(chat_app) - def test_wrong_app_mode(self, app: Flask, non_chat_app): + def test_wrong_app_mode(self, app, non_chat_app): api = conversation_module.ConversationListApi() method = unwrap(api.get) @@ -116,7 +107,11 @@ class TestConversationListApi: class TestConversationApi: - def test_delete_success(self, app: Flask, chat_app, user): + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + + def test_delete_success(self, app, chat_app, user): api = conversation_module.ConversationApi() method = unwrap(api.delete) @@ -134,7 +129,7 @@ class TestConversationApi: assert status == 204 assert body["result"] == "success" - def test_delete_not_found(self, app: Flask, chat_app, user): + def test_delete_not_found(self, app, chat_app, user): api = conversation_module.ConversationApi() method = unwrap(api.delete) @@ -150,7 +145,7 @@ class TestConversationApi: with pytest.raises(NotFound): method(chat_app, "cid") - def test_delete_wrong_app_mode(self, app: Flask, non_chat_app): + def test_delete_wrong_app_mode(self, app, non_chat_app): api = conversation_module.ConversationApi() method = unwrap(api.delete) @@ -160,7 +155,11 @@ class TestConversationApi: class TestConversationRenameApi: - def test_rename_success(self, app: Flask, chat_app, user): + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + + def test_rename_success(self, app, chat_app, user): api = conversation_module.ConversationRenameApi() method = unwrap(api.post) @@ -179,7 +178,7 @@ class TestConversationRenameApi: assert result["id"] == "cid" - def test_rename_not_found(self, app: Flask, chat_app, user): + def test_rename_not_found(self, app, chat_app, user): api = conversation_module.ConversationRenameApi() method = unwrap(api.post) @@ -197,7 +196,11 @@ class TestConversationRenameApi: class TestConversationPinApi: - def test_pin_success(self, app: Flask, chat_app, user): + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + + def test_pin_success(self, app, chat_app, user): api = conversation_module.ConversationPinApi() method = unwrap(api.patch) @@ -215,7 +218,11 @@ class TestConversationPinApi: class TestConversationUnPinApi: - def test_unpin_success(self, app: Flask, chat_app, user): + @pytest.fixture + def app(self, flask_app_with_containers): + return flask_app_with_containers + + def test_unpin_success(self, app, chat_app, user): api = conversation_module.ConversationUnPinApi() method = unwrap(api.patch) From 6b0c6d0cde33f2f5b5dc07aa274ce5ec5afabbc8 Mon Sep 17 00:00:00 2001 From: yyh <92089059+lyzno1@users.noreply.github.com> Date: Tue, 31 Mar 2026 15:06:16 +0800 Subject: [PATCH 38/40] fix(web): internationalize DSL export modal labels (#34323) --- web/app/components/workflow/dsl-export-confirm-modal.tsx | 6 +++--- web/i18n/en-US/workflow.json | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/web/app/components/workflow/dsl-export-confirm-modal.tsx b/web/app/components/workflow/dsl-export-confirm-modal.tsx index e698de722e..a92698c8b7 100644 --- a/web/app/components/workflow/dsl-export-confirm-modal.tsx +++ b/web/app/components/workflow/dsl-export-confirm-modal.tsx @@ -45,8 +45,8 @@ const DSLExportConfirmModal = ({ - - + + @@ -56,7 +56,7 @@ const DSLExportConfirmModal = ({
{env.name}
-
Secret
+
{t('env.export.secret', { ns: 'workflow' })}
diff --git a/web/i18n/en-US/workflow.json b/web/i18n/en-US/workflow.json index dd9337ecc0..5c7df02791 100644 --- a/web/i18n/en-US/workflow.json +++ b/web/i18n/en-US/workflow.json @@ -287,7 +287,10 @@ "env.export.checkbox": "Export secret values", "env.export.export": "Export DSL with secret values ", "env.export.ignore": "Export DSL", + "env.export.name": "Name", + "env.export.secret": "Secret", "env.export.title": "Export Secret environment variables?", + "env.export.value": "Value", "env.modal.description": "Description", "env.modal.descriptionPlaceholder": "Describe the variable", "env.modal.editTitle": "Edit Environment Variable", From 4653ed7ead91c7cf82dfaf398f3cba8db62ab3e6 Mon Sep 17 00:00:00 2001 From: hj24 Date: Tue, 31 Mar 2026 18:23:32 +0800 Subject: [PATCH 39/40] refactor: enhance billing info response handling --- api/services/billing_service.py | 56 +++++- api/services/feature_service.py | 5 +- .../services/test_billing_service.py | 183 ++++++++++++++++-- 3 files changed, 225 insertions(+), 19 deletions(-) diff --git a/api/services/billing_service.py b/api/services/billing_service.py index 70d4ce1ee6..13f9d1fcf4 100644 --- a/api/services/billing_service.py +++ b/api/services/billing_service.py @@ -2,7 +2,7 @@ import json import logging import os from collections.abc import Sequence -from typing import Literal +from typing import Literal, NotRequired import httpx from pydantic import TypeAdapter @@ -26,6 +26,56 @@ class SubscriptionPlan(TypedDict): expiration_date: int +class _BillingQuota(TypedDict): + size: int + limit: int + + +class _VectorSpaceQuota(TypedDict): + size: float + limit: int + + +class _KnowledgeRateLimit(TypedDict): + size: NotRequired[int] + limit: int + + +class _BillingSubscription(TypedDict): + plan: str + interval: str + education: bool + + +class BillingInfo(TypedDict): + """Response of /subscription/info. + + NOTE (hj24): + - Fields not listed here (e.g. trigger_event, api_rate_limit) are stripped by TypeAdapter.validate_python() + - To ensure the precision, billing may convert fields like int as str, be careful when use TypeAdapter: + 1. validate_python in non-strict mode will coerce it to the expected type + 2. In strict mode, it will raise ValidationError + 3. To preserve compatibility, always keep non-strict mode here and avoid strict mode + """ + + enabled: bool + subscription: _BillingSubscription + members: _BillingQuota + apps: _BillingQuota + vector_space: _VectorSpaceQuota + knowledge_rate_limit: _KnowledgeRateLimit + documents_upload_quota: _BillingQuota + annotation_quota_limit: _BillingQuota + docs_processing: str + can_replace_logo: bool + model_load_balancing_enabled: bool + knowledge_pipeline_publish_enabled: bool + next_credit_reset_date: NotRequired[int] + + +_billing_info_adapter = TypeAdapter(BillingInfo) + + class BillingService: base_url = os.environ.get("BILLING_API_URL", "BILLING_API_URL") secret_key = os.environ.get("BILLING_API_SECRET_KEY", "BILLING_API_SECRET_KEY") @@ -38,11 +88,11 @@ class BillingService: _PLAN_CACHE_TTL = 600 @classmethod - def get_info(cls, tenant_id: str): + def get_info(cls, tenant_id: str) -> BillingInfo: params = {"tenant_id": tenant_id} billing_info = cls._send_request("GET", "/subscription/info", params=params) - return billing_info + return _billing_info_adapter.validate_python(billing_info) @classmethod def get_tenant_feature_plan_usage_info(cls, tenant_id: str): diff --git a/api/services/feature_service.py b/api/services/feature_service.py index f38e1762d1..56d896629c 100644 --- a/api/services/feature_service.py +++ b/api/services/feature_service.py @@ -312,7 +312,10 @@ class FeatureService: features.apps.limit = billing_info["apps"]["limit"] if "vector_space" in billing_info: - features.vector_space.size = billing_info["vector_space"]["size"] + # NOTE (hj24): billing API returns vector_space.size as float (e.g. 0.0) + # but LimitationModel.size is int; truncate here for compatibility + features.vector_space.size = int(billing_info["vector_space"]["size"]) + # NOTE END features.vector_space.limit = billing_info["vector_space"]["limit"] if "documents_upload_quota" in billing_info: diff --git a/api/tests/unit_tests/services/test_billing_service.py b/api/tests/unit_tests/services/test_billing_service.py index 316381f0ca..4eb35e50b7 100644 --- a/api/tests/unit_tests/services/test_billing_service.py +++ b/api/tests/unit_tests/services/test_billing_service.py @@ -290,9 +290,19 @@ class TestBillingServiceSubscriptionInfo: # Arrange tenant_id = "tenant-123" expected_response = { - "subscription_plan": "professional", - "billing_cycle": "monthly", - "status": "active", + "enabled": True, + "subscription": {"plan": "professional", "interval": "month", "education": False}, + "members": {"size": 1, "limit": 50}, + "apps": {"size": 1, "limit": 200}, + "vector_space": {"size": 0.0, "limit": 20480}, + "knowledge_rate_limit": {"limit": 1000}, + "documents_upload_quota": {"size": 0, "limit": 1000}, + "annotation_quota_limit": {"size": 0, "limit": 5000}, + "docs_processing": "top-priority", + "can_replace_logo": True, + "model_load_balancing_enabled": True, + "knowledge_pipeline_publish_enabled": True, + "next_credit_reset_date": 1775952000, } mock_send_request.return_value = expected_response @@ -1009,17 +1019,14 @@ class TestBillingServiceEdgeCases: yield mock def test_get_info_empty_response(self, mock_send_request): - """Test handling of empty billing info response.""" - # Arrange + """Empty response from billing API should raise ValidationError due to missing required fields.""" + from pydantic import ValidationError + tenant_id = "tenant-empty" mock_send_request.return_value = {} - # Act - result = BillingService.get_info(tenant_id) - - # Assert - assert result == {} - mock_send_request.assert_called_once() + with pytest.raises(ValidationError): + BillingService.get_info(tenant_id) def test_update_tenant_feature_plan_usage_zero_delta(self, mock_send_request): """Test updating tenant feature usage with zero delta (no change).""" @@ -1434,12 +1441,21 @@ class TestBillingServiceIntegrationScenarios: # Step 1: Get current billing info mock_send_request.return_value = { - "subscription_plan": "sandbox", - "billing_cycle": "monthly", - "status": "active", + "enabled": True, + "subscription": {"plan": "sandbox", "interval": "", "education": False}, + "members": {"size": 0, "limit": 1}, + "apps": {"size": 0, "limit": 5}, + "vector_space": {"size": 0.0, "limit": 50}, + "knowledge_rate_limit": {"limit": 10}, + "documents_upload_quota": {"size": 0, "limit": 50}, + "annotation_quota_limit": {"size": 0, "limit": 10}, + "docs_processing": "standard", + "can_replace_logo": False, + "model_load_balancing_enabled": False, + "knowledge_pipeline_publish_enabled": False, } current_info = BillingService.get_info(tenant_id) - assert current_info["subscription_plan"] == "sandbox" + assert current_info["subscription"]["plan"] == "sandbox" # Step 2: Get payment link for upgrade mock_send_request.return_value = {"payment_link": "https://payment.example.com/upgrade"} @@ -1553,3 +1569,140 @@ class TestBillingServiceIntegrationScenarios: mock_send_request.return_value = {"result": "success", "activated": True} activate_result = BillingService.EducationIdentity.activate(account, "token-123", "MIT", "student") assert activate_result["activated"] is True + + +class TestBillingServiceSubscriptionInfoDataType: + """Unit tests for data type coercion in BillingService.get_info + + 1. Verifies the get_info returns correct Python types for numeric fields + 2. Ensure the compatibility regardless of what results the upstream billing API returns + """ + + @pytest.fixture + def mock_send_request(self): + with patch.object(BillingService, "_send_request") as mock: + yield mock + + @pytest.fixture + def normal_billing_response(self) -> dict: + return { + "enabled": True, + "subscription": { + "plan": "team", + "interval": "year", + "education": False, + }, + "members": {"size": 10, "limit": 50}, + "apps": {"size": 80, "limit": 200}, + "vector_space": {"size": 5120.75, "limit": 20480}, + "knowledge_rate_limit": {"limit": 1000}, + "documents_upload_quota": {"size": 450, "limit": 1000}, + "annotation_quota_limit": {"size": 1200, "limit": 5000}, + "docs_processing": "top-priority", + "can_replace_logo": True, + "model_load_balancing_enabled": True, + "knowledge_pipeline_publish_enabled": True, + "next_credit_reset_date": 1745971200, + } + + @pytest.fixture + def string_billing_response(self) -> dict: + return { + "enabled": True, + "subscription": { + "plan": "team", + "interval": "year", + "education": False, + }, + "members": {"size": "10", "limit": "50"}, + "apps": {"size": "80", "limit": "200"}, + "vector_space": {"size": "5120.75", "limit": "20480"}, + "knowledge_rate_limit": {"limit": "1000"}, + "documents_upload_quota": {"size": "450", "limit": "1000"}, + "annotation_quota_limit": {"size": "1200", "limit": "5000"}, + "docs_processing": "top-priority", + "can_replace_logo": True, + "model_load_balancing_enabled": True, + "knowledge_pipeline_publish_enabled": True, + "next_credit_reset_date": "1745971200", + } + + @staticmethod + def _assert_billing_info_types(result: dict): + assert isinstance(result["enabled"], bool) + assert isinstance(result["subscription"]["plan"], str) + assert isinstance(result["subscription"]["interval"], str) + assert isinstance(result["subscription"]["education"], bool) + + assert isinstance(result["members"]["size"], int) + assert isinstance(result["members"]["limit"], int) + + assert isinstance(result["apps"]["size"], int) + assert isinstance(result["apps"]["limit"], int) + + assert isinstance(result["vector_space"]["size"], float) + assert isinstance(result["vector_space"]["limit"], int) + + assert isinstance(result["knowledge_rate_limit"]["limit"], int) + + assert isinstance(result["documents_upload_quota"]["size"], int) + assert isinstance(result["documents_upload_quota"]["limit"], int) + + assert isinstance(result["annotation_quota_limit"]["size"], int) + assert isinstance(result["annotation_quota_limit"]["limit"], int) + + assert isinstance(result["docs_processing"], str) + assert isinstance(result["can_replace_logo"], bool) + assert isinstance(result["model_load_balancing_enabled"], bool) + assert isinstance(result["knowledge_pipeline_publish_enabled"], bool) + if "next_credit_reset_date" in result: + assert isinstance(result["next_credit_reset_date"], int) + + def test_get_info_with_normal_types(self, mock_send_request, normal_billing_response): + """When the billing API returns native numeric types, get_info should preserve them.""" + mock_send_request.return_value = normal_billing_response + + result = BillingService.get_info("tenant-type-test") + + self._assert_billing_info_types(result) + mock_send_request.assert_called_once_with("GET", "/subscription/info", params={"tenant_id": "tenant-type-test"}) + + def test_get_info_with_string_types(self, mock_send_request, string_billing_response): + """When the billing API returns numeric values as strings, get_info should coerce them.""" + mock_send_request.return_value = string_billing_response + + result = BillingService.get_info("tenant-type-test") + + self._assert_billing_info_types(result) + mock_send_request.assert_called_once_with("GET", "/subscription/info", params={"tenant_id": "tenant-type-test"}) + + def test_get_info_without_optional_fields(self, mock_send_request, string_billing_response): + """NotRequired fields can be absent without raising.""" + del string_billing_response["next_credit_reset_date"] + mock_send_request.return_value = string_billing_response + + result = BillingService.get_info("tenant-type-test") + + assert "next_credit_reset_date" not in result + self._assert_billing_info_types(result) + + def test_get_info_with_extra_fields(self, mock_send_request, string_billing_response): + """Undefined fields are silently stripped by validate_python.""" + string_billing_response["new_feature"] = "something" + mock_send_request.return_value = string_billing_response + + result = BillingService.get_info("tenant-type-test") + + # extra fields are dropped by TypeAdapter on TypedDict + assert "new_feature" not in result + self._assert_billing_info_types(result) + + def test_get_info_missing_required_field_raises(self, mock_send_request, string_billing_response): + """Missing a required field should raise ValidationError.""" + from pydantic import ValidationError + + del string_billing_response["members"] + mock_send_request.return_value = string_billing_response + + with pytest.raises(ValidationError): + BillingService.get_info("tenant-type-test") From 919c08045272f909353f4599eba64d5f02be8014 Mon Sep 17 00:00:00 2001 From: hj24 Date: Wed, 1 Apr 2026 10:35:34 +0800 Subject: [PATCH 40/40] chore: update comments --- api/services/billing_service.py | 4 ++++ api/services/feature_service.py | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/api/services/billing_service.py b/api/services/billing_service.py index 13f9d1fcf4..0f0c49e7fe 100644 --- a/api/services/billing_service.py +++ b/api/services/billing_service.py @@ -37,7 +37,11 @@ class _VectorSpaceQuota(TypedDict): class _KnowledgeRateLimit(TypedDict): + # NOTE (hj24): + # 1. Return for sandbox users but is null for other plans, it's defined but never used. + # 2. Keep it for compatibility for now, can be deprecated in future versions. size: NotRequired[int] + # NOTE END limit: int diff --git a/api/services/feature_service.py b/api/services/feature_service.py index 56d896629c..df653e0ba7 100644 --- a/api/services/feature_service.py +++ b/api/services/feature_service.py @@ -336,7 +336,11 @@ class FeatureService: features.model_load_balancing_enabled = billing_info["model_load_balancing_enabled"] if "knowledge_rate_limit" in billing_info: + # NOTE (hj24): + # 1. knowledge_rate_limit size is nullable, currently it's defined but never used, only limit is used. + # 2. So be careful if later we decide to use [size], we cannot assume it is always present. features.knowledge_rate_limit = billing_info["knowledge_rate_limit"]["limit"] + # NOTE END if "knowledge_pipeline_publish_enabled" in billing_info: features.knowledge_pipeline.publish_enabled = billing_info["knowledge_pipeline_publish_enabled"]
NAMEVALUE{t('env.export.name', { ns: 'workflow' })}{t('env.export.value', { ns: 'workflow' })}