diff --git a/.branchlet.json b/.branchlet.json new file mode 100644 index 0000000000..cc13ff9f74 --- /dev/null +++ b/.branchlet.json @@ -0,0 +1,37 @@ +{ + "worktreeCopyPatterns": [ + ".env*", + ".vscode/**", + ".auth/**", + ".claude/**", + "autogpt_platform/.env*", + "autogpt_platform/backend/.env*", + "autogpt_platform/frontend/.env*", + "autogpt_platform/frontend/.auth/**", + "autogpt_platform/db/docker/.env*" + ], + "worktreeCopyIgnores": [ + "**/node_modules/**", + "**/dist/**", + "**/.git/**", + "**/Thumbs.db", + "**/.DS_Store", + "**/.next/**", + "**/__pycache__/**", + "**/.ruff_cache/**", + "**/.pytest_cache/**", + "**/*.pyc", + "**/playwright-report/**", + "**/logs/**", + "**/site/**" + ], + "worktreePathTemplate": "$BASE_PATH.worktree", + "postCreateCmd": [ + "cd autogpt_platform/autogpt_libs && poetry install", + "cd autogpt_platform/backend && poetry install && poetry run prisma generate", + "cd autogpt_platform/frontend && pnpm install", + "cd docs && pip install -r requirements.txt" + ], + "terminalCommand": "code .", + "deleteBranchWithWorktree": false +} diff --git a/.dockerignore b/.dockerignore index 94bf1742f1..c9524ce700 100644 --- a/.dockerignore +++ b/.dockerignore @@ -16,6 +16,7 @@ !autogpt_platform/backend/poetry.lock !autogpt_platform/backend/README.md !autogpt_platform/backend/.env +!autogpt_platform/backend/gen_prisma_types_stub.py # Platform - Market !autogpt_platform/market/market/ diff --git a/.github/workflows/claude-dependabot.yml b/.github/workflows/claude-dependabot.yml index 20b6f1d28e..1fd0da3d8e 100644 --- a/.github/workflows/claude-dependabot.yml +++ b/.github/workflows/claude-dependabot.yml @@ -74,7 +74,7 @@ jobs: - name: Generate Prisma Client working-directory: autogpt_platform/backend - run: poetry run prisma generate + run: poetry run prisma generate && poetry run gen-prisma-stub # Frontend Node.js/pnpm setup (mirrors platform-frontend-ci.yml) - name: Set up Node.js diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 3f5e8c22ec..71c6ef49c2 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -90,7 +90,7 @@ jobs: - name: Generate Prisma Client working-directory: autogpt_platform/backend - run: poetry run prisma generate + run: poetry run prisma generate && poetry run gen-prisma-stub # Frontend Node.js/pnpm setup (mirrors platform-frontend-ci.yml) - name: Set up Node.js diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 13ef01cc44..aac8befee0 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -72,7 +72,7 @@ jobs: - name: Generate Prisma Client working-directory: autogpt_platform/backend - run: poetry run prisma generate + run: poetry run prisma generate && poetry run gen-prisma-stub # Frontend Node.js/pnpm setup (mirrors platform-frontend-ci.yml) - name: Set up Node.js @@ -108,6 +108,16 @@ jobs: # run: pnpm playwright install --with-deps chromium # Docker setup for development environment + - name: Free up disk space + run: | + # Remove large unused tools to free disk space for Docker builds + sudo rm -rf /usr/share/dotnet + sudo rm -rf /usr/local/lib/android + sudo rm -rf /opt/ghc + sudo rm -rf /opt/hostedtoolcache/CodeQL + sudo docker system prune -af + df -h + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 diff --git a/.github/workflows/platform-backend-ci.yml b/.github/workflows/platform-backend-ci.yml index f962382fa5..da5ab83c1c 100644 --- a/.github/workflows/platform-backend-ci.yml +++ b/.github/workflows/platform-backend-ci.yml @@ -134,7 +134,7 @@ jobs: run: poetry install - name: Generate Prisma Client - run: poetry run prisma generate + run: poetry run prisma generate && poetry run gen-prisma-stub - id: supabase name: Start Supabase diff --git a/autogpt_platform/Makefile b/autogpt_platform/Makefile index d99fee49d7..2ff454e392 100644 --- a/autogpt_platform/Makefile +++ b/autogpt_platform/Makefile @@ -12,6 +12,7 @@ reset-db: rm -rf db/docker/volumes/db/data cd backend && poetry run prisma migrate deploy cd backend && poetry run prisma generate + cd backend && poetry run gen-prisma-stub # View logs for core services logs-core: @@ -33,6 +34,7 @@ init-env: migrate: cd backend && poetry run prisma migrate deploy cd backend && poetry run prisma generate + cd backend && poetry run gen-prisma-stub run-backend: cd backend && poetry run app diff --git a/autogpt_platform/backend/Dockerfile b/autogpt_platform/backend/Dockerfile index 7f51bad3a1..b3389d1787 100644 --- a/autogpt_platform/backend/Dockerfile +++ b/autogpt_platform/backend/Dockerfile @@ -48,7 +48,8 @@ RUN poetry install --no-ansi --no-root # Generate Prisma client COPY autogpt_platform/backend/schema.prisma ./ COPY autogpt_platform/backend/backend/data/partial_types.py ./backend/data/partial_types.py -RUN poetry run prisma generate +COPY autogpt_platform/backend/gen_prisma_types_stub.py ./ +RUN poetry run prisma generate && poetry run gen-prisma-stub FROM debian:13-slim AS server_dependencies diff --git a/autogpt_platform/backend/backend/api/features/library/db.py b/autogpt_platform/backend/backend/api/features/library/db.py index 69ed0d2730..1c17e7b36c 100644 --- a/autogpt_platform/backend/backend/api/features/library/db.py +++ b/autogpt_platform/backend/backend/api/features/library/db.py @@ -489,7 +489,7 @@ async def update_agent_version_in_library( agent_graph_version: int, ) -> library_model.LibraryAgent: """ - Updates the agent version in the library if useGraphIsActiveVersion is True. + Updates the agent version in the library for any agent owned by the user. Args: user_id: Owner of the LibraryAgent. @@ -498,20 +498,31 @@ async def update_agent_version_in_library( Raises: DatabaseError: If there's an error with the update. + NotFoundError: If no library agent is found for this user and agent. """ logger.debug( f"Updating agent version in library for user #{user_id}, " f"agent #{agent_graph_id} v{agent_graph_version}" ) - try: - library_agent = await prisma.models.LibraryAgent.prisma().find_first_or_raise( + async with transaction() as tx: + library_agent = await prisma.models.LibraryAgent.prisma(tx).find_first_or_raise( where={ "userId": user_id, "agentGraphId": agent_graph_id, - "useGraphIsActiveVersion": True, }, ) - lib = await prisma.models.LibraryAgent.prisma().update( + + # Delete any conflicting LibraryAgent for the target version + await prisma.models.LibraryAgent.prisma(tx).delete_many( + where={ + "userId": user_id, + "agentGraphId": agent_graph_id, + "agentGraphVersion": agent_graph_version, + "id": {"not": library_agent.id}, + } + ) + + lib = await prisma.models.LibraryAgent.prisma(tx).update( where={"id": library_agent.id}, data={ "AgentGraph": { @@ -525,13 +536,13 @@ async def update_agent_version_in_library( }, include={"AgentGraph": True}, ) - if lib is None: - raise NotFoundError(f"Library agent {library_agent.id} not found") - return library_model.LibraryAgent.from_db(lib) - except prisma.errors.PrismaError as e: - logger.error(f"Database error updating agent version in library: {e}") - raise DatabaseError("Failed to update agent version in library") from e + if lib is None: + raise NotFoundError( + f"Failed to update library agent for {agent_graph_id} v{agent_graph_version}" + ) + + return library_model.LibraryAgent.from_db(lib) async def update_library_agent( @@ -825,6 +836,7 @@ async def add_store_agent_to_library( } }, "isCreatedByUser": False, + "useGraphIsActiveVersion": False, "settings": SafeJson( _initialize_graph_settings(graph_model).model_dump() ), diff --git a/autogpt_platform/backend/backend/api/features/library/model.py b/autogpt_platform/backend/backend/api/features/library/model.py index c20f82afae..56fad7bfd3 100644 --- a/autogpt_platform/backend/backend/api/features/library/model.py +++ b/autogpt_platform/backend/backend/api/features/library/model.py @@ -48,6 +48,7 @@ class LibraryAgent(pydantic.BaseModel): id: str graph_id: str graph_version: int + owner_user_id: str # ID of user who owns/created this agent graph image_url: str | None @@ -163,6 +164,7 @@ class LibraryAgent(pydantic.BaseModel): id=agent.id, graph_id=agent.agentGraphId, graph_version=agent.agentGraphVersion, + owner_user_id=agent.userId, image_url=agent.imageUrl, creator_name=creator_name, creator_image_url=creator_image_url, diff --git a/autogpt_platform/backend/backend/api/features/library/routes_test.py b/autogpt_platform/backend/backend/api/features/library/routes_test.py index ad28b5b6bd..0f05240a7f 100644 --- a/autogpt_platform/backend/backend/api/features/library/routes_test.py +++ b/autogpt_platform/backend/backend/api/features/library/routes_test.py @@ -42,6 +42,7 @@ async def test_get_library_agents_success( id="test-agent-1", graph_id="test-agent-1", graph_version=1, + owner_user_id=test_user_id, name="Test Agent 1", description="Test Description 1", image_url=None, @@ -64,6 +65,7 @@ async def test_get_library_agents_success( id="test-agent-2", graph_id="test-agent-2", graph_version=1, + owner_user_id=test_user_id, name="Test Agent 2", description="Test Description 2", image_url=None, @@ -138,6 +140,7 @@ async def test_get_favorite_library_agents_success( id="test-agent-1", graph_id="test-agent-1", graph_version=1, + owner_user_id=test_user_id, name="Favorite Agent 1", description="Test Favorite Description 1", image_url=None, @@ -205,6 +208,7 @@ def test_add_agent_to_library_success( id="test-library-agent-id", graph_id="test-agent-1", graph_version=1, + owner_user_id=test_user_id, name="Test Agent 1", description="Test Description 1", image_url=None, diff --git a/autogpt_platform/backend/backend/api/features/store/db.py b/autogpt_platform/backend/backend/api/features/store/db.py index 8e5a39df89..8e4310ee02 100644 --- a/autogpt_platform/backend/backend/api/features/store/db.py +++ b/autogpt_platform/backend/backend/api/features/store/db.py @@ -614,6 +614,7 @@ async def get_store_submissions( submission_models = [] for sub in submissions: submission_model = store_model.StoreSubmission( + listing_id=sub.listing_id, agent_id=sub.agent_id, agent_version=sub.agent_version, name=sub.name, @@ -667,35 +668,48 @@ async def delete_store_submission( submission_id: str, ) -> bool: """ - Delete a store listing submission as the submitting user. + Delete a store submission version as the submitting user. Args: user_id: ID of the authenticated user - submission_id: ID of the submission to be deleted + submission_id: StoreListingVersion ID to delete Returns: - bool: True if the submission was successfully deleted, False otherwise + bool: True if successfully deleted """ - logger.debug(f"Deleting store submission {submission_id} for user {user_id}") - try: - # Verify the submission belongs to this user - submission = await prisma.models.StoreListing.prisma().find_first( - where={"agentGraphId": submission_id, "owningUserId": user_id} + # Find the submission version with ownership check + version = await prisma.models.StoreListingVersion.prisma().find_first( + where={"id": submission_id}, include={"StoreListing": True} ) - if not submission: - logger.warning(f"Submission not found for user {user_id}: {submission_id}") - raise store_exceptions.SubmissionNotFoundError( - f"Submission not found for this user. User ID: {user_id}, Submission ID: {submission_id}" + if ( + not version + or not version.StoreListing + or version.StoreListing.owningUserId != user_id + ): + raise store_exceptions.SubmissionNotFoundError("Submission not found") + + # Prevent deletion of approved submissions + if version.submissionStatus == prisma.enums.SubmissionStatus.APPROVED: + raise store_exceptions.InvalidOperationError( + "Cannot delete approved submissions" ) - # Delete the submission - await prisma.models.StoreListing.prisma().delete(where={"id": submission.id}) - - logger.debug( - f"Successfully deleted submission {submission_id} for user {user_id}" + # Delete the version + await prisma.models.StoreListingVersion.prisma().delete( + where={"id": version.id} ) + + # Clean up empty listing if this was the last version + remaining = await prisma.models.StoreListingVersion.prisma().count( + where={"storeListingId": version.storeListingId} + ) + if remaining == 0: + await prisma.models.StoreListing.prisma().delete( + where={"id": version.storeListingId} + ) + return True except Exception as e: @@ -759,9 +773,15 @@ async def create_store_submission( logger.warning( f"Agent not found for user {user_id}: {agent_id} v{agent_version}" ) - raise store_exceptions.AgentNotFoundError( - f"Agent not found for this user. User ID: {user_id}, Agent ID: {agent_id}, Version: {agent_version}" - ) + # Provide more user-friendly error message when agent_id is empty + if not agent_id or agent_id.strip() == "": + raise store_exceptions.AgentNotFoundError( + "No agent selected. Please select an agent before submitting to the store." + ) + else: + raise store_exceptions.AgentNotFoundError( + f"Agent not found for this user. User ID: {user_id}, Agent ID: {agent_id}, Version: {agent_version}" + ) # Check if listing already exists for this agent existing_listing = await prisma.models.StoreListing.prisma().find_first( @@ -833,6 +853,7 @@ async def create_store_submission( logger.debug(f"Created store listing for agent {agent_id}") # Return submission details return store_model.StoreSubmission( + listing_id=listing.id, agent_id=agent_id, agent_version=agent_version, name=name, @@ -944,81 +965,56 @@ async def edit_store_submission( # Currently we are not allowing user to update the agent associated with a submission # If we allow it in future, then we need a check here to verify the agent belongs to this user. - # Check if we can edit this submission - if current_version.submissionStatus == prisma.enums.SubmissionStatus.REJECTED: + # Only allow editing of PENDING submissions + if current_version.submissionStatus != prisma.enums.SubmissionStatus.PENDING: raise store_exceptions.InvalidOperationError( - "Cannot edit a rejected submission" - ) - - # For APPROVED submissions, we need to create a new version - if current_version.submissionStatus == prisma.enums.SubmissionStatus.APPROVED: - # Create a new version for the existing listing - return await create_store_version( - user_id=user_id, - agent_id=current_version.agentGraphId, - agent_version=current_version.agentGraphVersion, - store_listing_id=current_version.storeListingId, - name=name, - video_url=video_url, - agent_output_demo_url=agent_output_demo_url, - image_urls=image_urls, - description=description, - sub_heading=sub_heading, - categories=categories, - changes_summary=changes_summary, - recommended_schedule_cron=recommended_schedule_cron, - instructions=instructions, + f"Cannot edit a {current_version.submissionStatus.value.lower()} submission. Only pending submissions can be edited." ) # For PENDING submissions, we can update the existing version - elif current_version.submissionStatus == prisma.enums.SubmissionStatus.PENDING: - # Update the existing version - updated_version = await prisma.models.StoreListingVersion.prisma().update( - where={"id": store_listing_version_id}, - data=prisma.types.StoreListingVersionUpdateInput( - name=name, - videoUrl=video_url, - agentOutputDemoUrl=agent_output_demo_url, - imageUrls=image_urls, - description=description, - categories=categories, - subHeading=sub_heading, - changesSummary=changes_summary, - recommendedScheduleCron=recommended_schedule_cron, - instructions=instructions, - ), - ) - - logger.debug( - f"Updated existing version {store_listing_version_id} for agent {current_version.agentGraphId}" - ) - - if not updated_version: - raise DatabaseError("Failed to update store listing version") - return store_model.StoreSubmission( - agent_id=current_version.agentGraphId, - agent_version=current_version.agentGraphVersion, + # Update the existing version + updated_version = await prisma.models.StoreListingVersion.prisma().update( + where={"id": store_listing_version_id}, + data=prisma.types.StoreListingVersionUpdateInput( name=name, - sub_heading=sub_heading, - slug=current_version.StoreListing.slug, + videoUrl=video_url, + agentOutputDemoUrl=agent_output_demo_url, + imageUrls=image_urls, description=description, - instructions=instructions, - image_urls=image_urls, - date_submitted=updated_version.submittedAt or updated_version.createdAt, - status=updated_version.submissionStatus, - runs=0, - rating=0.0, - store_listing_version_id=updated_version.id, - changes_summary=changes_summary, - video_url=video_url, categories=categories, - version=updated_version.version, - ) + subHeading=sub_heading, + changesSummary=changes_summary, + recommendedScheduleCron=recommended_schedule_cron, + instructions=instructions, + ), + ) - else: - raise store_exceptions.InvalidOperationError( - f"Cannot edit submission with status: {current_version.submissionStatus}" - ) + logger.debug( + f"Updated existing version {store_listing_version_id} for agent {current_version.agentGraphId}" + ) + + if not updated_version: + raise DatabaseError("Failed to update store listing version") + return store_model.StoreSubmission( + listing_id=current_version.StoreListing.id, + agent_id=current_version.agentGraphId, + agent_version=current_version.agentGraphVersion, + name=name, + sub_heading=sub_heading, + slug=current_version.StoreListing.slug, + description=description, + instructions=instructions, + image_urls=image_urls, + date_submitted=updated_version.submittedAt or updated_version.createdAt, + status=updated_version.submissionStatus, + runs=0, + rating=0.0, + store_listing_version_id=updated_version.id, + changes_summary=changes_summary, + video_url=video_url, + categories=categories, + version=updated_version.version, + ) except ( store_exceptions.SubmissionNotFoundError, @@ -1097,38 +1093,78 @@ async def create_store_version( f"Agent not found for this user. User ID: {user_id}, Agent ID: {agent_id}, Version: {agent_version}" ) - # Get the latest version number - latest_version = listing.Versions[0] if listing.Versions else None - - next_version = (latest_version.version + 1) if latest_version else 1 - - # Create a new version for the existing listing - new_version = await prisma.models.StoreListingVersion.prisma().create( - data=prisma.types.StoreListingVersionCreateInput( - version=next_version, - agentGraphId=agent_id, - agentGraphVersion=agent_version, - name=name, - videoUrl=video_url, - agentOutputDemoUrl=agent_output_demo_url, - imageUrls=image_urls, - description=description, - instructions=instructions, - categories=categories, - subHeading=sub_heading, - submissionStatus=prisma.enums.SubmissionStatus.PENDING, - submittedAt=datetime.now(), - changesSummary=changes_summary, - recommendedScheduleCron=recommended_schedule_cron, - storeListingId=store_listing_id, + # Check if there's already a PENDING submission for this agent (any version) + existing_pending_submission = ( + await prisma.models.StoreListingVersion.prisma().find_first( + where=prisma.types.StoreListingVersionWhereInput( + storeListingId=store_listing_id, + agentGraphId=agent_id, + submissionStatus=prisma.enums.SubmissionStatus.PENDING, + isDeleted=False, + ) ) ) + # Handle existing pending submission and create new one atomically + async with transaction() as tx: + # Get the latest version number first + latest_listing = await prisma.models.StoreListing.prisma(tx).find_first( + where=prisma.types.StoreListingWhereInput( + id=store_listing_id, owningUserId=user_id + ), + include={"Versions": {"order_by": {"version": "desc"}, "take": 1}}, + ) + + if not latest_listing: + raise store_exceptions.ListingNotFoundError( + f"Store listing not found. User ID: {user_id}, Listing ID: {store_listing_id}" + ) + + latest_version = ( + latest_listing.Versions[0] if latest_listing.Versions else None + ) + next_version = (latest_version.version + 1) if latest_version else 1 + + # If there's an existing pending submission, delete it atomically before creating new one + if existing_pending_submission: + logger.info( + f"Found existing PENDING submission for agent {agent_id} (was v{existing_pending_submission.agentGraphVersion}, now v{agent_version}), replacing existing submission instead of creating duplicate" + ) + await prisma.models.StoreListingVersion.prisma(tx).delete( + where={"id": existing_pending_submission.id} + ) + logger.debug( + f"Deleted existing pending submission {existing_pending_submission.id}" + ) + + # Create a new version for the existing listing + new_version = await prisma.models.StoreListingVersion.prisma(tx).create( + data=prisma.types.StoreListingVersionCreateInput( + version=next_version, + agentGraphId=agent_id, + agentGraphVersion=agent_version, + name=name, + videoUrl=video_url, + agentOutputDemoUrl=agent_output_demo_url, + imageUrls=image_urls, + description=description, + instructions=instructions, + categories=categories, + subHeading=sub_heading, + submissionStatus=prisma.enums.SubmissionStatus.PENDING, + submittedAt=datetime.now(), + changesSummary=changes_summary, + recommendedScheduleCron=recommended_schedule_cron, + storeListingId=store_listing_id, + ) + ) + logger.debug( f"Created new version for listing {store_listing_id} of agent {agent_id}" ) # Return submission details return store_model.StoreSubmission( + listing_id=listing.id, agent_id=agent_id, agent_version=agent_version, name=name, @@ -1708,15 +1744,12 @@ async def review_store_submission( # Convert to Pydantic model for consistency return store_model.StoreSubmission( + listing_id=(submission.StoreListing.id if submission.StoreListing else ""), agent_id=submission.agentGraphId, agent_version=submission.agentGraphVersion, name=submission.name, sub_heading=submission.subHeading, - slug=( - submission.StoreListing.slug - if hasattr(submission, "storeListing") and submission.StoreListing - else "" - ), + slug=(submission.StoreListing.slug if submission.StoreListing else ""), description=submission.description, instructions=submission.instructions, image_urls=submission.imageUrls or [], @@ -1818,9 +1851,7 @@ async def get_admin_listings_with_versions( where = prisma.types.StoreListingWhereInput(**where_dict) include = prisma.types.StoreListingInclude( Versions=prisma.types.FindManyStoreListingVersionArgsFromStoreListing( - order_by=prisma.types._StoreListingVersion_version_OrderByInput( - version="desc" - ) + order_by={"version": "desc"} ), OwningUser=True, ) @@ -1845,6 +1876,7 @@ async def get_admin_listings_with_versions( # If we have versions, turn them into StoreSubmission models for version in listing.Versions or []: version_model = store_model.StoreSubmission( + listing_id=listing.id, agent_id=version.agentGraphId, agent_version=version.agentGraphVersion, name=version.name, diff --git a/autogpt_platform/backend/backend/api/features/store/model.py b/autogpt_platform/backend/backend/api/features/store/model.py index 972898b296..077135217a 100644 --- a/autogpt_platform/backend/backend/api/features/store/model.py +++ b/autogpt_platform/backend/backend/api/features/store/model.py @@ -110,6 +110,7 @@ class Profile(pydantic.BaseModel): class StoreSubmission(pydantic.BaseModel): + listing_id: str agent_id: str agent_version: int name: str @@ -164,8 +165,12 @@ class StoreListingsWithVersionsResponse(pydantic.BaseModel): class StoreSubmissionRequest(pydantic.BaseModel): - agent_id: str - agent_version: int + agent_id: str = pydantic.Field( + ..., min_length=1, description="Agent ID cannot be empty" + ) + agent_version: int = pydantic.Field( + ..., gt=0, description="Agent version must be greater than 0" + ) slug: str name: str sub_heading: str diff --git a/autogpt_platform/backend/backend/api/features/store/model_test.py b/autogpt_platform/backend/backend/api/features/store/model_test.py index a37966601b..fd09a0cf77 100644 --- a/autogpt_platform/backend/backend/api/features/store/model_test.py +++ b/autogpt_platform/backend/backend/api/features/store/model_test.py @@ -138,6 +138,7 @@ def test_creator_details(): def test_store_submission(): submission = store_model.StoreSubmission( + listing_id="listing123", agent_id="agent123", agent_version=1, sub_heading="Test subheading", @@ -159,6 +160,7 @@ def test_store_submissions_response(): response = store_model.StoreSubmissionsResponse( submissions=[ store_model.StoreSubmission( + listing_id="listing123", agent_id="agent123", agent_version=1, sub_heading="Test subheading", diff --git a/autogpt_platform/backend/backend/api/features/store/routes_test.py b/autogpt_platform/backend/backend/api/features/store/routes_test.py index 7fdc0b9ebb..36431c20ec 100644 --- a/autogpt_platform/backend/backend/api/features/store/routes_test.py +++ b/autogpt_platform/backend/backend/api/features/store/routes_test.py @@ -521,6 +521,7 @@ def test_get_submissions_success( mocked_value = store_model.StoreSubmissionsResponse( submissions=[ store_model.StoreSubmission( + listing_id="test-listing-id", name="Test Agent", description="Test agent description", image_urls=["test.jpg"], diff --git a/autogpt_platform/backend/backend/blocks/airtable/_webhook.py b/autogpt_platform/backend/backend/blocks/airtable/_webhook.py index 58e6f95d0c..452630953e 100644 --- a/autogpt_platform/backend/backend/blocks/airtable/_webhook.py +++ b/autogpt_platform/backend/backend/blocks/airtable/_webhook.py @@ -6,6 +6,9 @@ import hashlib import hmac import logging from enum import Enum +from typing import cast + +from prisma.types import Serializable from backend.sdk import ( BaseWebhooksManager, @@ -84,7 +87,9 @@ class AirtableWebhookManager(BaseWebhooksManager): # update webhook config await update_webhook( webhook.id, - config={"base_id": base_id, "cursor": response.cursor}, + config=cast( + dict[str, Serializable], {"base_id": base_id, "cursor": response.cursor} + ), ) event_type = "notification" diff --git a/autogpt_platform/backend/backend/blocks/helpers/review.py b/autogpt_platform/backend/backend/blocks/helpers/review.py new file mode 100644 index 0000000000..f35397e6aa --- /dev/null +++ b/autogpt_platform/backend/backend/blocks/helpers/review.py @@ -0,0 +1,184 @@ +""" +Shared helpers for Human-In-The-Loop (HITL) review functionality. +Used by both the dedicated HumanInTheLoopBlock and blocks that require human review. +""" + +import logging +from typing import Any, Optional + +from prisma.enums import ReviewStatus +from pydantic import BaseModel + +from backend.data.execution import ExecutionContext, ExecutionStatus +from backend.data.human_review import ReviewResult +from backend.executor.manager import async_update_node_execution_status +from backend.util.clients import get_database_manager_async_client + +logger = logging.getLogger(__name__) + + +class ReviewDecision(BaseModel): + """Result of a review decision.""" + + should_proceed: bool + message: str + review_result: ReviewResult + + +class HITLReviewHelper: + """Helper class for Human-In-The-Loop review operations.""" + + @staticmethod + async def get_or_create_human_review(**kwargs) -> Optional[ReviewResult]: + """Create or retrieve a human review from the database.""" + return await get_database_manager_async_client().get_or_create_human_review( + **kwargs + ) + + @staticmethod + async def update_node_execution_status(**kwargs) -> None: + """Update the execution status of a node.""" + await async_update_node_execution_status( + db_client=get_database_manager_async_client(), **kwargs + ) + + @staticmethod + async def update_review_processed_status( + node_exec_id: str, processed: bool + ) -> None: + """Update the processed status of a review.""" + return await get_database_manager_async_client().update_review_processed_status( + node_exec_id, processed + ) + + @staticmethod + async def _handle_review_request( + input_data: Any, + user_id: str, + node_exec_id: str, + graph_exec_id: str, + graph_id: str, + graph_version: int, + execution_context: ExecutionContext, + block_name: str = "Block", + editable: bool = False, + ) -> Optional[ReviewResult]: + """ + Handle a review request for a block that requires human review. + + Args: + input_data: The input data to be reviewed + user_id: ID of the user requesting the review + node_exec_id: ID of the node execution + graph_exec_id: ID of the graph execution + graph_id: ID of the graph + graph_version: Version of the graph + execution_context: Current execution context + block_name: Name of the block requesting review + editable: Whether the reviewer can edit the data + + Returns: + ReviewResult if review is complete, None if waiting for human input + + Raises: + Exception: If review creation or status update fails + """ + # Skip review if safe mode is disabled - return auto-approved result + if not execution_context.safe_mode: + logger.info( + f"Block {block_name} skipping review for node {node_exec_id} - safe mode disabled" + ) + return ReviewResult( + data=input_data, + status=ReviewStatus.APPROVED, + message="Auto-approved (safe mode disabled)", + processed=True, + node_exec_id=node_exec_id, + ) + + result = await HITLReviewHelper.get_or_create_human_review( + user_id=user_id, + node_exec_id=node_exec_id, + graph_exec_id=graph_exec_id, + graph_id=graph_id, + graph_version=graph_version, + input_data=input_data, + message=f"Review required for {block_name} execution", + editable=editable, + ) + + if result is None: + logger.info( + f"Block {block_name} pausing execution for node {node_exec_id} - awaiting human review" + ) + await HITLReviewHelper.update_node_execution_status( + exec_id=node_exec_id, + status=ExecutionStatus.REVIEW, + ) + return None # Signal that execution should pause + + # Mark review as processed if not already done + if not result.processed: + await HITLReviewHelper.update_review_processed_status( + node_exec_id=node_exec_id, processed=True + ) + + return result + + @staticmethod + async def handle_review_decision( + input_data: Any, + user_id: str, + node_exec_id: str, + graph_exec_id: str, + graph_id: str, + graph_version: int, + execution_context: ExecutionContext, + block_name: str = "Block", + editable: bool = False, + ) -> Optional[ReviewDecision]: + """ + Handle a review request and return the decision in a single call. + + Args: + input_data: The input data to be reviewed + user_id: ID of the user requesting the review + node_exec_id: ID of the node execution + graph_exec_id: ID of the graph execution + graph_id: ID of the graph + graph_version: Version of the graph + execution_context: Current execution context + block_name: Name of the block requesting review + editable: Whether the reviewer can edit the data + + Returns: + ReviewDecision if review is complete (approved/rejected), + None if execution should pause (awaiting review) + """ + review_result = await HITLReviewHelper._handle_review_request( + input_data=input_data, + user_id=user_id, + node_exec_id=node_exec_id, + graph_exec_id=graph_exec_id, + graph_id=graph_id, + graph_version=graph_version, + execution_context=execution_context, + block_name=block_name, + editable=editable, + ) + + if review_result is None: + # Still awaiting review - return None to pause execution + return None + + # Review is complete, determine outcome + should_proceed = review_result.status == ReviewStatus.APPROVED + message = review_result.message or ( + "Execution approved by reviewer" + if should_proceed + else "Execution rejected by reviewer" + ) + + return ReviewDecision( + should_proceed=should_proceed, message=message, review_result=review_result + ) diff --git a/autogpt_platform/backend/backend/blocks/human_in_the_loop.py b/autogpt_platform/backend/backend/blocks/human_in_the_loop.py index 13c9fb31db..1e338816c8 100644 --- a/autogpt_platform/backend/backend/blocks/human_in_the_loop.py +++ b/autogpt_platform/backend/backend/blocks/human_in_the_loop.py @@ -3,6 +3,7 @@ from typing import Any from prisma.enums import ReviewStatus +from backend.blocks.helpers.review import HITLReviewHelper from backend.data.block import ( Block, BlockCategory, @@ -11,11 +12,9 @@ from backend.data.block import ( BlockSchemaOutput, BlockType, ) -from backend.data.execution import ExecutionContext, ExecutionStatus +from backend.data.execution import ExecutionContext from backend.data.human_review import ReviewResult from backend.data.model import SchemaField -from backend.executor.manager import async_update_node_execution_status -from backend.util.clients import get_database_manager_async_client logger = logging.getLogger(__name__) @@ -72,32 +71,26 @@ class HumanInTheLoopBlock(Block): ("approved_data", {"name": "John Doe", "age": 30}), ], test_mock={ - "get_or_create_human_review": lambda *_args, **_kwargs: ReviewResult( - data={"name": "John Doe", "age": 30}, - status=ReviewStatus.APPROVED, - message="", - processed=False, - node_exec_id="test-node-exec-id", - ), - "update_node_execution_status": lambda *_args, **_kwargs: None, - "update_review_processed_status": lambda *_args, **_kwargs: None, + "handle_review_decision": lambda **kwargs: type( + "ReviewDecision", + (), + { + "should_proceed": True, + "message": "Test approval message", + "review_result": ReviewResult( + data={"name": "John Doe", "age": 30}, + status=ReviewStatus.APPROVED, + message="", + processed=False, + node_exec_id="test-node-exec-id", + ), + }, + )(), }, ) - async def get_or_create_human_review(self, **kwargs): - return await get_database_manager_async_client().get_or_create_human_review( - **kwargs - ) - - async def update_node_execution_status(self, **kwargs): - return await async_update_node_execution_status( - db_client=get_database_manager_async_client(), **kwargs - ) - - async def update_review_processed_status(self, node_exec_id: str, processed: bool): - return await get_database_manager_async_client().update_review_processed_status( - node_exec_id, processed - ) + async def handle_review_decision(self, **kwargs): + return await HITLReviewHelper.handle_review_decision(**kwargs) async def run( self, @@ -109,7 +102,7 @@ class HumanInTheLoopBlock(Block): graph_id: str, graph_version: int, execution_context: ExecutionContext, - **kwargs, + **_kwargs, ) -> BlockOutput: if not execution_context.safe_mode: logger.info( @@ -119,48 +112,28 @@ class HumanInTheLoopBlock(Block): yield "review_message", "Auto-approved (safe mode disabled)" return - try: - result = await self.get_or_create_human_review( - user_id=user_id, - node_exec_id=node_exec_id, - graph_exec_id=graph_exec_id, - graph_id=graph_id, - graph_version=graph_version, - input_data=input_data.data, - message=input_data.name, - editable=input_data.editable, - ) - except Exception as e: - logger.error(f"Error in HITL block for node {node_exec_id}: {str(e)}") - raise + decision = await self.handle_review_decision( + input_data=input_data.data, + user_id=user_id, + node_exec_id=node_exec_id, + graph_exec_id=graph_exec_id, + graph_id=graph_id, + graph_version=graph_version, + execution_context=execution_context, + block_name=self.name, + editable=input_data.editable, + ) - if result is None: - logger.info( - f"HITL block pausing execution for node {node_exec_id} - awaiting human review" - ) - try: - await self.update_node_execution_status( - exec_id=node_exec_id, - status=ExecutionStatus.REVIEW, - ) - return - except Exception as e: - logger.error( - f"Failed to update node status for HITL block {node_exec_id}: {str(e)}" - ) - raise + if decision is None: + return - if not result.processed: - await self.update_review_processed_status( - node_exec_id=node_exec_id, processed=True - ) + status = decision.review_result.status + if status == ReviewStatus.APPROVED: + yield "approved_data", decision.review_result.data + elif status == ReviewStatus.REJECTED: + yield "rejected_data", decision.review_result.data + else: + raise RuntimeError(f"Unexpected review status: {status}") - if result.status == ReviewStatus.APPROVED: - yield "approved_data", result.data - if result.message: - yield "review_message", result.message - - elif result.status == ReviewStatus.REJECTED: - yield "rejected_data", result.data - if result.message: - yield "review_message", result.message + if decision.message: + yield "review_message", decision.message diff --git a/autogpt_platform/backend/backend/blocks/reddit.py b/autogpt_platform/backend/backend/blocks/reddit.py index 231e7affef..1109d568db 100644 --- a/autogpt_platform/backend/backend/blocks/reddit.py +++ b/autogpt_platform/backend/backend/blocks/reddit.py @@ -3,6 +3,7 @@ from datetime import datetime, timezone from typing import Iterator, Literal import praw +from praw.models import Comment, MoreComments, Submission from pydantic import BaseModel, SecretStr from backend.data.block import ( @@ -15,33 +16,51 @@ from backend.data.block import ( from backend.data.model import ( CredentialsField, CredentialsMetaInput, + OAuth2Credentials, SchemaField, - UserPasswordCredentials, ) from backend.integrations.providers import ProviderName from backend.util.mock import MockObject from backend.util.settings import Settings -RedditCredentials = UserPasswordCredentials +# Type aliases for Reddit API options +UserPostSort = Literal["new", "hot", "top", "controversial"] +SearchSort = Literal["relevance", "hot", "top", "new", "comments"] +TimeFilter = Literal["all", "day", "hour", "month", "week", "year"] +CommentSort = Literal["best", "top", "new", "controversial", "old", "qa"] +InboxType = Literal["all", "unread", "messages", "mentions", "comment_replies"] + +RedditCredentials = OAuth2Credentials RedditCredentialsInput = CredentialsMetaInput[ Literal[ProviderName.REDDIT], - Literal["user_password"], + Literal["oauth2"], ] def RedditCredentialsField() -> RedditCredentialsInput: """Creates a Reddit credentials input on a block.""" return CredentialsField( - description="The Reddit integration requires a username and password.", + description="Connect your Reddit account to access Reddit features.", ) -TEST_CREDENTIALS = UserPasswordCredentials( +TEST_CREDENTIALS = OAuth2Credentials( id="01234567-89ab-cdef-0123-456789abcdef", provider="reddit", - username=SecretStr("mock-reddit-username"), - password=SecretStr("mock-reddit-password"), + access_token=SecretStr("mock-reddit-access-token"), + refresh_token=SecretStr("mock-reddit-refresh-token"), + access_token_expires_at=9999999999, + scopes=[ + "identity", + "read", + "submit", + "edit", + "history", + "privatemessages", + "flair", + ], title="Mock Reddit credentials", + username="mock-reddit-username", ) TEST_CREDENTIALS_INPUT = { @@ -53,27 +72,29 @@ TEST_CREDENTIALS_INPUT = { class RedditPost(BaseModel): - id: str + post_id: str subreddit: str title: str body: str -class RedditComment(BaseModel): - post_id: str - comment: str - - settings = Settings() logger = logging.getLogger(__name__) def get_praw(creds: RedditCredentials) -> praw.Reddit: + """ + Create a PRAW Reddit client using OAuth2 credentials. + + Uses the refresh_token for authentication, which allows the client + to automatically refresh the access token when needed. + """ client = praw.Reddit( client_id=settings.secrets.reddit_client_id, client_secret=settings.secrets.reddit_client_secret, - username=creds.username.get_secret_value(), - password=creds.password.get_secret_value(), + refresh_token=( + creds.refresh_token.get_secret_value() if creds.refresh_token else None + ), user_agent=settings.config.reddit_user_agent, ) me = client.user.me() @@ -83,11 +104,36 @@ def get_praw(creds: RedditCredentials) -> praw.Reddit: return client +def strip_reddit_prefix(id_str: str) -> str: + """ + Strip Reddit type prefix (t1_, t3_, etc.) from an ID if present. + + Reddit uses type prefixes like t1_ for comments, t3_ for posts, etc. + This helper normalizes IDs by removing these prefixes when present, + allowing blocks to accept both 'abc123' and 't3_abc123' formats. + + Args: + id_str: The ID string that may have a Reddit type prefix. + + Returns: + The ID without the type prefix. + """ + if ( + len(id_str) > 3 + and id_str[0] == "t" + and id_str[1].isdigit() + and id_str[2] == "_" + ): + return id_str[3:] + return id_str + + class GetRedditPostsBlock(Block): class Input(BlockSchemaInput): subreddit: str = SchemaField( description="Subreddit name, excluding the /r/ prefix", default="writingprompts", + advanced=False, ) credentials: RedditCredentialsInput = RedditCredentialsField() last_minutes: int | None = SchemaField( @@ -128,26 +174,32 @@ class GetRedditPostsBlock(Block): ( "post", RedditPost( - id="id1", subreddit="subreddit", title="title1", body="body1" + post_id="id1", + subreddit="subreddit", + title="title1", + body="body1", ), ), ( "post", RedditPost( - id="id2", subreddit="subreddit", title="title2", body="body2" + post_id="id2", + subreddit="subreddit", + title="title2", + body="body2", ), ), ( "posts", [ RedditPost( - id="id1", + post_id="id1", subreddit="subreddit", title="title1", body="body1", ), RedditPost( - id="id2", + post_id="id2", subreddit="subreddit", title="title2", body="body2", @@ -184,13 +236,14 @@ class GetRedditPostsBlock(Block): ) time_difference = current_time - post_datetime if time_difference.total_seconds() / 60 > input_data.last_minutes: - continue + # Posts are ordered newest-first, so all subsequent posts will also be older + break if input_data.last_post and post.id == input_data.last_post: break reddit_post = RedditPost( - id=post.id, + post_id=post.id, subreddit=input_data.subreddit, title=post.title, body=post.selftext, @@ -204,10 +257,18 @@ class GetRedditPostsBlock(Block): class PostRedditCommentBlock(Block): class Input(BlockSchemaInput): credentials: RedditCredentialsInput = RedditCredentialsField() - data: RedditComment = SchemaField(description="Reddit comment") + post_id: str = SchemaField( + description="The ID of the post to comment on", + ) + comment: str = SchemaField( + description="The content of the comment to post", + ) class Output(BlockSchemaOutput): comment_id: str = SchemaField(description="Posted comment ID") + post_id: str = SchemaField( + description="The post ID (pass-through for chaining)" + ) def __init__(self): super().__init__( @@ -223,17 +284,24 @@ class PostRedditCommentBlock(Block): test_credentials=TEST_CREDENTIALS, test_input={ "credentials": TEST_CREDENTIALS_INPUT, - "data": {"post_id": "id", "comment": "comment"}, + "post_id": "test_post_id", + "comment": "comment", + }, + test_output=[ + ("comment_id", "dummy_comment_id"), + ("post_id", "test_post_id"), + ], + test_mock={ + "reply_post": lambda creds, post_id, comment: "dummy_comment_id" }, - test_output=[("comment_id", "dummy_comment_id")], - test_mock={"reply_post": lambda creds, comment: "dummy_comment_id"}, ) @staticmethod - def reply_post(creds: RedditCredentials, comment: RedditComment) -> str: + def reply_post(creds: RedditCredentials, post_id: str, comment: str) -> str: client = get_praw(creds) - submission = client.submission(id=comment.post_id) - new_comment = submission.reply(comment.comment) + post_id = strip_reddit_prefix(post_id) + submission = client.submission(id=post_id) + new_comment = submission.reply(comment) if not new_comment: raise ValueError("Failed to post comment.") return new_comment.id @@ -241,4 +309,2230 @@ class PostRedditCommentBlock(Block): async def run( self, input_data: Input, *, credentials: RedditCredentials, **kwargs ) -> BlockOutput: - yield "comment_id", self.reply_post(credentials, input_data.data) + yield "comment_id", self.reply_post( + credentials, + post_id=input_data.post_id, + comment=input_data.comment, + ) + yield "post_id", input_data.post_id + + +class CreateRedditPostBlock(Block): + class Input(BlockSchemaInput): + credentials: RedditCredentialsInput = RedditCredentialsField() + subreddit: str = SchemaField( + description="Subreddit to post to, excluding the /r/ prefix", + ) + title: str = SchemaField( + description="Title of the post", + ) + content: str = SchemaField( + description="Body text of the post (for text posts)", + default="", + ) + url: str | None = SchemaField( + description="URL to submit (for link posts). If provided, content is ignored.", + default=None, + ) + flair_id: str | None = SchemaField( + description="Flair template ID to apply to the post (from GetSubredditFlairsBlock)", + default=None, + ) + flair_text: str | None = SchemaField( + description="Custom flair text (only used if the flair template allows editing)", + default=None, + ) + + class Output(BlockSchemaOutput): + post_id: str = SchemaField(description="ID of the created post") + post_url: str = SchemaField(description="URL of the created post") + subreddit: str = SchemaField( + description="The subreddit name (pass-through for chaining)" + ) + + def __init__(self): + super().__init__( + id="f3a2b1c0-8d7e-4f6a-9b5c-1234567890ab", + description="Create a new post on a subreddit. Can create text posts or link posts.", + categories={BlockCategory.SOCIAL}, + input_schema=CreateRedditPostBlock.Input, + output_schema=CreateRedditPostBlock.Output, + disabled=( + not settings.secrets.reddit_client_id + or not settings.secrets.reddit_client_secret + ), + test_credentials=TEST_CREDENTIALS, + test_input={ + "credentials": TEST_CREDENTIALS_INPUT, + "subreddit": "test", + "title": "Test Post", + "content": "This is a test post body.", + }, + test_output=[ + ("post_id", "abc123"), + ("post_url", "https://reddit.com/r/test/comments/abc123/test_post/"), + ("subreddit", "test"), + ], + test_mock={ + "create_post": lambda creds, subreddit, title, content, url, flair_id, flair_text: ( + "abc123", + "https://reddit.com/r/test/comments/abc123/test_post/", + ) + }, + ) + + @staticmethod + def create_post( + creds: RedditCredentials, + subreddit: str, + title: str, + content: str = "", + url: str | None = None, + flair_id: str | None = None, + flair_text: str | None = None, + ) -> tuple[str, str]: + """ + Create a new post on a subreddit. + + Args: + creds: Reddit OAuth2 credentials + subreddit: Subreddit name (without /r/ prefix) + title: Post title + content: Post body text (for text posts) + url: URL to submit (for link posts, overrides content) + flair_id: Optional flair template ID to apply + flair_text: Optional custom flair text (for editable flairs) + + Returns: + Tuple of (post_id, post_url) + """ + client = get_praw(creds) + sub = client.subreddit(subreddit) + + if url: + submission = sub.submit( + title=title, url=url, flair_id=flair_id, flair_text=flair_text + ) + else: + submission = sub.submit( + title=title, selftext=content, flair_id=flair_id, flair_text=flair_text + ) + + return submission.id, f"https://reddit.com{submission.permalink}" + + async def run( + self, input_data: Input, *, credentials: RedditCredentials, **kwargs + ) -> BlockOutput: + post_id, post_url = self.create_post( + credentials, + input_data.subreddit, + input_data.title, + input_data.content, + input_data.url, + input_data.flair_id, + input_data.flair_text, + ) + yield "post_id", post_id + yield "post_url", post_url + yield "subreddit", input_data.subreddit + + +class RedditPostDetails(BaseModel): + """Detailed information about a Reddit post.""" + + id: str + subreddit: str + title: str + body: str + author: str + score: int + upvote_ratio: float + num_comments: int + created_utc: float + url: str + permalink: str + is_self: bool + over_18: bool + + +class GetRedditPostBlock(Block): + """Get detailed information about a specific Reddit post.""" + + class Input(BlockSchemaInput): + credentials: RedditCredentialsInput = RedditCredentialsField() + post_id: str = SchemaField( + description="The ID of the post to fetch (e.g., 'abc123' or full ID 't3_abc123')", + ) + + class Output(BlockSchemaOutput): + post: RedditPostDetails = SchemaField(description="Detailed post information") + error: str = SchemaField( + description="Error message if the post couldn't be fetched" + ) + + def __init__(self): + super().__init__( + id="36e6a259-168c-4032-83ec-b2935d0e4584", + description="Get detailed information about a specific Reddit post by its ID.", + categories={BlockCategory.SOCIAL}, + input_schema=GetRedditPostBlock.Input, + output_schema=GetRedditPostBlock.Output, + disabled=( + not settings.secrets.reddit_client_id + or not settings.secrets.reddit_client_secret + ), + test_credentials=TEST_CREDENTIALS, + test_input={ + "credentials": TEST_CREDENTIALS_INPUT, + "post_id": "abc123", + }, + test_output=[ + ( + "post", + RedditPostDetails( + id="abc123", + subreddit="test", + title="Test Post", + body="Test body", + author="testuser", + score=100, + upvote_ratio=0.95, + num_comments=10, + created_utc=1234567890.0, + url="https://reddit.com/r/test/comments/abc123/test_post/", + permalink="/r/test/comments/abc123/test_post/", + is_self=True, + over_18=False, + ), + ), + ], + test_mock={ + "get_post": lambda creds, post_id: RedditPostDetails( + id="abc123", + subreddit="test", + title="Test Post", + body="Test body", + author="testuser", + score=100, + upvote_ratio=0.95, + num_comments=10, + created_utc=1234567890.0, + url="https://reddit.com/r/test/comments/abc123/test_post/", + permalink="/r/test/comments/abc123/test_post/", + is_self=True, + over_18=False, + ) + }, + ) + + @staticmethod + def get_post(creds: RedditCredentials, post_id: str) -> RedditPostDetails: + client = get_praw(creds) + post_id = strip_reddit_prefix(post_id) + submission = client.submission(id=post_id) + + return RedditPostDetails( + id=submission.id, + subreddit=submission.subreddit.display_name, + title=submission.title, + body=submission.selftext, + author=str(submission.author) if submission.author else "[deleted]", + score=submission.score, + upvote_ratio=submission.upvote_ratio, + num_comments=submission.num_comments, + created_utc=submission.created_utc, + url=submission.url, + permalink=submission.permalink, + is_self=submission.is_self, + over_18=submission.over_18, + ) + + async def run( + self, input_data: Input, *, credentials: RedditCredentials, **kwargs + ) -> BlockOutput: + try: + post = self.get_post(credentials, input_data.post_id) + yield "post", post + except Exception as e: + yield "error", str(e) + + +class GetUserPostsBlock(Block): + """Get posts by a specific Reddit user.""" + + class Input(BlockSchemaInput): + credentials: RedditCredentialsInput = RedditCredentialsField() + username: str = SchemaField( + description="Reddit username to fetch posts from (without /u/ prefix)", + ) + post_limit: int = SchemaField( + description="Maximum number of posts to fetch", + default=10, + ) + sort: UserPostSort = SchemaField( + description="Sort order for user posts", + default="new", + ) + + class Output(BlockSchemaOutput): + post: RedditPost = SchemaField(description="A post by the user") + posts: list[RedditPost] = SchemaField(description="All posts by the user") + error: str = SchemaField( + description="Error message if posts couldn't be fetched" + ) + + def __init__(self): + super().__init__( + id="6fbe6329-d13e-4d2e-bd4d-b4d921b56161", + description="Fetch posts by a specific Reddit user.", + categories={BlockCategory.SOCIAL}, + input_schema=GetUserPostsBlock.Input, + output_schema=GetUserPostsBlock.Output, + disabled=( + not settings.secrets.reddit_client_id + or not settings.secrets.reddit_client_secret + ), + test_credentials=TEST_CREDENTIALS, + test_input={ + "credentials": TEST_CREDENTIALS_INPUT, + "username": "testuser", + "post_limit": 2, + }, + test_output=[ + ( + "post", + RedditPost( + post_id="id1", subreddit="sub1", title="title1", body="body1" + ), + ), + ( + "post", + RedditPost( + post_id="id2", subreddit="sub2", title="title2", body="body2" + ), + ), + ( + "posts", + [ + RedditPost( + post_id="id1", + subreddit="sub1", + title="title1", + body="body1", + ), + RedditPost( + post_id="id2", + subreddit="sub2", + title="title2", + body="body2", + ), + ], + ), + ], + test_mock={ + "get_user_posts": lambda creds, username, limit, sort: [ + MockObject( + id="id1", + subreddit=MockObject(display_name="sub1"), + title="title1", + selftext="body1", + ), + MockObject( + id="id2", + subreddit=MockObject(display_name="sub2"), + title="title2", + selftext="body2", + ), + ] + }, + ) + + @staticmethod + def get_user_posts( + creds: RedditCredentials, username: str, limit: int, sort: UserPostSort + ) -> list[Submission]: + client = get_praw(creds) + redditor = client.redditor(username) + + if sort == "new": + submissions = redditor.submissions.new(limit=limit) + elif sort == "hot": + submissions = redditor.submissions.hot(limit=limit) + elif sort == "top": + submissions = redditor.submissions.top(limit=limit) + elif sort == "controversial": + submissions = redditor.submissions.controversial(limit=limit) + else: + submissions = redditor.submissions.new(limit=limit) + + return list(submissions) + + async def run( + self, input_data: Input, *, credentials: RedditCredentials, **kwargs + ) -> BlockOutput: + try: + submissions = self.get_user_posts( + credentials, + input_data.username, + input_data.post_limit, + input_data.sort, + ) + all_posts = [] + for submission in submissions: + post = RedditPost( + post_id=submission.id, + subreddit=submission.subreddit.display_name, + title=submission.title, + body=submission.selftext, + ) + all_posts.append(post) + yield "post", post + yield "posts", all_posts + except Exception as e: + yield "error", str(e) + + +class RedditGetMyPostsBlock(Block): + """Get posts by the authenticated Reddit user.""" + + class Input(BlockSchemaInput): + credentials: RedditCredentialsInput = RedditCredentialsField() + post_limit: int = SchemaField( + description="Maximum number of posts to fetch", + default=10, + ) + sort: UserPostSort = SchemaField( + description="Sort order for posts", + default="new", + ) + + class Output(BlockSchemaOutput): + post: RedditPost = SchemaField(description="A post by you") + posts: list[RedditPost] = SchemaField(description="All your posts") + error: str = SchemaField( + description="Error message if posts couldn't be fetched" + ) + + def __init__(self): + super().__init__( + id="4ab3381b-0c07-4201-89b3-fa2ec264f154", + description="Fetch posts created by the authenticated Reddit user (you).", + categories={BlockCategory.SOCIAL}, + input_schema=RedditGetMyPostsBlock.Input, + output_schema=RedditGetMyPostsBlock.Output, + disabled=( + not settings.secrets.reddit_client_id + or not settings.secrets.reddit_client_secret + ), + test_credentials=TEST_CREDENTIALS, + test_input={ + "credentials": TEST_CREDENTIALS_INPUT, + "post_limit": 2, + }, + test_output=[ + ( + "post", + RedditPost( + post_id="id1", subreddit="sub1", title="title1", body="body1" + ), + ), + ( + "post", + RedditPost( + post_id="id2", subreddit="sub2", title="title2", body="body2" + ), + ), + ( + "posts", + [ + RedditPost( + post_id="id1", + subreddit="sub1", + title="title1", + body="body1", + ), + RedditPost( + post_id="id2", + subreddit="sub2", + title="title2", + body="body2", + ), + ], + ), + ], + test_mock={ + "get_my_posts": lambda creds, limit, sort: [ + MockObject( + id="id1", + subreddit=MockObject(display_name="sub1"), + title="title1", + selftext="body1", + ), + MockObject( + id="id2", + subreddit=MockObject(display_name="sub2"), + title="title2", + selftext="body2", + ), + ] + }, + ) + + @staticmethod + def get_my_posts( + creds: RedditCredentials, limit: int, sort: UserPostSort + ) -> list[Submission]: + client = get_praw(creds) + me = client.user.me() + if not me: + raise ValueError("Could not get authenticated user.") + + if sort == "new": + submissions = me.submissions.new(limit=limit) + elif sort == "hot": + submissions = me.submissions.hot(limit=limit) + elif sort == "top": + submissions = me.submissions.top(limit=limit) + elif sort == "controversial": + submissions = me.submissions.controversial(limit=limit) + else: + submissions = me.submissions.new(limit=limit) + + return list(submissions) + + async def run( + self, input_data: Input, *, credentials: RedditCredentials, **kwargs + ) -> BlockOutput: + try: + submissions = self.get_my_posts( + credentials, + input_data.post_limit, + input_data.sort, + ) + all_posts = [] + for submission in submissions: + post = RedditPost( + post_id=submission.id, + subreddit=submission.subreddit.display_name, + title=submission.title, + body=submission.selftext, + ) + all_posts.append(post) + yield "post", post + yield "posts", all_posts + except Exception as e: + yield "error", str(e) + + +class RedditSearchResult(BaseModel): + """A search result from Reddit.""" + + id: str + subreddit: str + title: str + body: str + author: str + score: int + num_comments: int + created_utc: float + permalink: str + + +class SearchRedditBlock(Block): + """Search Reddit for posts matching a query.""" + + class Input(BlockSchemaInput): + credentials: RedditCredentialsInput = RedditCredentialsField() + query: str = SchemaField( + description="Search query string", + ) + subreddit: str | None = SchemaField( + description="Limit search to a specific subreddit (without /r/ prefix)", + default=None, + ) + sort: SearchSort = SchemaField( + description="Sort order for search results", + default="relevance", + ) + time_filter: TimeFilter = SchemaField( + description="Time filter for search results", + default="all", + ) + limit: int = SchemaField( + description="Maximum number of results to return", + default=10, + ) + + class Output(BlockSchemaOutput): + result: RedditSearchResult = SchemaField(description="A search result") + results: list[RedditSearchResult] = SchemaField( + description="All search results" + ) + error: str = SchemaField(description="Error message if search failed") + + def __init__(self): + super().__init__( + id="4a0c975e-807b-4d5e-83c9-1619864a4b1a", + description="Search Reddit for posts matching a query. Can search all of Reddit or a specific subreddit.", + categories={BlockCategory.SOCIAL}, + input_schema=SearchRedditBlock.Input, + output_schema=SearchRedditBlock.Output, + disabled=( + not settings.secrets.reddit_client_id + or not settings.secrets.reddit_client_secret + ), + test_credentials=TEST_CREDENTIALS, + test_input={ + "credentials": TEST_CREDENTIALS_INPUT, + "query": "test query", + "limit": 2, + }, + test_output=[ + ( + "result", + RedditSearchResult( + id="id1", + subreddit="sub1", + title="title1", + body="body1", + author="author1", + score=100, + num_comments=10, + created_utc=1234567890.0, + permalink="/r/sub1/comments/id1/title1/", + ), + ), + ( + "result", + RedditSearchResult( + id="id2", + subreddit="sub2", + title="title2", + body="body2", + author="author2", + score=50, + num_comments=5, + created_utc=1234567891.0, + permalink="/r/sub2/comments/id2/title2/", + ), + ), + ( + "results", + [ + RedditSearchResult( + id="id1", + subreddit="sub1", + title="title1", + body="body1", + author="author1", + score=100, + num_comments=10, + created_utc=1234567890.0, + permalink="/r/sub1/comments/id1/title1/", + ), + RedditSearchResult( + id="id2", + subreddit="sub2", + title="title2", + body="body2", + author="author2", + score=50, + num_comments=5, + created_utc=1234567891.0, + permalink="/r/sub2/comments/id2/title2/", + ), + ], + ), + ], + test_mock={ + "search_reddit": lambda creds, query, subreddit, sort, time_filter, limit: [ + MockObject( + id="id1", + subreddit=MockObject(display_name="sub1"), + title="title1", + selftext="body1", + author="author1", + score=100, + num_comments=10, + created_utc=1234567890.0, + permalink="/r/sub1/comments/id1/title1/", + ), + MockObject( + id="id2", + subreddit=MockObject(display_name="sub2"), + title="title2", + selftext="body2", + author="author2", + score=50, + num_comments=5, + created_utc=1234567891.0, + permalink="/r/sub2/comments/id2/title2/", + ), + ] + }, + ) + + @staticmethod + def search_reddit( + creds: RedditCredentials, + query: str, + subreddit: str | None, + sort: SearchSort, + time_filter: TimeFilter, + limit: int, + ) -> list[Submission]: + client = get_praw(creds) + + if subreddit: + sub = client.subreddit(subreddit) + results = sub.search(query, sort=sort, time_filter=time_filter, limit=limit) + else: + results = client.subreddit("all").search( + query, sort=sort, time_filter=time_filter, limit=limit + ) + + return list(results) + + async def run( + self, input_data: Input, *, credentials: RedditCredentials, **kwargs + ) -> BlockOutput: + try: + submissions = self.search_reddit( + credentials, + input_data.query, + input_data.subreddit, + input_data.sort, + input_data.time_filter, + input_data.limit, + ) + all_results = [] + for submission in submissions: + result = RedditSearchResult( + id=submission.id, + subreddit=submission.subreddit.display_name, + title=submission.title, + body=submission.selftext, + author=str(submission.author) if submission.author else "[deleted]", + score=submission.score, + num_comments=submission.num_comments, + created_utc=submission.created_utc, + permalink=submission.permalink, + ) + all_results.append(result) + yield "result", result + yield "results", all_results + except Exception as e: + yield "error", str(e) + + +class EditRedditPostBlock(Block): + """Edit an existing Reddit post that you own.""" + + class Input(BlockSchemaInput): + credentials: RedditCredentialsInput = RedditCredentialsField() + post_id: str = SchemaField( + description="The ID of the post to edit (must be your own post)", + ) + new_content: str = SchemaField( + description="The new body text for the post", + ) + + class Output(BlockSchemaOutput): + success: bool = SchemaField(description="Whether the edit was successful") + post_id: str = SchemaField( + description="The post ID (pass-through for chaining)" + ) + post_url: str = SchemaField(description="URL of the edited post") + error: str = SchemaField(description="Error message if the edit failed") + + def __init__(self): + super().__init__( + id="cdb9df0f-8b1d-433e-873a-ededc1b6479d", + description="Edit the body text of an existing Reddit post that you own. Only works for self/text posts.", + categories={BlockCategory.SOCIAL}, + input_schema=EditRedditPostBlock.Input, + output_schema=EditRedditPostBlock.Output, + disabled=( + not settings.secrets.reddit_client_id + or not settings.secrets.reddit_client_secret + ), + test_credentials=TEST_CREDENTIALS, + test_input={ + "credentials": TEST_CREDENTIALS_INPUT, + "post_id": "abc123", + "new_content": "Updated post content", + }, + test_output=[ + ("success", True), + ("post_id", "abc123"), + ("post_url", "https://reddit.com/r/test/comments/abc123/test_post/"), + ], + test_mock={ + "edit_post": lambda creds, post_id, new_content: ( + True, + "https://reddit.com/r/test/comments/abc123/test_post/", + ) + }, + ) + + @staticmethod + def edit_post( + creds: RedditCredentials, post_id: str, new_content: str + ) -> tuple[bool, str]: + client = get_praw(creds) + post_id = strip_reddit_prefix(post_id) + submission = client.submission(id=post_id) + submission.edit(new_content) + return True, f"https://reddit.com{submission.permalink}" + + async def run( + self, input_data: Input, *, credentials: RedditCredentials, **kwargs + ) -> BlockOutput: + try: + success, post_url = self.edit_post( + credentials, input_data.post_id, input_data.new_content + ) + yield "success", success + yield "post_id", input_data.post_id + yield "post_url", post_url + except Exception as e: + error_msg = str(e) + if "403" in error_msg: + error_msg = ( + "Permission denied (403): You can only edit your own posts. " + "Make sure the post belongs to the authenticated Reddit account." + ) + yield "error", error_msg + + +class SubredditInfo(BaseModel): + """Information about a subreddit.""" + + name: str + display_name: str + title: str + description: str + public_description: str + subscribers: int + created_utc: float + over_18: bool + url: str + + +class GetSubredditInfoBlock(Block): + """Get information about a subreddit.""" + + class Input(BlockSchemaInput): + credentials: RedditCredentialsInput = RedditCredentialsField() + subreddit: str = SchemaField( + description="Subreddit name (without /r/ prefix)", + ) + + class Output(BlockSchemaOutput): + info: SubredditInfo = SchemaField(description="Subreddit information") + subreddit: str = SchemaField( + description="The subreddit name (pass-through for chaining)" + ) + error: str = SchemaField( + description="Error message if the subreddit couldn't be fetched" + ) + + def __init__(self): + super().__init__( + id="5a2d1f0c-01fb-43ea-bad7-2260d269c930", + description="Get information about a subreddit including subscriber count, description, and rules.", + categories={BlockCategory.SOCIAL}, + input_schema=GetSubredditInfoBlock.Input, + output_schema=GetSubredditInfoBlock.Output, + disabled=( + not settings.secrets.reddit_client_id + or not settings.secrets.reddit_client_secret + ), + test_credentials=TEST_CREDENTIALS, + test_input={ + "credentials": TEST_CREDENTIALS_INPUT, + "subreddit": "python", + }, + test_output=[ + ( + "info", + SubredditInfo( + name="t5_2qh0y", + display_name="python", + title="Python", + description="News about the Python programming language", + public_description="News about Python", + subscribers=1000000, + created_utc=1234567890.0, + over_18=False, + url="/r/python/", + ), + ), + ("subreddit", "python"), + ], + test_mock={ + "get_subreddit_info": lambda creds, subreddit: SubredditInfo( + name="t5_2qh0y", + display_name="python", + title="Python", + description="News about the Python programming language", + public_description="News about Python", + subscribers=1000000, + created_utc=1234567890.0, + over_18=False, + url="/r/python/", + ) + }, + ) + + @staticmethod + def get_subreddit_info(creds: RedditCredentials, subreddit: str) -> SubredditInfo: + client = get_praw(creds) + sub = client.subreddit(subreddit) + + return SubredditInfo( + name=sub.name, + display_name=sub.display_name, + title=sub.title, + description=sub.description, + public_description=sub.public_description, + subscribers=sub.subscribers, + created_utc=sub.created_utc, + over_18=sub.over18, + url=sub.url, + ) + + async def run( + self, input_data: Input, *, credentials: RedditCredentials, **kwargs + ) -> BlockOutput: + try: + info = self.get_subreddit_info(credentials, input_data.subreddit) + yield "info", info + yield "subreddit", input_data.subreddit + except Exception as e: + yield "error", str(e) + + +class RedditComment(BaseModel): + """A Reddit comment.""" + + comment_id: str + post_id: str + parent_comment_id: str | None + author: str + body: str + score: int + created_utc: float + edited: bool + is_submitter: bool + permalink: str + depth: int + + +class GetRedditPostCommentsBlock(Block): + """Get comments on a Reddit post.""" + + class Input(BlockSchemaInput): + credentials: RedditCredentialsInput = RedditCredentialsField() + post_id: str = SchemaField( + description="The ID of the post to get comments from", + ) + limit: int = SchemaField( + description="Maximum number of top-level comments to fetch (max 100)", + default=25, + ) + sort: CommentSort = SchemaField( + description="Sort order for comments", + default="best", + ) + + class Output(BlockSchemaOutput): + comment: RedditComment = SchemaField(description="A comment on the post") + comments: list[RedditComment] = SchemaField(description="All fetched comments") + post_id: str = SchemaField( + description="The post ID (pass-through for chaining)" + ) + error: str = SchemaField( + description="Error message if comments couldn't be fetched" + ) + + def __init__(self): + super().__init__( + id="98422b2c-c3b0-4d70-871f-56bd966f46da", + description="Get top-level comments on a Reddit post.", + categories={BlockCategory.SOCIAL}, + input_schema=GetRedditPostCommentsBlock.Input, + output_schema=GetRedditPostCommentsBlock.Output, + disabled=( + not settings.secrets.reddit_client_id + or not settings.secrets.reddit_client_secret + ), + test_credentials=TEST_CREDENTIALS, + test_input={ + "credentials": TEST_CREDENTIALS_INPUT, + "post_id": "abc123", + "limit": 2, + }, + test_output=[ + ( + "comment", + RedditComment( + comment_id="comment1", + post_id="abc123", + parent_comment_id=None, + author="user1", + body="Comment body 1", + score=10, + created_utc=1234567890.0, + edited=False, + is_submitter=False, + permalink="/r/test/comments/abc123/test/comment1/", + depth=0, + ), + ), + ( + "comment", + RedditComment( + comment_id="comment2", + post_id="abc123", + parent_comment_id=None, + author="user2", + body="Comment body 2", + score=5, + created_utc=1234567891.0, + edited=False, + is_submitter=True, + permalink="/r/test/comments/abc123/test/comment2/", + depth=0, + ), + ), + ( + "comments", + [ + RedditComment( + comment_id="comment1", + post_id="abc123", + parent_comment_id=None, + author="user1", + body="Comment body 1", + score=10, + created_utc=1234567890.0, + edited=False, + is_submitter=False, + permalink="/r/test/comments/abc123/test/comment1/", + depth=0, + ), + RedditComment( + comment_id="comment2", + post_id="abc123", + parent_comment_id=None, + author="user2", + body="Comment body 2", + score=5, + created_utc=1234567891.0, + edited=False, + is_submitter=True, + permalink="/r/test/comments/abc123/test/comment2/", + depth=0, + ), + ], + ), + ("post_id", "abc123"), + ], + test_mock={ + "get_comments": lambda creds, post_id, limit, sort: [ + MockObject( + id="comment1", + link_id="t3_abc123", + parent_id="t3_abc123", + author="user1", + body="Comment body 1", + score=10, + created_utc=1234567890.0, + edited=False, + is_submitter=False, + permalink="/r/test/comments/abc123/test/comment1/", + depth=0, + ), + MockObject( + id="comment2", + link_id="t3_abc123", + parent_id="t3_abc123", + author="user2", + body="Comment body 2", + score=5, + created_utc=1234567891.0, + edited=False, + is_submitter=True, + permalink="/r/test/comments/abc123/test/comment2/", + depth=0, + ), + ] + }, + ) + + @staticmethod + def get_comments( + creds: RedditCredentials, post_id: str, limit: int, sort: CommentSort + ) -> list[Comment]: + client = get_praw(creds) + post_id = strip_reddit_prefix(post_id) + submission = client.submission(id=post_id) + submission.comment_sort = sort + # Replace MoreComments with actual comments up to limit + submission.comments.replace_more(limit=0) + # Return only top-level comments (depth=0), limited + # CommentForest supports indexing, so use slicing directly + max_comments = min(limit, 100) + return [ + submission.comments[i] + for i in range(min(len(submission.comments), max_comments)) + ] + + async def run( + self, input_data: Input, *, credentials: RedditCredentials, **kwargs + ) -> BlockOutput: + try: + comments = self.get_comments( + credentials, + input_data.post_id, + input_data.limit, + input_data.sort, + ) + all_comments = [] + for comment in comments: + # Extract post_id from link_id (format: t3_xxxxx) + comment_post_id = strip_reddit_prefix(comment.link_id) + + # parent_comment_id is None for top-level comments (parent is a post: t3_) + # For replies, extract the comment ID from t1_xxxxx + parent_comment_id = None + if comment.parent_id.startswith("t1_"): + parent_comment_id = strip_reddit_prefix(comment.parent_id) + + comment_data = RedditComment( + comment_id=comment.id, + post_id=comment_post_id, + parent_comment_id=parent_comment_id, + author=str(comment.author) if comment.author else "[deleted]", + body=comment.body, + score=comment.score, + created_utc=comment.created_utc, + edited=bool(comment.edited), + is_submitter=comment.is_submitter, + permalink=comment.permalink, + depth=comment.depth, + ) + all_comments.append(comment_data) + yield "comment", comment_data + yield "comments", all_comments + yield "post_id", input_data.post_id + except Exception as e: + yield "error", str(e) + + +class GetRedditCommentRepliesBlock(Block): + """Get replies to a specific Reddit comment.""" + + class Input(BlockSchemaInput): + credentials: RedditCredentialsInput = RedditCredentialsField() + comment_id: str = SchemaField( + description="The ID of the comment to get replies from", + ) + post_id: str = SchemaField( + description="The ID of the post containing the comment", + ) + limit: int = SchemaField( + description="Maximum number of replies to fetch (max 50)", + default=10, + ) + + class Output(BlockSchemaOutput): + reply: RedditComment = SchemaField(description="A reply to the comment") + replies: list[RedditComment] = SchemaField(description="All replies") + comment_id: str = SchemaField( + description="The parent comment ID (pass-through for chaining)" + ) + post_id: str = SchemaField( + description="The post ID (pass-through for chaining)" + ) + error: str = SchemaField( + description="Error message if replies couldn't be fetched" + ) + + def __init__(self): + super().__init__( + id="7fa83965-7289-432f-98a9-1575f5bcc8f1", + description="Get replies to a specific Reddit comment.", + categories={BlockCategory.SOCIAL}, + input_schema=GetRedditCommentRepliesBlock.Input, + output_schema=GetRedditCommentRepliesBlock.Output, + disabled=( + not settings.secrets.reddit_client_id + or not settings.secrets.reddit_client_secret + ), + test_credentials=TEST_CREDENTIALS, + test_input={ + "credentials": TEST_CREDENTIALS_INPUT, + "comment_id": "comment1", + "post_id": "abc123", + "limit": 2, + }, + test_output=[ + ( + "reply", + RedditComment( + comment_id="reply1", + post_id="abc123", + parent_comment_id="comment1", + author="replier1", + body="Reply body 1", + score=3, + created_utc=1234567892.0, + edited=False, + is_submitter=False, + permalink="/r/test/comments/abc123/test/reply1/", + depth=1, + ), + ), + ( + "replies", + [ + RedditComment( + comment_id="reply1", + post_id="abc123", + parent_comment_id="comment1", + author="replier1", + body="Reply body 1", + score=3, + created_utc=1234567892.0, + edited=False, + is_submitter=False, + permalink="/r/test/comments/abc123/test/reply1/", + depth=1, + ), + ], + ), + ("comment_id", "comment1"), + ("post_id", "abc123"), + ], + test_mock={ + "get_replies": lambda creds, comment_id, post_id, limit: [ + MockObject( + id="reply1", + link_id="t3_abc123", + parent_id="t1_comment1", + author="replier1", + body="Reply body 1", + score=3, + created_utc=1234567892.0, + edited=False, + is_submitter=False, + permalink="/r/test/comments/abc123/test/reply1/", + depth=1, + ), + ] + }, + ) + + @staticmethod + def get_replies( + creds: RedditCredentials, comment_id: str, post_id: str, limit: int + ) -> list[Comment]: + client = get_praw(creds) + post_id = strip_reddit_prefix(post_id) + comment_id = strip_reddit_prefix(comment_id) + + # Get the submission and find the comment + submission = client.submission(id=post_id) + submission.comments.replace_more(limit=0) + + # Find the target comment - filter out MoreComments which don't have .id + comment = None + for c in submission.comments.list(): + if isinstance(c, MoreComments): + continue + if c.id == comment_id: + comment = c + break + + if not comment: + return [] + + # Get direct replies - filter out MoreComments objects + replies = [] + # CommentForest supports indexing + for i in range(len(comment.replies)): + reply = comment.replies[i] + if isinstance(reply, MoreComments): + continue + replies.append(reply) + if len(replies) >= min(limit, 50): + break + + return replies + + async def run( + self, input_data: Input, *, credentials: RedditCredentials, **kwargs + ) -> BlockOutput: + try: + replies = self.get_replies( + credentials, + input_data.comment_id, + input_data.post_id, + input_data.limit, + ) + all_replies = [] + for reply in replies: + reply_post_id = strip_reddit_prefix(reply.link_id) + + # parent_comment_id is the parent comment (always present for replies) + parent_comment_id = None + if reply.parent_id.startswith("t1_"): + parent_comment_id = strip_reddit_prefix(reply.parent_id) + + reply_data = RedditComment( + comment_id=reply.id, + post_id=reply_post_id, + parent_comment_id=parent_comment_id, + author=str(reply.author) if reply.author else "[deleted]", + body=reply.body, + score=reply.score, + created_utc=reply.created_utc, + edited=bool(reply.edited), + is_submitter=reply.is_submitter, + permalink=reply.permalink, + depth=reply.depth, + ) + all_replies.append(reply_data) + yield "reply", reply_data + yield "replies", all_replies + yield "comment_id", input_data.comment_id + yield "post_id", input_data.post_id + except Exception as e: + yield "error", str(e) + + +class GetRedditCommentBlock(Block): + """Get details about a specific Reddit comment.""" + + class Input(BlockSchemaInput): + credentials: RedditCredentialsInput = RedditCredentialsField() + comment_id: str = SchemaField( + description="The ID of the comment to fetch", + ) + + class Output(BlockSchemaOutput): + comment: RedditComment = SchemaField(description="The comment details") + error: str = SchemaField( + description="Error message if comment couldn't be fetched" + ) + + def __init__(self): + super().__init__( + id="72cb311a-5998-4e0a-9bc4-f1b67a97284e", + description="Get details about a specific Reddit comment by its ID.", + categories={BlockCategory.SOCIAL}, + input_schema=GetRedditCommentBlock.Input, + output_schema=GetRedditCommentBlock.Output, + disabled=( + not settings.secrets.reddit_client_id + or not settings.secrets.reddit_client_secret + ), + test_credentials=TEST_CREDENTIALS, + test_input={ + "credentials": TEST_CREDENTIALS_INPUT, + "comment_id": "comment1", + }, + test_output=[ + ( + "comment", + RedditComment( + comment_id="comment1", + post_id="abc123", + parent_comment_id=None, + author="user1", + body="Comment body", + score=10, + created_utc=1234567890.0, + edited=False, + is_submitter=False, + permalink="/r/test/comments/abc123/test/comment1/", + depth=0, + ), + ), + ], + test_mock={ + "get_comment": lambda creds, comment_id: MockObject( + id="comment1", + link_id="t3_abc123", + parent_id="t3_abc123", + author="user1", + body="Comment body", + score=10, + created_utc=1234567890.0, + edited=False, + is_submitter=False, + permalink="/r/test/comments/abc123/test/comment1/", + depth=0, + ) + }, + ) + + @staticmethod + def get_comment(creds: RedditCredentials, comment_id: str): + client = get_praw(creds) + comment_id = strip_reddit_prefix(comment_id) + return client.comment(id=comment_id) + + async def run( + self, input_data: Input, *, credentials: RedditCredentials, **kwargs + ) -> BlockOutput: + try: + comment = self.get_comment(credentials, input_data.comment_id) + + post_id = strip_reddit_prefix(comment.link_id) + + # parent_comment_id is None for top-level comments (parent is a post: t3_) + parent_comment_id = None + if comment.parent_id.startswith("t1_"): + parent_comment_id = strip_reddit_prefix(comment.parent_id) + + comment_data = RedditComment( + comment_id=comment.id, + post_id=post_id, + parent_comment_id=parent_comment_id, + author=str(comment.author) if comment.author else "[deleted]", + body=comment.body, + score=comment.score, + created_utc=comment.created_utc, + edited=bool(comment.edited), + is_submitter=comment.is_submitter, + permalink=comment.permalink, + # depth is only available when comments are fetched as part of a tree, + # not when fetched directly by ID + depth=getattr(comment, "depth", 0), + ) + yield "comment", comment_data + except Exception as e: + yield "error", str(e) + + +class ReplyToRedditCommentBlock(Block): + """Reply to a specific Reddit comment.""" + + class Input(BlockSchemaInput): + credentials: RedditCredentialsInput = RedditCredentialsField() + comment_id: str = SchemaField( + description="The ID of the comment to reply to", + ) + reply_text: str = SchemaField( + description="The text content of the reply", + ) + + class Output(BlockSchemaOutput): + comment_id: str = SchemaField(description="ID of the newly created reply") + parent_comment_id: str = SchemaField( + description="The parent comment ID (pass-through for chaining)" + ) + error: str = SchemaField(description="Error message if reply failed") + + def __init__(self): + super().__init__( + id="7635b059-3a9f-4f7d-b499-1b56c4f76f4f", + description="Reply to a specific Reddit comment. Useful for threaded conversations.", + categories={BlockCategory.SOCIAL}, + input_schema=ReplyToRedditCommentBlock.Input, + output_schema=ReplyToRedditCommentBlock.Output, + disabled=( + not settings.secrets.reddit_client_id + or not settings.secrets.reddit_client_secret + ), + test_credentials=TEST_CREDENTIALS, + test_input={ + "credentials": TEST_CREDENTIALS_INPUT, + "comment_id": "parent_comment", + "reply_text": "This is a reply", + }, + test_output=[ + ("comment_id", "new_reply_id"), + ("parent_comment_id", "parent_comment"), + ], + test_mock={ + "reply_to_comment": lambda creds, comment_id, reply_text: "new_reply_id" + }, + ) + + @staticmethod + def reply_to_comment( + creds: RedditCredentials, comment_id: str, reply_text: str + ) -> str: + client = get_praw(creds) + comment_id = strip_reddit_prefix(comment_id) + comment = client.comment(id=comment_id) + reply = comment.reply(reply_text) + if not reply: + raise ValueError("Failed to post reply.") + return reply.id + + async def run( + self, input_data: Input, *, credentials: RedditCredentials, **kwargs + ) -> BlockOutput: + try: + new_comment_id = self.reply_to_comment( + credentials, input_data.comment_id, input_data.reply_text + ) + yield "comment_id", new_comment_id + yield "parent_comment_id", input_data.comment_id + except Exception as e: + yield "error", str(e) + + +class RedditUserProfileSubreddit(BaseModel): + """Information about a user's profile subreddit.""" + + name: str + title: str + public_description: str + subscribers: int + over_18: bool + + +class RedditUserInfo(BaseModel): + """Information about a Reddit user.""" + + username: str + user_id: str + comment_karma: int + link_karma: int + total_karma: int + created_utc: float + is_gold: bool + is_mod: bool + has_verified_email: bool + moderated_subreddits: list[str] + profile_subreddit: RedditUserProfileSubreddit | None + + +class GetRedditUserInfoBlock(Block): + """Get information about a Reddit user.""" + + class Input(BlockSchemaInput): + credentials: RedditCredentialsInput = RedditCredentialsField() + username: str = SchemaField( + description="The Reddit username to look up (without /u/ prefix)", + ) + + class Output(BlockSchemaOutput): + user: RedditUserInfo = SchemaField(description="User information") + username: str = SchemaField( + description="The username (pass-through for chaining)" + ) + error: str = SchemaField(description="Error message if user lookup failed") + + def __init__(self): + super().__init__( + id="1b4c6bd1-4f28-4bad-9ae9-e7034a0f61ff", + description="Get information about a Reddit user including karma, account age, and verification status.", + categories={BlockCategory.SOCIAL}, + input_schema=GetRedditUserInfoBlock.Input, + output_schema=GetRedditUserInfoBlock.Output, + disabled=( + not settings.secrets.reddit_client_id + or not settings.secrets.reddit_client_secret + ), + test_credentials=TEST_CREDENTIALS, + test_input={ + "credentials": TEST_CREDENTIALS_INPUT, + "username": "testuser", + }, + test_output=[ + ( + "user", + RedditUserInfo( + username="testuser", + user_id="abc123", + comment_karma=1000, + link_karma=500, + total_karma=1500, + created_utc=1234567890.0, + is_gold=False, + is_mod=True, + has_verified_email=True, + moderated_subreddits=["python", "learnpython"], + profile_subreddit=RedditUserProfileSubreddit( + name="u_testuser", + title="testuser's profile", + public_description="A test user", + subscribers=100, + over_18=False, + ), + ), + ), + ("username", "testuser"), + ], + test_mock={ + "get_user_info": lambda creds, username: MockObject( + name="testuser", + id="abc123", + comment_karma=1000, + link_karma=500, + total_karma=1500, + created_utc=1234567890.0, + is_gold=False, + is_mod=True, + has_verified_email=True, + subreddit=MockObject( + display_name="u_testuser", + title="testuser's profile", + public_description="A test user", + subscribers=100, + over18=False, + ), + ), + "get_moderated_subreddits": lambda creds, username: [ + MockObject(display_name="python"), + MockObject(display_name="learnpython"), + ], + }, + ) + + @staticmethod + def get_user_info(creds: RedditCredentials, username: str): + client = get_praw(creds) + if username.startswith("u/"): + username = username[2:] + return client.redditor(username) + + @staticmethod + def get_moderated_subreddits(creds: RedditCredentials, username: str) -> list: + client = get_praw(creds) + if username.startswith("u/"): + username = username[2:] + redditor = client.redditor(username) + return list(redditor.moderated()) + + async def run( + self, input_data: Input, *, credentials: RedditCredentials, **kwargs + ) -> BlockOutput: + try: + redditor = self.get_user_info(credentials, input_data.username) + moderated = self.get_moderated_subreddits(credentials, input_data.username) + + # Extract moderated subreddit names + moderated_subreddits = [sub.display_name for sub in moderated] + + # Get profile subreddit info if available + profile_subreddit = None + if hasattr(redditor, "subreddit") and redditor.subreddit: + try: + profile_subreddit = RedditUserProfileSubreddit( + name=redditor.subreddit.display_name, + title=redditor.subreddit.title or "", + public_description=redditor.subreddit.public_description or "", + subscribers=redditor.subreddit.subscribers or 0, + over_18=( + redditor.subreddit.over18 + if hasattr(redditor.subreddit, "over18") + else False + ), + ) + except Exception: + # Profile subreddit may not be accessible + pass + + user_info = RedditUserInfo( + username=redditor.name, + user_id=redditor.id, + comment_karma=redditor.comment_karma, + link_karma=redditor.link_karma, + total_karma=redditor.total_karma, + created_utc=redditor.created_utc, + is_gold=redditor.is_gold, + is_mod=redditor.is_mod, + has_verified_email=redditor.has_verified_email, + moderated_subreddits=moderated_subreddits, + profile_subreddit=profile_subreddit, + ) + yield "user", user_info + yield "username", input_data.username + except Exception as e: + yield "error", str(e) + + +class SendRedditMessageBlock(Block): + """Send a private message to a Reddit user.""" + + class Input(BlockSchemaInput): + credentials: RedditCredentialsInput = RedditCredentialsField() + username: str = SchemaField( + description="The Reddit username to send a message to (without /u/ prefix)", + ) + subject: str = SchemaField( + description="The subject line of the message", + ) + message: str = SchemaField( + description="The body content of the message", + ) + + class Output(BlockSchemaOutput): + success: bool = SchemaField(description="Whether the message was sent") + username: str = SchemaField( + description="The username (pass-through for chaining)" + ) + error: str = SchemaField(description="Error message if sending failed") + + def __init__(self): + super().__init__( + id="7921101a-0537-4259-82ea-bc186ca6b1b6", + description="Send a private message (DM) to a Reddit user.", + categories={BlockCategory.SOCIAL}, + input_schema=SendRedditMessageBlock.Input, + output_schema=SendRedditMessageBlock.Output, + disabled=( + not settings.secrets.reddit_client_id + or not settings.secrets.reddit_client_secret + ), + test_credentials=TEST_CREDENTIALS, + test_input={ + "credentials": TEST_CREDENTIALS_INPUT, + "username": "testuser", + "subject": "Hello", + "message": "This is a test message", + }, + test_output=[ + ("success", True), + ("username", "testuser"), + ], + test_mock={"send_message": lambda creds, username, subject, message: True}, + ) + + @staticmethod + def send_message( + creds: RedditCredentials, username: str, subject: str, message: str + ) -> bool: + client = get_praw(creds) + if username.startswith("u/"): + username = username[2:] + redditor = client.redditor(username) + redditor.message(subject=subject, message=message) + return True + + async def run( + self, input_data: Input, *, credentials: RedditCredentials, **kwargs + ) -> BlockOutput: + try: + success = self.send_message( + credentials, + input_data.username, + input_data.subject, + input_data.message, + ) + yield "success", success + yield "username", input_data.username + except Exception as e: + yield "error", str(e) + + +class RedditInboxItem(BaseModel): + """A Reddit inbox item (message, comment reply, or mention).""" + + item_id: str + item_type: str # "message", "comment_reply", "mention" + subject: str + body: str + author: str + created_utc: float + is_read: bool + context: str | None # permalink for comments, None for messages + + +class GetRedditInboxBlock(Block): + """Get messages and notifications from Reddit inbox.""" + + class Input(BlockSchemaInput): + credentials: RedditCredentialsInput = RedditCredentialsField() + inbox_type: InboxType = SchemaField( + description="Type of inbox items to fetch", + default="unread", + ) + limit: int = SchemaField( + description="Maximum number of items to fetch", + default=25, + ) + mark_read: bool = SchemaField( + description="Whether to mark fetched items as read", + default=False, + ) + + class Output(BlockSchemaOutput): + item: RedditInboxItem = SchemaField(description="An inbox item") + items: list[RedditInboxItem] = SchemaField(description="All fetched items") + error: str = SchemaField(description="Error message if fetch failed") + + def __init__(self): + super().__init__( + id="5a91bb34-7ffe-4b9e-957b-9d4f8fe8dbc9", + description="Get messages, mentions, and comment replies from your Reddit inbox.", + categories={BlockCategory.SOCIAL}, + input_schema=GetRedditInboxBlock.Input, + output_schema=GetRedditInboxBlock.Output, + disabled=( + not settings.secrets.reddit_client_id + or not settings.secrets.reddit_client_secret + ), + test_credentials=TEST_CREDENTIALS, + test_input={ + "credentials": TEST_CREDENTIALS_INPUT, + "inbox_type": "unread", + "limit": 10, + }, + test_output=[ + ( + "item", + RedditInboxItem( + item_id="msg123", + item_type="message", + subject="Hello", + body="Test message body", + author="sender_user", + created_utc=1234567890.0, + is_read=False, + context=None, + ), + ), + ( + "items", + [ + RedditInboxItem( + item_id="msg123", + item_type="message", + subject="Hello", + body="Test message body", + author="sender_user", + created_utc=1234567890.0, + is_read=False, + context=None, + ), + ], + ), + ], + test_mock={ + "get_inbox": lambda creds, inbox_type, limit: [ + MockObject( + id="msg123", + subject="Hello", + body="Test message body", + author="sender_user", + created_utc=1234567890.0, + new=True, + context=None, + was_comment=False, + ), + ] + }, + ) + + @staticmethod + def get_inbox(creds: RedditCredentials, inbox_type: InboxType, limit: int) -> list: + client = get_praw(creds) + inbox = client.inbox + + if inbox_type == "all": + items = inbox.all(limit=limit) + elif inbox_type == "unread": + items = inbox.unread(limit=limit) + elif inbox_type == "messages": + items = inbox.messages(limit=limit) + elif inbox_type == "mentions": + items = inbox.mentions(limit=limit) + elif inbox_type == "comment_replies": + items = inbox.comment_replies(limit=limit) + else: + items = inbox.unread(limit=limit) + + return list(items) + + async def run( + self, input_data: Input, *, credentials: RedditCredentials, **kwargs + ) -> BlockOutput: + try: + raw_items = self.get_inbox( + credentials, input_data.inbox_type, input_data.limit + ) + all_items = [] + + for item in raw_items: + # Determine item type + if hasattr(item, "was_comment") and item.was_comment: + if hasattr(item, "subject") and "mention" in item.subject.lower(): + item_type = "mention" + else: + item_type = "comment_reply" + else: + item_type = "message" + + inbox_item = RedditInboxItem( + item_id=item.id, + item_type=item_type, + subject=item.subject if hasattr(item, "subject") else "", + body=item.body, + author=str(item.author) if item.author else "[deleted]", + created_utc=item.created_utc, + is_read=not item.new, + context=item.context if hasattr(item, "context") else None, + ) + all_items.append(inbox_item) + yield "item", inbox_item + + # Mark as read if requested + if input_data.mark_read and raw_items: + client = get_praw(credentials) + client.inbox.mark_read(raw_items) + + yield "items", all_items + except Exception as e: + yield "error", str(e) + + +class DeleteRedditPostBlock(Block): + """Delete a Reddit post that you own.""" + + class Input(BlockSchemaInput): + credentials: RedditCredentialsInput = RedditCredentialsField() + post_id: str = SchemaField( + description="The ID of the post to delete (must be your own post)", + ) + + class Output(BlockSchemaOutput): + success: bool = SchemaField(description="Whether the deletion was successful") + post_id: str = SchemaField( + description="The post ID (pass-through for chaining)" + ) + error: str = SchemaField(description="Error message if deletion failed") + + def __init__(self): + super().__init__( + id="72e4730a-d66d-4785-8e54-5ab3af450c81", + description="Delete a Reddit post that you own.", + categories={BlockCategory.SOCIAL}, + input_schema=DeleteRedditPostBlock.Input, + output_schema=DeleteRedditPostBlock.Output, + disabled=( + not settings.secrets.reddit_client_id + or not settings.secrets.reddit_client_secret + ), + test_credentials=TEST_CREDENTIALS, + test_input={ + "credentials": TEST_CREDENTIALS_INPUT, + "post_id": "abc123", + }, + test_output=[ + ("success", True), + ("post_id", "abc123"), + ], + test_mock={"delete_post": lambda creds, post_id: True}, + ) + + @staticmethod + def delete_post(creds: RedditCredentials, post_id: str) -> bool: + client = get_praw(creds) + post_id = strip_reddit_prefix(post_id) + submission = client.submission(id=post_id) + submission.delete() + return True + + async def run( + self, input_data: Input, *, credentials: RedditCredentials, **kwargs + ) -> BlockOutput: + try: + success = self.delete_post(credentials, input_data.post_id) + yield "success", success + yield "post_id", input_data.post_id + except Exception as e: + yield "error", str(e) + + +class DeleteRedditCommentBlock(Block): + """Delete a Reddit comment that you own.""" + + class Input(BlockSchemaInput): + credentials: RedditCredentialsInput = RedditCredentialsField() + comment_id: str = SchemaField( + description="The ID of the comment to delete (must be your own comment)", + ) + + class Output(BlockSchemaOutput): + success: bool = SchemaField(description="Whether the deletion was successful") + comment_id: str = SchemaField( + description="The comment ID (pass-through for chaining)" + ) + error: str = SchemaField(description="Error message if deletion failed") + + def __init__(self): + super().__init__( + id="2650584d-434f-46db-81ef-26c8d8d41f81", + description="Delete a Reddit comment that you own.", + categories={BlockCategory.SOCIAL}, + input_schema=DeleteRedditCommentBlock.Input, + output_schema=DeleteRedditCommentBlock.Output, + disabled=( + not settings.secrets.reddit_client_id + or not settings.secrets.reddit_client_secret + ), + test_credentials=TEST_CREDENTIALS, + test_input={ + "credentials": TEST_CREDENTIALS_INPUT, + "comment_id": "xyz789", + }, + test_output=[ + ("success", True), + ("comment_id", "xyz789"), + ], + test_mock={"delete_comment": lambda creds, comment_id: True}, + ) + + @staticmethod + def delete_comment(creds: RedditCredentials, comment_id: str) -> bool: + client = get_praw(creds) + comment_id = strip_reddit_prefix(comment_id) + comment = client.comment(id=comment_id) + comment.delete() + return True + + async def run( + self, input_data: Input, *, credentials: RedditCredentials, **kwargs + ) -> BlockOutput: + try: + success = self.delete_comment(credentials, input_data.comment_id) + yield "success", success + yield "comment_id", input_data.comment_id + except Exception as e: + yield "error", str(e) + + +class SubredditFlair(BaseModel): + """A subreddit link flair template.""" + + flair_id: str + text: str + text_editable: bool + css_class: str = "" # The CSS class for styling (from flair_css_class) + + +class GetSubredditFlairsBlock(Block): + """Get available link flairs for a subreddit.""" + + class Input(BlockSchemaInput): + credentials: RedditCredentialsInput = RedditCredentialsField() + subreddit: str = SchemaField( + description="Subreddit name (without /r/ prefix)", + ) + + class Output(BlockSchemaOutput): + flair: SubredditFlair = SchemaField(description="A flair option") + flairs: list[SubredditFlair] = SchemaField(description="All available flairs") + subreddit: str = SchemaField( + description="The subreddit name (pass-through for chaining)" + ) + error: str = SchemaField(description="Error message if fetch failed") + + def __init__(self): + super().__init__( + id="ada08f34-a7a9-44aa-869f-0638fa4e0a84", + description="Get available link flair options for a subreddit.", + categories={BlockCategory.SOCIAL}, + input_schema=GetSubredditFlairsBlock.Input, + output_schema=GetSubredditFlairsBlock.Output, + disabled=( + not settings.secrets.reddit_client_id + or not settings.secrets.reddit_client_secret + ), + test_credentials=TEST_CREDENTIALS, + test_input={ + "credentials": TEST_CREDENTIALS_INPUT, + "subreddit": "test", + }, + test_output=[ + ( + "flair", + SubredditFlair( + flair_id="abc123", + text="Discussion", + text_editable=False, + css_class="discussion", + ), + ), + ( + "flairs", + [ + SubredditFlair( + flair_id="abc123", + text="Discussion", + text_editable=False, + css_class="discussion", + ), + ], + ), + ("subreddit", "test"), + ], + test_mock={ + "get_flairs": lambda creds, subreddit: [ + { + "flair_template_id": "abc123", + "flair_text": "Discussion", + "flair_text_editable": False, + "flair_css_class": "discussion", + }, + ] + }, + ) + + @staticmethod + def get_flairs(creds: RedditCredentials, subreddit: str) -> list: + client = get_praw(creds) + # Use /r/{subreddit}/api/flairselector endpoint directly with is_newlink=True + # This returns link flairs available for new submissions without requiring mod access + # The link_templates API is moderator-only, so we use flairselector instead + # Path must include the subreddit prefix per Reddit API docs + response = client.post( + f"r/{subreddit}/api/flairselector", + data={"is_newlink": "true"}, + ) + # Response contains 'choices' list with available flairs + choices = response.get("choices", []) + return choices + + async def run( + self, input_data: Input, *, credentials: RedditCredentials, **kwargs + ) -> BlockOutput: + try: + raw_flairs = self.get_flairs(credentials, input_data.subreddit) + all_flairs = [] + + for flair in raw_flairs: + # /api/flairselector returns flairs with flair_template_id, flair_text, etc. + flair_data = SubredditFlair( + flair_id=flair.get("flair_template_id", ""), + text=flair.get("flair_text", ""), + text_editable=flair.get("flair_text_editable", False), + css_class=flair.get("flair_css_class", ""), + ) + all_flairs.append(flair_data) + yield "flair", flair_data + + yield "flairs", all_flairs + yield "subreddit", input_data.subreddit + except Exception as e: + yield "error", str(e) + + +class SubredditRule(BaseModel): + """A subreddit rule.""" + + short_name: str + description: str + kind: str # "all", "link", "comment" + violation_reason: str + priority: int + + +class GetSubredditRulesBlock(Block): + """Get the rules for a subreddit.""" + + class Input(BlockSchemaInput): + credentials: RedditCredentialsInput = RedditCredentialsField() + subreddit: str = SchemaField( + description="Subreddit name (without /r/ prefix)", + ) + + class Output(BlockSchemaOutput): + rule: SubredditRule = SchemaField(description="A subreddit rule") + rules: list[SubredditRule] = SchemaField(description="All subreddit rules") + subreddit: str = SchemaField( + description="The subreddit name (pass-through for chaining)" + ) + error: str = SchemaField(description="Error message if fetch failed") + + def __init__(self): + super().__init__( + id="222aa36c-fa70-4879-8e8a-37d100175f5c", + description="Get the rules for a subreddit to ensure compliance before posting.", + categories={BlockCategory.SOCIAL}, + input_schema=GetSubredditRulesBlock.Input, + output_schema=GetSubredditRulesBlock.Output, + disabled=( + not settings.secrets.reddit_client_id + or not settings.secrets.reddit_client_secret + ), + test_credentials=TEST_CREDENTIALS, + test_input={ + "credentials": TEST_CREDENTIALS_INPUT, + "subreddit": "test", + }, + test_output=[ + ( + "rule", + SubredditRule( + short_name="No spam", + description="Do not post spam or self-promotional content.", + kind="all", + violation_reason="Spam", + priority=0, + ), + ), + ( + "rules", + [ + SubredditRule( + short_name="No spam", + description="Do not post spam or self-promotional content.", + kind="all", + violation_reason="Spam", + priority=0, + ), + ], + ), + ("subreddit", "test"), + ], + test_mock={ + "get_rules": lambda creds, subreddit: [ + MockObject( + short_name="No spam", + description="Do not post spam or self-promotional content.", + kind="all", + violation_reason="Spam", + priority=0, + ), + ] + }, + ) + + @staticmethod + def get_rules(creds: RedditCredentials, subreddit: str) -> list: + client = get_praw(creds) + sub = client.subreddit(subreddit) + return list(sub.rules) + + async def run( + self, input_data: Input, *, credentials: RedditCredentials, **kwargs + ) -> BlockOutput: + try: + raw_rules = self.get_rules(credentials, input_data.subreddit) + all_rules = [] + + for idx, rule in enumerate(raw_rules): + rule_data = SubredditRule( + short_name=rule.short_name, + description=rule.description or "", + kind=rule.kind, + violation_reason=rule.violation_reason or rule.short_name, + priority=idx, + ) + all_rules.append(rule_data) + yield "rule", rule_data + + yield "rules", all_rules + yield "subreddit", input_data.subreddit + except Exception as e: + yield "error", str(e) diff --git a/autogpt_platform/backend/backend/blocks/smart_decision_maker.py b/autogpt_platform/backend/backend/blocks/smart_decision_maker.py index 751f6af37f..ff6042eaab 100644 --- a/autogpt_platform/backend/backend/blocks/smart_decision_maker.py +++ b/autogpt_platform/backend/backend/blocks/smart_decision_maker.py @@ -391,8 +391,12 @@ class SmartDecisionMakerBlock(Block): """ block = sink_node.block + # Use custom name from node metadata if set, otherwise fall back to block.name + custom_name = sink_node.metadata.get("customized_name") + tool_name = custom_name if custom_name else block.name + tool_function: dict[str, Any] = { - "name": SmartDecisionMakerBlock.cleanup(block.name), + "name": SmartDecisionMakerBlock.cleanup(tool_name), "description": block.description, } sink_block_input_schema = block.input_schema @@ -489,14 +493,24 @@ class SmartDecisionMakerBlock(Block): f"Sink graph metadata not found: {graph_id} {graph_version}" ) + # Use custom name from node metadata if set, otherwise fall back to graph name + custom_name = sink_node.metadata.get("customized_name") + tool_name = custom_name if custom_name else sink_graph_meta.name + tool_function: dict[str, Any] = { - "name": SmartDecisionMakerBlock.cleanup(sink_graph_meta.name), + "name": SmartDecisionMakerBlock.cleanup(tool_name), "description": sink_graph_meta.description, } properties = {} + field_mapping = {} for link in links: + field_name = link.sink_name + + clean_field_name = SmartDecisionMakerBlock.cleanup(field_name) + field_mapping[clean_field_name] = field_name + sink_block_input_schema = sink_node.input_default["input_schema"] sink_block_properties = sink_block_input_schema.get("properties", {}).get( link.sink_name, {} @@ -506,7 +520,7 @@ class SmartDecisionMakerBlock(Block): if "description" in sink_block_properties else f"The {link.sink_name} of the tool" ) - properties[link.sink_name] = { + properties[clean_field_name] = { "type": "string", "description": description, "default": json.dumps(sink_block_properties.get("default", None)), @@ -519,7 +533,7 @@ class SmartDecisionMakerBlock(Block): "strict": True, } - # Store node info for later use in output processing + tool_function["_field_mapping"] = field_mapping tool_function["_sink_node_id"] = sink_node.id return {"type": "function", "function": tool_function} @@ -975,10 +989,28 @@ class SmartDecisionMakerBlock(Block): graph_version: int, execution_context: ExecutionContext, execution_processor: "ExecutionProcessor", + nodes_to_skip: set[str] | None = None, **kwargs, ) -> BlockOutput: tool_functions = await self._create_tool_node_signatures(node_id) + original_tool_count = len(tool_functions) + + # Filter out tools for nodes that should be skipped (e.g., missing optional credentials) + if nodes_to_skip: + tool_functions = [ + tf + for tf in tool_functions + if tf.get("function", {}).get("_sink_node_id") not in nodes_to_skip + ] + + # Only raise error if we had tools but they were all filtered out + if original_tool_count > 0 and not tool_functions: + raise ValueError( + "No available tools to execute - all downstream nodes are unavailable " + "(possibly due to missing optional credentials)" + ) + yield "tool_functions", json.dumps(tool_functions) conversation_history = input_data.conversation_history or [] @@ -1129,8 +1161,9 @@ class SmartDecisionMakerBlock(Block): original_field_name = field_mapping.get(clean_arg_name, clean_arg_name) arg_value = tool_args.get(clean_arg_name) - sanitized_arg_name = self.cleanup(original_field_name) - emit_key = f"tools_^_{sink_node_id}_~_{sanitized_arg_name}" + # Use original_field_name directly (not sanitized) to match link sink_name + # The field_mapping already translates from LLM's cleaned names to original names + emit_key = f"tools_^_{sink_node_id}_~_{original_field_name}" logger.debug( "[SmartDecisionMakerBlock|geid:%s|neid:%s] emit %s", diff --git a/autogpt_platform/backend/backend/blocks/test/test_smart_decision_maker.py b/autogpt_platform/backend/backend/blocks/test/test_smart_decision_maker.py index c930fab37e..8266d433ad 100644 --- a/autogpt_platform/backend/backend/blocks/test/test_smart_decision_maker.py +++ b/autogpt_platform/backend/backend/blocks/test/test_smart_decision_maker.py @@ -1057,3 +1057,153 @@ async def test_smart_decision_maker_traditional_mode_default(): ) # Should yield individual tool parameters assert "tools_^_test-sink-node-id_~_max_keyword_difficulty" in outputs assert "conversations" in outputs + + +@pytest.mark.asyncio +async def test_smart_decision_maker_uses_customized_name_for_blocks(): + """Test that SmartDecisionMakerBlock uses customized_name from node metadata for tool names.""" + from unittest.mock import MagicMock + + from backend.blocks.basic import StoreValueBlock + from backend.blocks.smart_decision_maker import SmartDecisionMakerBlock + from backend.data.graph import Link, Node + + # Create a mock node with customized_name in metadata + mock_node = MagicMock(spec=Node) + mock_node.id = "test-node-id" + mock_node.block_id = StoreValueBlock().id + mock_node.metadata = {"customized_name": "My Custom Tool Name"} + mock_node.block = StoreValueBlock() + + # Create a mock link + mock_link = MagicMock(spec=Link) + mock_link.sink_name = "input" + + # Call the function directly + result = await SmartDecisionMakerBlock._create_block_function_signature( + mock_node, [mock_link] + ) + + # Verify the tool name uses the customized name (cleaned up) + assert result["type"] == "function" + assert result["function"]["name"] == "my_custom_tool_name" # Cleaned version + assert result["function"]["_sink_node_id"] == "test-node-id" + + +@pytest.mark.asyncio +async def test_smart_decision_maker_falls_back_to_block_name(): + """Test that SmartDecisionMakerBlock falls back to block.name when no customized_name.""" + from unittest.mock import MagicMock + + from backend.blocks.basic import StoreValueBlock + from backend.blocks.smart_decision_maker import SmartDecisionMakerBlock + from backend.data.graph import Link, Node + + # Create a mock node without customized_name + mock_node = MagicMock(spec=Node) + mock_node.id = "test-node-id" + mock_node.block_id = StoreValueBlock().id + mock_node.metadata = {} # No customized_name + mock_node.block = StoreValueBlock() + + # Create a mock link + mock_link = MagicMock(spec=Link) + mock_link.sink_name = "input" + + # Call the function directly + result = await SmartDecisionMakerBlock._create_block_function_signature( + mock_node, [mock_link] + ) + + # Verify the tool name uses the block's default name + assert result["type"] == "function" + assert result["function"]["name"] == "storevalueblock" # Default block name cleaned + assert result["function"]["_sink_node_id"] == "test-node-id" + + +@pytest.mark.asyncio +async def test_smart_decision_maker_uses_customized_name_for_agents(): + """Test that SmartDecisionMakerBlock uses customized_name from metadata for agent nodes.""" + from unittest.mock import AsyncMock, MagicMock, patch + + from backend.blocks.smart_decision_maker import SmartDecisionMakerBlock + from backend.data.graph import Link, Node + + # Create a mock node with customized_name in metadata + mock_node = MagicMock(spec=Node) + mock_node.id = "test-agent-node-id" + mock_node.metadata = {"customized_name": "My Custom Agent"} + mock_node.input_default = { + "graph_id": "test-graph-id", + "graph_version": 1, + "input_schema": {"properties": {"test_input": {"description": "Test input"}}}, + } + + # Create a mock link + mock_link = MagicMock(spec=Link) + mock_link.sink_name = "test_input" + + # Mock the database client + mock_graph_meta = MagicMock() + mock_graph_meta.name = "Original Agent Name" + mock_graph_meta.description = "Agent description" + + mock_db_client = AsyncMock() + mock_db_client.get_graph_metadata.return_value = mock_graph_meta + + with patch( + "backend.blocks.smart_decision_maker.get_database_manager_async_client", + return_value=mock_db_client, + ): + result = await SmartDecisionMakerBlock._create_agent_function_signature( + mock_node, [mock_link] + ) + + # Verify the tool name uses the customized name (cleaned up) + assert result["type"] == "function" + assert result["function"]["name"] == "my_custom_agent" # Cleaned version + assert result["function"]["_sink_node_id"] == "test-agent-node-id" + + +@pytest.mark.asyncio +async def test_smart_decision_maker_agent_falls_back_to_graph_name(): + """Test that agent node falls back to graph name when no customized_name.""" + from unittest.mock import AsyncMock, MagicMock, patch + + from backend.blocks.smart_decision_maker import SmartDecisionMakerBlock + from backend.data.graph import Link, Node + + # Create a mock node without customized_name + mock_node = MagicMock(spec=Node) + mock_node.id = "test-agent-node-id" + mock_node.metadata = {} # No customized_name + mock_node.input_default = { + "graph_id": "test-graph-id", + "graph_version": 1, + "input_schema": {"properties": {"test_input": {"description": "Test input"}}}, + } + + # Create a mock link + mock_link = MagicMock(spec=Link) + mock_link.sink_name = "test_input" + + # Mock the database client + mock_graph_meta = MagicMock() + mock_graph_meta.name = "Original Agent Name" + mock_graph_meta.description = "Agent description" + + mock_db_client = AsyncMock() + mock_db_client.get_graph_metadata.return_value = mock_graph_meta + + with patch( + "backend.blocks.smart_decision_maker.get_database_manager_async_client", + return_value=mock_db_client, + ): + result = await SmartDecisionMakerBlock._create_agent_function_signature( + mock_node, [mock_link] + ) + + # Verify the tool name uses the graph's default name + assert result["type"] == "function" + assert result["function"]["name"] == "original_agent_name" # Graph name cleaned + assert result["function"]["_sink_node_id"] == "test-agent-node-id" diff --git a/autogpt_platform/backend/backend/blocks/test/test_smart_decision_maker_dict.py b/autogpt_platform/backend/backend/blocks/test/test_smart_decision_maker_dict.py index 839bdc5e15..2087c0b7d6 100644 --- a/autogpt_platform/backend/backend/blocks/test/test_smart_decision_maker_dict.py +++ b/autogpt_platform/backend/backend/blocks/test/test_smart_decision_maker_dict.py @@ -15,6 +15,7 @@ async def test_smart_decision_maker_handles_dynamic_dict_fields(): mock_node.block = CreateDictionaryBlock() mock_node.block_id = CreateDictionaryBlock().id mock_node.input_default = {} + mock_node.metadata = {} # Create mock links with dynamic dictionary fields mock_links = [ @@ -77,6 +78,7 @@ async def test_smart_decision_maker_handles_dynamic_list_fields(): mock_node.block = AddToListBlock() mock_node.block_id = AddToListBlock().id mock_node.input_default = {} + mock_node.metadata = {} # Create mock links with dynamic list fields mock_links = [ diff --git a/autogpt_platform/backend/backend/blocks/test/test_smart_decision_maker_dynamic_fields.py b/autogpt_platform/backend/backend/blocks/test/test_smart_decision_maker_dynamic_fields.py index 6ed830e517..af89a83f86 100644 --- a/autogpt_platform/backend/backend/blocks/test/test_smart_decision_maker_dynamic_fields.py +++ b/autogpt_platform/backend/backend/blocks/test/test_smart_decision_maker_dynamic_fields.py @@ -44,6 +44,7 @@ async def test_create_block_function_signature_with_dict_fields(): mock_node.block = CreateDictionaryBlock() mock_node.block_id = CreateDictionaryBlock().id mock_node.input_default = {} + mock_node.metadata = {} # Create mock links with dynamic dictionary fields (source sanitized, sink original) mock_links = [ @@ -106,6 +107,7 @@ async def test_create_block_function_signature_with_list_fields(): mock_node.block = AddToListBlock() mock_node.block_id = AddToListBlock().id mock_node.input_default = {} + mock_node.metadata = {} # Create mock links with dynamic list fields mock_links = [ @@ -159,6 +161,7 @@ async def test_create_block_function_signature_with_object_fields(): mock_node.block = MatchTextPatternBlock() mock_node.block_id = MatchTextPatternBlock().id mock_node.input_default = {} + mock_node.metadata = {} # Create mock links with dynamic object fields mock_links = [ @@ -208,11 +211,13 @@ async def test_create_tool_node_signatures(): mock_dict_node.block = CreateDictionaryBlock() mock_dict_node.block_id = CreateDictionaryBlock().id mock_dict_node.input_default = {} + mock_dict_node.metadata = {} mock_list_node = Mock() mock_list_node.block = AddToListBlock() mock_list_node.block_id = AddToListBlock().id mock_list_node.input_default = {} + mock_list_node.metadata = {} # Mock links with dynamic fields dict_link1 = Mock( @@ -423,6 +428,7 @@ async def test_mixed_regular_and_dynamic_fields(): mock_node.block.name = "TestBlock" mock_node.block.description = "A test block" mock_node.block.input_schema = Mock() + mock_node.metadata = {} # Mock the get_field_schema to return a proper schema for regular fields def get_field_schema(field_name): diff --git a/autogpt_platform/backend/backend/blocks/wordpress/__init__.py b/autogpt_platform/backend/backend/blocks/wordpress/__init__.py index c7b1e26eea..3eae4a1063 100644 --- a/autogpt_platform/backend/backend/blocks/wordpress/__init__.py +++ b/autogpt_platform/backend/backend/blocks/wordpress/__init__.py @@ -1,3 +1,3 @@ -from .blog import WordPressCreatePostBlock +from .blog import WordPressCreatePostBlock, WordPressGetAllPostsBlock -__all__ = ["WordPressCreatePostBlock"] +__all__ = ["WordPressCreatePostBlock", "WordPressGetAllPostsBlock"] diff --git a/autogpt_platform/backend/backend/blocks/wordpress/_api.py b/autogpt_platform/backend/backend/blocks/wordpress/_api.py index 78f535947b..d21dc3e05d 100644 --- a/autogpt_platform/backend/backend/blocks/wordpress/_api.py +++ b/autogpt_platform/backend/backend/blocks/wordpress/_api.py @@ -161,7 +161,7 @@ async def oauth_exchange_code_for_tokens( grant_type="authorization_code", ).model_dump(exclude_none=True) - response = await Requests().post( + response = await Requests(raise_for_status=False).post( f"{WORDPRESS_BASE_URL}oauth2/token", headers=headers, data=data, @@ -205,7 +205,7 @@ async def oauth_refresh_tokens( grant_type="refresh_token", ).model_dump(exclude_none=True) - response = await Requests().post( + response = await Requests(raise_for_status=False).post( f"{WORDPRESS_BASE_URL}oauth2/token", headers=headers, data=data, @@ -252,7 +252,7 @@ async def validate_token( "token": token, } - response = await Requests().get( + response = await Requests(raise_for_status=False).get( f"{WORDPRESS_BASE_URL}oauth2/token-info", params=params, ) @@ -296,7 +296,7 @@ async def make_api_request( url = f"{WORDPRESS_BASE_URL.rstrip('/')}{endpoint}" - request_method = getattr(Requests(), method.lower()) + request_method = getattr(Requests(raise_for_status=False), method.lower()) response = await request_method( url, headers=headers, @@ -476,6 +476,7 @@ async def create_post( data["tags"] = ",".join(str(t) for t in data["tags"]) # Make the API request + site = normalize_site(site) endpoint = f"/rest/v1.1/sites/{site}/posts/new" headers = { @@ -483,7 +484,7 @@ async def create_post( "Content-Type": "application/x-www-form-urlencoded", } - response = await Requests().post( + response = await Requests(raise_for_status=False).post( f"{WORDPRESS_BASE_URL.rstrip('/')}{endpoint}", headers=headers, data=data, @@ -499,3 +500,132 @@ async def create_post( ) error_message = error_data.get("message", response.text) raise ValueError(f"Failed to create post: {response.status} - {error_message}") + + +class Post(BaseModel): + """Response model for individual posts in a posts list response. + + This is a simplified version compared to PostResponse, as the list endpoint + returns less detailed information than the create/get single post endpoints. + """ + + ID: int + site_ID: int + author: PostAuthor + date: datetime + modified: datetime + title: str + URL: str + short_URL: str + content: str | None = None + excerpt: str | None = None + slug: str + guid: str + status: str + sticky: bool + password: str | None = "" + parent: Union[Dict[str, Any], bool, None] = None + type: str + discussion: Dict[str, Union[str, bool, int]] | None = None + likes_enabled: bool | None = None + sharing_enabled: bool | None = None + like_count: int | None = None + i_like: bool | None = None + is_reblogged: bool | None = None + is_following: bool | None = None + global_ID: str | None = None + featured_image: str | None = None + post_thumbnail: Dict[str, Any] | None = None + format: str | None = None + geo: Union[Dict[str, Any], bool, None] = None + menu_order: int | None = None + page_template: str | None = None + publicize_URLs: List[str] | None = None + terms: Dict[str, Dict[str, Any]] | None = None + tags: Dict[str, Dict[str, Any]] | None = None + categories: Dict[str, Dict[str, Any]] | None = None + attachments: Dict[str, Dict[str, Any]] | None = None + attachment_count: int | None = None + metadata: List[Dict[str, Any]] | None = None + meta: Dict[str, Any] | None = None + capabilities: Dict[str, bool] | None = None + revisions: List[int] | None = None + other_URLs: Dict[str, Any] | None = None + + +class PostsResponse(BaseModel): + """Response model for WordPress posts list.""" + + found: int + posts: List[Post] + meta: Dict[str, Any] + + +def normalize_site(site: str) -> str: + """ + Normalize a site identifier by stripping protocol and trailing slashes. + + Args: + site: Site URL, domain, or ID (e.g., "https://myblog.wordpress.com/", "myblog.wordpress.com", "123456789") + + Returns: + Normalized site identifier (domain or ID only) + """ + site = site.strip() + if site.startswith("https://"): + site = site[8:] + elif site.startswith("http://"): + site = site[7:] + return site.rstrip("/") + + +async def get_posts( + credentials: Credentials, + site: str, + status: PostStatus | None = None, + number: int = 100, + offset: int = 0, +) -> PostsResponse: + """ + Get posts from a WordPress site. + + Args: + credentials: OAuth credentials + site: Site ID or domain (e.g., "myblog.wordpress.com" or "123456789") + status: Filter by post status using PostStatus enum, or None for all + number: Number of posts to retrieve (max 100) + offset: Number of posts to skip (for pagination) + + Returns: + PostsResponse with the list of posts + """ + site = normalize_site(site) + endpoint = f"/rest/v1.1/sites/{site}/posts" + + headers = { + "Authorization": credentials.auth_header(), + } + + params: Dict[str, Any] = { + "number": max(1, min(number, 100)), # 1–100 posts per request + "offset": offset, + } + + if status: + params["status"] = status.value + response = await Requests(raise_for_status=False).get( + f"{WORDPRESS_BASE_URL.rstrip('/')}{endpoint}", + headers=headers, + params=params, + ) + + if response.ok: + return PostsResponse.model_validate(response.json()) + + error_data = ( + response.json() + if response.headers.get("content-type", "").startswith("application/json") + else {} + ) + error_message = error_data.get("message", response.text) + raise ValueError(f"Failed to get posts: {response.status} - {error_message}") diff --git a/autogpt_platform/backend/backend/blocks/wordpress/blog.py b/autogpt_platform/backend/backend/blocks/wordpress/blog.py index c0ad5eca54..22b691480b 100644 --- a/autogpt_platform/backend/backend/blocks/wordpress/blog.py +++ b/autogpt_platform/backend/backend/blocks/wordpress/blog.py @@ -9,7 +9,15 @@ from backend.sdk import ( SchemaField, ) -from ._api import CreatePostRequest, PostResponse, PostStatus, create_post +from ._api import ( + CreatePostRequest, + Post, + PostResponse, + PostsResponse, + PostStatus, + create_post, + get_posts, +) from ._config import wordpress @@ -49,8 +57,15 @@ class WordPressCreatePostBlock(Block): media_urls: list[str] = SchemaField( description="URLs of images to sideload and attach to the post", default=[] ) + publish_as_draft: bool = SchemaField( + description="If True, publishes the post as a draft. If False, publishes it publicly.", + default=False, + ) class Output(BlockSchemaOutput): + site: str = SchemaField( + description="The site ID or domain (pass-through for chaining with other blocks)" + ) post_id: int = SchemaField(description="The ID of the created post") post_url: str = SchemaField(description="The full URL of the created post") short_url: str = SchemaField(description="The shortened wp.me URL") @@ -78,7 +93,9 @@ class WordPressCreatePostBlock(Block): tags=input_data.tags, featured_image=input_data.featured_image, media_urls=input_data.media_urls, - status=PostStatus.PUBLISH, + status=( + PostStatus.DRAFT if input_data.publish_as_draft else PostStatus.PUBLISH + ), ) post_response: PostResponse = await create_post( @@ -87,7 +104,69 @@ class WordPressCreatePostBlock(Block): post_data=post_request, ) + yield "site", input_data.site yield "post_id", post_response.ID yield "post_url", post_response.URL yield "short_url", post_response.short_URL yield "post_data", post_response.model_dump() + + +class WordPressGetAllPostsBlock(Block): + """ + Fetches all posts from a WordPress.com site or Jetpack-enabled site. + Supports filtering by status and pagination. + """ + + class Input(BlockSchemaInput): + credentials: CredentialsMetaInput = wordpress.credentials_field() + site: str = SchemaField( + description="Site ID or domain (e.g., 'myblog.wordpress.com' or '123456789')" + ) + status: PostStatus | None = SchemaField( + description="Filter by post status, or None for all", + default=None, + ) + number: int = SchemaField( + description="Number of posts to retrieve (max 100 per request)", default=20 + ) + offset: int = SchemaField( + description="Number of posts to skip (for pagination)", default=0 + ) + + class Output(BlockSchemaOutput): + site: str = SchemaField( + description="The site ID or domain (pass-through for chaining with other blocks)" + ) + found: int = SchemaField(description="Total number of posts found") + posts: list[Post] = SchemaField( + description="List of post objects with their details" + ) + post: Post = SchemaField( + description="Individual post object (yielded for each post)" + ) + + def __init__(self): + super().__init__( + id="97728fa7-7f6f-4789-ba0c-f2c114119536", + description="Fetch all posts from WordPress.com or Jetpack sites", + categories={BlockCategory.SOCIAL}, + input_schema=self.Input, + output_schema=self.Output, + ) + + async def run( + self, input_data: Input, *, credentials: Credentials, **kwargs + ) -> BlockOutput: + posts_response: PostsResponse = await get_posts( + credentials=credentials, + site=input_data.site, + status=input_data.status, + number=input_data.number, + offset=input_data.offset, + ) + + yield "site", input_data.site + yield "found", posts_response.found + yield "posts", posts_response.posts + for post in posts_response.posts: + yield "post", post diff --git a/autogpt_platform/backend/backend/data/block.py b/autogpt_platform/backend/backend/data/block.py index 727688dcf0..24a68cca03 100644 --- a/autogpt_platform/backend/backend/data/block.py +++ b/autogpt_platform/backend/backend/data/block.py @@ -50,6 +50,8 @@ from .model import ( logger = logging.getLogger(__name__) if TYPE_CHECKING: + from backend.data.execution import ExecutionContext + from .graph import Link app_config = Config() @@ -472,6 +474,7 @@ class Block(ABC, Generic[BlockSchemaInputType, BlockSchemaOutputType]): self.block_type = block_type self.webhook_config = webhook_config self.execution_stats: NodeExecutionStats = NodeExecutionStats() + self.requires_human_review: bool = False if self.webhook_config: if isinstance(self.webhook_config, BlockWebhookConfig): @@ -614,7 +617,77 @@ class Block(ABC, Generic[BlockSchemaInputType, BlockSchemaOutputType]): block_id=self.id, ) from ex + async def is_block_exec_need_review( + self, + input_data: BlockInput, + *, + user_id: str, + node_exec_id: str, + graph_exec_id: str, + graph_id: str, + graph_version: int, + execution_context: "ExecutionContext", + **kwargs, + ) -> tuple[bool, BlockInput]: + """ + Check if this block execution needs human review and handle the review process. + + Returns: + Tuple of (should_pause, input_data_to_use) + - should_pause: True if execution should be paused for review + - input_data_to_use: The input data to use (may be modified by reviewer) + """ + # Skip review if not required or safe mode is disabled + if not self.requires_human_review or not execution_context.safe_mode: + return False, input_data + + from backend.blocks.helpers.review import HITLReviewHelper + + # Handle the review request and get decision + decision = await HITLReviewHelper.handle_review_decision( + input_data=input_data, + user_id=user_id, + node_exec_id=node_exec_id, + graph_exec_id=graph_exec_id, + graph_id=graph_id, + graph_version=graph_version, + execution_context=execution_context, + block_name=self.name, + editable=True, + ) + + if decision is None: + # We're awaiting review - pause execution + return True, input_data + + if not decision.should_proceed: + # Review was rejected, raise an error to stop execution + raise BlockExecutionError( + message=f"Block execution rejected by reviewer: {decision.message}", + block_name=self.name, + block_id=self.id, + ) + + # Review was approved - use the potentially modified data + # ReviewResult.data must be a dict for block inputs + reviewed_data = decision.review_result.data + if not isinstance(reviewed_data, dict): + raise BlockExecutionError( + message=f"Review data must be a dict for block input, got {type(reviewed_data).__name__}", + block_name=self.name, + block_id=self.id, + ) + return False, reviewed_data + async def _execute(self, input_data: BlockInput, **kwargs) -> BlockOutput: + # Check for review requirement and get potentially modified input data + should_pause, input_data = await self.is_block_exec_need_review( + input_data, **kwargs + ) + if should_pause: + return + + # Validate the input data (original or reviewer-modified) once if error := self.input_schema.validate_data(input_data): raise BlockInputError( message=f"Unable to execute block with invalid input data: {error}", @@ -622,6 +695,7 @@ class Block(ABC, Generic[BlockSchemaInputType, BlockSchemaOutputType]): block_id=self.id, ) + # Use the validated input data async for output_name, output_data in self.run( self.input_schema(**{k: v for k, v in input_data.items() if v is not None}), **kwargs, diff --git a/autogpt_platform/backend/backend/data/execution.py b/autogpt_platform/backend/backend/data/execution.py index 020a5a1906..2759dfe179 100644 --- a/autogpt_platform/backend/backend/data/execution.py +++ b/autogpt_platform/backend/backend/data/execution.py @@ -383,6 +383,7 @@ class GraphExecutionWithNodes(GraphExecution): self, execution_context: ExecutionContext, compiled_nodes_input_masks: Optional[NodesInputMasks] = None, + nodes_to_skip: Optional[set[str]] = None, ): return GraphExecutionEntry( user_id=self.user_id, @@ -390,6 +391,7 @@ class GraphExecutionWithNodes(GraphExecution): graph_version=self.graph_version or 0, graph_exec_id=self.id, nodes_input_masks=compiled_nodes_input_masks, + nodes_to_skip=nodes_to_skip or set(), execution_context=execution_context, ) @@ -1145,6 +1147,8 @@ class GraphExecutionEntry(BaseModel): graph_id: str graph_version: int nodes_input_masks: Optional[NodesInputMasks] = None + nodes_to_skip: set[str] = Field(default_factory=set) + """Node IDs that should be skipped due to optional credentials not being configured.""" execution_context: ExecutionContext = Field(default_factory=ExecutionContext) diff --git a/autogpt_platform/backend/backend/data/graph.py b/autogpt_platform/backend/backend/data/graph.py index 0757a86f4a..e9be80892c 100644 --- a/autogpt_platform/backend/backend/data/graph.py +++ b/autogpt_platform/backend/backend/data/graph.py @@ -94,6 +94,15 @@ class Node(BaseDbModel): input_links: list[Link] = [] output_links: list[Link] = [] + @property + def credentials_optional(self) -> bool: + """ + Whether credentials are optional for this node. + When True and credentials are not configured, the node will be skipped + during execution rather than causing a validation error. + """ + return self.metadata.get("credentials_optional", False) + @property def block(self) -> AnyBlockSchema | "_UnknownBlockBase": """Get the block for this node. Returns UnknownBlock if block is deleted/missing.""" @@ -235,7 +244,10 @@ class BaseGraph(BaseDbModel): return any( node.block_id for node in self.nodes - if node.block.block_type == BlockType.HUMAN_IN_THE_LOOP + if ( + node.block.block_type == BlockType.HUMAN_IN_THE_LOOP + or node.block.requires_human_review + ) ) @property @@ -326,7 +338,35 @@ class Graph(BaseGraph): @computed_field @property def credentials_input_schema(self) -> dict[str, Any]: - return self._credentials_input_schema.jsonschema() + schema = self._credentials_input_schema.jsonschema() + + # Determine which credential fields are required based on credentials_optional metadata + graph_credentials_inputs = self.aggregate_credentials_inputs() + required_fields = [] + + # Build a map of node_id -> node for quick lookup + all_nodes = {node.id: node for node in self.nodes} + for sub_graph in self.sub_graphs: + for node in sub_graph.nodes: + all_nodes[node.id] = node + + for field_key, ( + _field_info, + node_field_pairs, + ) in graph_credentials_inputs.items(): + # A field is required if ANY node using it has credentials_optional=False + is_required = False + for node_id, _field_name in node_field_pairs: + node = all_nodes.get(node_id) + if node and not node.credentials_optional: + is_required = True + break + + if is_required: + required_fields.append(field_key) + + schema["required"] = required_fields + return schema @property def _credentials_input_schema(self) -> type[BlockSchema]: diff --git a/autogpt_platform/backend/backend/data/graph_test.py b/autogpt_platform/backend/backend/data/graph_test.py index 044d75e0ca..eea7277eb9 100644 --- a/autogpt_platform/backend/backend/data/graph_test.py +++ b/autogpt_platform/backend/backend/data/graph_test.py @@ -396,3 +396,58 @@ async def test_access_store_listing_graph(server: SpinTestServer): created_graph.id, created_graph.version, "3e53486c-cf57-477e-ba2a-cb02dc828e1b" ) assert got_graph is not None + + +# ============================================================================ +# Tests for Optional Credentials Feature +# ============================================================================ + + +def test_node_credentials_optional_default(): + """Test that credentials_optional defaults to False when not set in metadata.""" + node = Node( + id="test_node", + block_id=StoreValueBlock().id, + input_default={}, + metadata={}, + ) + assert node.credentials_optional is False + + +def test_node_credentials_optional_true(): + """Test that credentials_optional returns True when explicitly set.""" + node = Node( + id="test_node", + block_id=StoreValueBlock().id, + input_default={}, + metadata={"credentials_optional": True}, + ) + assert node.credentials_optional is True + + +def test_node_credentials_optional_false(): + """Test that credentials_optional returns False when explicitly set to False.""" + node = Node( + id="test_node", + block_id=StoreValueBlock().id, + input_default={}, + metadata={"credentials_optional": False}, + ) + assert node.credentials_optional is False + + +def test_node_credentials_optional_with_other_metadata(): + """Test that credentials_optional works correctly with other metadata present.""" + node = Node( + id="test_node", + block_id=StoreValueBlock().id, + input_default={}, + metadata={ + "position": {"x": 100, "y": 200}, + "customized_name": "My Custom Node", + "credentials_optional": True, + }, + ) + assert node.credentials_optional is True + assert node.metadata["position"] == {"x": 100, "y": 200} + assert node.metadata["customized_name"] == "My Custom Node" diff --git a/autogpt_platform/backend/backend/executor/manager.py b/autogpt_platform/backend/backend/executor/manager.py index 75459c5a2a..39d4f984eb 100644 --- a/autogpt_platform/backend/backend/executor/manager.py +++ b/autogpt_platform/backend/backend/executor/manager.py @@ -178,6 +178,7 @@ async def execute_node( execution_processor: "ExecutionProcessor", execution_stats: NodeExecutionStats | None = None, nodes_input_masks: Optional[NodesInputMasks] = None, + nodes_to_skip: Optional[set[str]] = None, ) -> BlockOutput: """ Execute a node in the graph. This will trigger a block execution on a node, @@ -245,6 +246,7 @@ async def execute_node( "user_id": user_id, "execution_context": execution_context, "execution_processor": execution_processor, + "nodes_to_skip": nodes_to_skip or set(), } # Last-minute fetch credentials + acquire a system-wide read-write lock to prevent @@ -542,6 +544,7 @@ class ExecutionProcessor: node_exec_progress: NodeExecutionProgress, nodes_input_masks: Optional[NodesInputMasks], graph_stats_pair: tuple[GraphExecutionStats, threading.Lock], + nodes_to_skip: Optional[set[str]] = None, ) -> NodeExecutionStats: log_metadata = LogMetadata( logger=_logger, @@ -564,6 +567,7 @@ class ExecutionProcessor: db_client=db_client, log_metadata=log_metadata, nodes_input_masks=nodes_input_masks, + nodes_to_skip=nodes_to_skip, ) if isinstance(status, BaseException): raise status @@ -609,6 +613,7 @@ class ExecutionProcessor: db_client: "DatabaseManagerAsyncClient", log_metadata: LogMetadata, nodes_input_masks: Optional[NodesInputMasks] = None, + nodes_to_skip: Optional[set[str]] = None, ) -> ExecutionStatus: status = ExecutionStatus.RUNNING @@ -645,6 +650,7 @@ class ExecutionProcessor: execution_processor=self, execution_stats=stats, nodes_input_masks=nodes_input_masks, + nodes_to_skip=nodes_to_skip, ): await persist_output(output_name, output_data) @@ -956,6 +962,21 @@ class ExecutionProcessor: queued_node_exec = execution_queue.get() + # Check if this node should be skipped due to optional credentials + if queued_node_exec.node_id in graph_exec.nodes_to_skip: + log_metadata.info( + f"Skipping node execution {queued_node_exec.node_exec_id} " + f"for node {queued_node_exec.node_id} - optional credentials not configured" + ) + # Mark the node as completed without executing + # No outputs will be produced, so downstream nodes won't trigger + update_node_execution_status( + db_client=db_client, + exec_id=queued_node_exec.node_exec_id, + status=ExecutionStatus.COMPLETED, + ) + continue + log_metadata.debug( f"Dispatching node execution {queued_node_exec.node_exec_id} " f"for node {queued_node_exec.node_id}", @@ -1016,6 +1037,7 @@ class ExecutionProcessor: execution_stats, execution_stats_lock, ), + nodes_to_skip=graph_exec.nodes_to_skip, ), self.node_execution_loop, ) diff --git a/autogpt_platform/backend/backend/executor/utils.py b/autogpt_platform/backend/backend/executor/utils.py index bcd3dcf3b6..1fb2b9404f 100644 --- a/autogpt_platform/backend/backend/executor/utils.py +++ b/autogpt_platform/backend/backend/executor/utils.py @@ -239,14 +239,19 @@ async def _validate_node_input_credentials( graph: GraphModel, user_id: str, nodes_input_masks: Optional[NodesInputMasks] = None, -) -> dict[str, dict[str, str]]: +) -> tuple[dict[str, dict[str, str]], set[str]]: """ - Checks all credentials for all nodes of the graph and returns structured errors. + Checks all credentials for all nodes of the graph and returns structured errors + and a set of nodes that should be skipped due to optional missing credentials. Returns: - dict[node_id, dict[field_name, error_message]]: Credential validation errors per node + tuple[ + dict[node_id, dict[field_name, error_message]]: Credential validation errors per node, + set[node_id]: Nodes that should be skipped (optional credentials not configured) + ] """ credential_errors: dict[str, dict[str, str]] = defaultdict(dict) + nodes_to_skip: set[str] = set() for node in graph.nodes: block = node.block @@ -256,27 +261,46 @@ async def _validate_node_input_credentials( if not credentials_fields: continue + # Track if any credential field is missing for this node + has_missing_credentials = False + for field_name, credentials_meta_type in credentials_fields.items(): try: + # Check nodes_input_masks first, then input_default + field_value = None if ( nodes_input_masks and (node_input_mask := nodes_input_masks.get(node.id)) and field_name in node_input_mask ): - credentials_meta = credentials_meta_type.model_validate( - node_input_mask[field_name] - ) + field_value = node_input_mask[field_name] elif field_name in node.input_default: - credentials_meta = credentials_meta_type.model_validate( - node.input_default[field_name] - ) - else: - # Missing credentials - credential_errors[node.id][ - field_name - ] = "These credentials are required" - continue + # For optional credentials, don't use input_default - treat as missing + # This prevents stale credential IDs from failing validation + if node.credentials_optional: + field_value = None + else: + field_value = node.input_default[field_name] + + # Check if credentials are missing (None, empty, or not present) + if field_value is None or ( + isinstance(field_value, dict) and not field_value.get("id") + ): + has_missing_credentials = True + # If node has credentials_optional flag, mark for skipping instead of error + if node.credentials_optional: + continue # Don't add error, will be marked for skip after loop + else: + credential_errors[node.id][ + field_name + ] = "These credentials are required" + continue + + credentials_meta = credentials_meta_type.model_validate(field_value) + except ValidationError as e: + # Validation error means credentials were provided but invalid + # This should always be an error, even if optional credential_errors[node.id][field_name] = f"Invalid credentials: {e}" continue @@ -287,6 +311,7 @@ async def _validate_node_input_credentials( ) except Exception as e: # Handle any errors fetching credentials + # If credentials were explicitly configured but unavailable, it's an error credential_errors[node.id][ field_name ] = f"Credentials not available: {e}" @@ -313,7 +338,19 @@ async def _validate_node_input_credentials( ] = "Invalid credentials: type/provider mismatch" continue - return credential_errors + # If node has optional credentials and any are missing, mark for skipping + # But only if there are no other errors for this node + if ( + has_missing_credentials + and node.credentials_optional + and node.id not in credential_errors + ): + nodes_to_skip.add(node.id) + logger.info( + f"Node #{node.id} will be skipped: optional credentials not configured" + ) + + return credential_errors, nodes_to_skip def make_node_credentials_input_map( @@ -355,21 +392,25 @@ async def validate_graph_with_credentials( graph: GraphModel, user_id: str, nodes_input_masks: Optional[NodesInputMasks] = None, -) -> Mapping[str, Mapping[str, str]]: +) -> tuple[Mapping[str, Mapping[str, str]], set[str]]: """ - Validate graph including credentials and return structured errors per node. + Validate graph including credentials and return structured errors per node, + along with a set of nodes that should be skipped due to optional missing credentials. Returns: - dict[node_id, dict[field_name, error_message]]: Validation errors per node + tuple[ + dict[node_id, dict[field_name, error_message]]: Validation errors per node, + set[node_id]: Nodes that should be skipped (optional credentials not configured) + ] """ # Get input validation errors node_input_errors = GraphModel.validate_graph_get_errors( graph, for_run=True, nodes_input_masks=nodes_input_masks ) - # Get credential input/availability/validation errors - node_credential_input_errors = await _validate_node_input_credentials( - graph, user_id, nodes_input_masks + # Get credential input/availability/validation errors and nodes to skip + node_credential_input_errors, nodes_to_skip = ( + await _validate_node_input_credentials(graph, user_id, nodes_input_masks) ) # Merge credential errors with structural errors @@ -378,7 +419,7 @@ async def validate_graph_with_credentials( node_input_errors[node_id] = {} node_input_errors[node_id].update(field_errors) - return node_input_errors + return node_input_errors, nodes_to_skip async def _construct_starting_node_execution_input( @@ -386,7 +427,7 @@ async def _construct_starting_node_execution_input( user_id: str, graph_inputs: BlockInput, nodes_input_masks: Optional[NodesInputMasks] = None, -) -> list[tuple[str, BlockInput]]: +) -> tuple[list[tuple[str, BlockInput]], set[str]]: """ Validates and prepares the input data for executing a graph. This function checks the graph for starting nodes, validates the input data @@ -400,11 +441,14 @@ async def _construct_starting_node_execution_input( node_credentials_map: `dict[node_id, dict[input_name, CredentialsMetaInput]]` Returns: - list[tuple[str, BlockInput]]: A list of tuples, each containing the node ID and - the corresponding input data for that node. + tuple[ + list[tuple[str, BlockInput]]: A list of tuples, each containing the node ID + and the corresponding input data for that node. + set[str]: Node IDs that should be skipped (optional credentials not configured) + ] """ # Use new validation function that includes credentials - validation_errors = await validate_graph_with_credentials( + validation_errors, nodes_to_skip = await validate_graph_with_credentials( graph, user_id, nodes_input_masks ) n_error_nodes = len(validation_errors) @@ -445,7 +489,7 @@ async def _construct_starting_node_execution_input( "No starting nodes found for the graph, make sure an AgentInput or blocks with no inbound links are present as starting nodes." ) - return nodes_input + return nodes_input, nodes_to_skip async def validate_and_construct_node_execution_input( @@ -456,7 +500,7 @@ async def validate_and_construct_node_execution_input( graph_credentials_inputs: Optional[Mapping[str, CredentialsMetaInput]] = None, nodes_input_masks: Optional[NodesInputMasks] = None, is_sub_graph: bool = False, -) -> tuple[GraphModel, list[tuple[str, BlockInput]], NodesInputMasks]: +) -> tuple[GraphModel, list[tuple[str, BlockInput]], NodesInputMasks, set[str]]: """ Public wrapper that handles graph fetching, credential mapping, and validation+construction. This centralizes the logic used by both scheduler validation and actual execution. @@ -473,6 +517,7 @@ async def validate_and_construct_node_execution_input( GraphModel: Full graph object for the given `graph_id`. list[tuple[node_id, BlockInput]]: Starting node IDs with corresponding inputs. dict[str, BlockInput]: Node input masks including all passed-in credentials. + set[str]: Node IDs that should be skipped (optional credentials not configured). Raises: NotFoundError: If the graph is not found. @@ -514,14 +559,16 @@ async def validate_and_construct_node_execution_input( nodes_input_masks or {}, ) - starting_nodes_input = await _construct_starting_node_execution_input( - graph=graph, - user_id=user_id, - graph_inputs=graph_inputs, - nodes_input_masks=nodes_input_masks, + starting_nodes_input, nodes_to_skip = ( + await _construct_starting_node_execution_input( + graph=graph, + user_id=user_id, + graph_inputs=graph_inputs, + nodes_input_masks=nodes_input_masks, + ) ) - return graph, starting_nodes_input, nodes_input_masks + return graph, starting_nodes_input, nodes_input_masks, nodes_to_skip def _merge_nodes_input_masks( @@ -779,6 +826,9 @@ async def add_graph_execution( # Use existing execution's compiled input masks compiled_nodes_input_masks = graph_exec.nodes_input_masks or {} + # For resumed executions, nodes_to_skip was already determined at creation time + # TODO: Consider storing nodes_to_skip in DB if we need to preserve it across resumes + nodes_to_skip: set[str] = set() logger.info(f"Resuming graph execution #{graph_exec.id} for graph #{graph_id}") else: @@ -787,7 +837,7 @@ async def add_graph_execution( ) # Create new execution - graph, starting_nodes_input, compiled_nodes_input_masks = ( + graph, starting_nodes_input, compiled_nodes_input_masks, nodes_to_skip = ( await validate_and_construct_node_execution_input( graph_id=graph_id, user_id=user_id, @@ -836,6 +886,7 @@ async def add_graph_execution( try: graph_exec_entry = graph_exec.to_graph_execution_entry( compiled_nodes_input_masks=compiled_nodes_input_masks, + nodes_to_skip=nodes_to_skip, execution_context=execution_context, ) logger.info(f"Publishing execution {graph_exec.id} to execution queue") diff --git a/autogpt_platform/backend/backend/executor/utils_test.py b/autogpt_platform/backend/backend/executor/utils_test.py index 8854214e14..0e652f9627 100644 --- a/autogpt_platform/backend/backend/executor/utils_test.py +++ b/autogpt_platform/backend/backend/executor/utils_test.py @@ -367,10 +367,13 @@ async def test_add_graph_execution_is_repeatable(mocker: MockerFixture): ) # Setup mock returns + # The function returns (graph, starting_nodes_input, compiled_nodes_input_masks, nodes_to_skip) + nodes_to_skip: set[str] = set() mock_validate.return_value = ( mock_graph, starting_nodes_input, compiled_nodes_input_masks, + nodes_to_skip, ) mock_prisma.is_connected.return_value = True mock_edb.create_graph_execution = mocker.AsyncMock(return_value=mock_graph_exec) @@ -456,3 +459,212 @@ async def test_add_graph_execution_is_repeatable(mocker: MockerFixture): # Both executions should succeed (though they create different objects) assert result1 == mock_graph_exec assert result2 == mock_graph_exec_2 + + +# ============================================================================ +# Tests for Optional Credentials Feature +# ============================================================================ + + +@pytest.mark.asyncio +async def test_validate_node_input_credentials_returns_nodes_to_skip( + mocker: MockerFixture, +): + """ + Test that _validate_node_input_credentials returns nodes_to_skip set + for nodes with credentials_optional=True and missing credentials. + """ + from backend.executor.utils import _validate_node_input_credentials + + # Create a mock node with credentials_optional=True + mock_node = mocker.MagicMock() + mock_node.id = "node-with-optional-creds" + mock_node.credentials_optional = True + mock_node.input_default = {} # No credentials configured + + # Create a mock block with credentials field + mock_block = mocker.MagicMock() + mock_credentials_field_type = mocker.MagicMock() + mock_block.input_schema.get_credentials_fields.return_value = { + "credentials": mock_credentials_field_type + } + mock_node.block = mock_block + + # Create mock graph + mock_graph = mocker.MagicMock() + mock_graph.nodes = [mock_node] + + # Call the function + errors, nodes_to_skip = await _validate_node_input_credentials( + graph=mock_graph, + user_id="test-user-id", + nodes_input_masks=None, + ) + + # Node should be in nodes_to_skip, not in errors + assert mock_node.id in nodes_to_skip + assert mock_node.id not in errors + + +@pytest.mark.asyncio +async def test_validate_node_input_credentials_required_missing_creds_error( + mocker: MockerFixture, +): + """ + Test that _validate_node_input_credentials returns errors + for nodes with credentials_optional=False and missing credentials. + """ + from backend.executor.utils import _validate_node_input_credentials + + # Create a mock node with credentials_optional=False (required) + mock_node = mocker.MagicMock() + mock_node.id = "node-with-required-creds" + mock_node.credentials_optional = False + mock_node.input_default = {} # No credentials configured + + # Create a mock block with credentials field + mock_block = mocker.MagicMock() + mock_credentials_field_type = mocker.MagicMock() + mock_block.input_schema.get_credentials_fields.return_value = { + "credentials": mock_credentials_field_type + } + mock_node.block = mock_block + + # Create mock graph + mock_graph = mocker.MagicMock() + mock_graph.nodes = [mock_node] + + # Call the function + errors, nodes_to_skip = await _validate_node_input_credentials( + graph=mock_graph, + user_id="test-user-id", + nodes_input_masks=None, + ) + + # Node should be in errors, not in nodes_to_skip + assert mock_node.id in errors + assert "credentials" in errors[mock_node.id] + assert "required" in errors[mock_node.id]["credentials"].lower() + assert mock_node.id not in nodes_to_skip + + +@pytest.mark.asyncio +async def test_validate_graph_with_credentials_returns_nodes_to_skip( + mocker: MockerFixture, +): + """ + Test that validate_graph_with_credentials returns nodes_to_skip set + from _validate_node_input_credentials. + """ + from backend.executor.utils import validate_graph_with_credentials + + # Mock _validate_node_input_credentials to return specific values + mock_validate = mocker.patch( + "backend.executor.utils._validate_node_input_credentials" + ) + expected_errors = {"node1": {"field": "error"}} + expected_nodes_to_skip = {"node2", "node3"} + mock_validate.return_value = (expected_errors, expected_nodes_to_skip) + + # Mock GraphModel with validate_graph_get_errors method + mock_graph = mocker.MagicMock() + mock_graph.validate_graph_get_errors.return_value = {} + + # Call the function + errors, nodes_to_skip = await validate_graph_with_credentials( + graph=mock_graph, + user_id="test-user-id", + nodes_input_masks=None, + ) + + # Verify nodes_to_skip is passed through + assert nodes_to_skip == expected_nodes_to_skip + assert "node1" in errors + + +@pytest.mark.asyncio +async def test_add_graph_execution_with_nodes_to_skip(mocker: MockerFixture): + """ + Test that add_graph_execution properly passes nodes_to_skip + to the graph execution entry. + """ + from backend.data.execution import GraphExecutionWithNodes + from backend.executor.utils import add_graph_execution + + # Mock data + graph_id = "test-graph-id" + user_id = "test-user-id" + inputs = {"test_input": "test_value"} + graph_version = 1 + + # Mock the graph object + mock_graph = mocker.MagicMock() + mock_graph.version = graph_version + + # Starting nodes and masks + starting_nodes_input = [("node1", {"input1": "value1"})] + compiled_nodes_input_masks = {} + nodes_to_skip = {"skipped-node-1", "skipped-node-2"} + + # Mock the graph execution object + mock_graph_exec = mocker.MagicMock(spec=GraphExecutionWithNodes) + mock_graph_exec.id = "execution-id-123" + mock_graph_exec.node_executions = [] + + # Track what's passed to to_graph_execution_entry + captured_kwargs = {} + + def capture_to_entry(**kwargs): + captured_kwargs.update(kwargs) + return mocker.MagicMock() + + mock_graph_exec.to_graph_execution_entry.side_effect = capture_to_entry + + # Setup mocks + mock_validate = mocker.patch( + "backend.executor.utils.validate_and_construct_node_execution_input" + ) + mock_edb = mocker.patch("backend.executor.utils.execution_db") + mock_prisma = mocker.patch("backend.executor.utils.prisma") + mock_udb = mocker.patch("backend.executor.utils.user_db") + mock_gdb = mocker.patch("backend.executor.utils.graph_db") + mock_get_queue = mocker.patch("backend.executor.utils.get_async_execution_queue") + mock_get_event_bus = mocker.patch( + "backend.executor.utils.get_async_execution_event_bus" + ) + + # Setup returns - include nodes_to_skip in the tuple + mock_validate.return_value = ( + mock_graph, + starting_nodes_input, + compiled_nodes_input_masks, + nodes_to_skip, # This should be passed through + ) + mock_prisma.is_connected.return_value = True + mock_edb.create_graph_execution = mocker.AsyncMock(return_value=mock_graph_exec) + mock_edb.update_graph_execution_stats = mocker.AsyncMock( + return_value=mock_graph_exec + ) + mock_edb.update_node_execution_status_batch = mocker.AsyncMock() + + mock_user = mocker.MagicMock() + mock_user.timezone = "UTC" + mock_settings = mocker.MagicMock() + mock_settings.human_in_the_loop_safe_mode = True + + mock_udb.get_user_by_id = mocker.AsyncMock(return_value=mock_user) + mock_gdb.get_graph_settings = mocker.AsyncMock(return_value=mock_settings) + mock_get_queue.return_value = mocker.AsyncMock() + mock_get_event_bus.return_value = mocker.MagicMock(publish=mocker.AsyncMock()) + + # Call the function + await add_graph_execution( + graph_id=graph_id, + user_id=user_id, + inputs=inputs, + graph_version=graph_version, + ) + + # Verify nodes_to_skip was passed to to_graph_execution_entry + assert "nodes_to_skip" in captured_kwargs + assert captured_kwargs["nodes_to_skip"] == nodes_to_skip diff --git a/autogpt_platform/backend/backend/integrations/oauth/__init__.py b/autogpt_platform/backend/backend/integrations/oauth/__init__.py index 137b9eadfd..1ea7a23ee7 100644 --- a/autogpt_platform/backend/backend/integrations/oauth/__init__.py +++ b/autogpt_platform/backend/backend/integrations/oauth/__init__.py @@ -8,6 +8,7 @@ from .discord import DiscordOAuthHandler from .github import GitHubOAuthHandler from .google import GoogleOAuthHandler from .notion import NotionOAuthHandler +from .reddit import RedditOAuthHandler from .twitter import TwitterOAuthHandler if TYPE_CHECKING: @@ -20,6 +21,7 @@ _ORIGINAL_HANDLERS = [ GitHubOAuthHandler, GoogleOAuthHandler, NotionOAuthHandler, + RedditOAuthHandler, TwitterOAuthHandler, TodoistOAuthHandler, ] diff --git a/autogpt_platform/backend/backend/integrations/oauth/reddit.py b/autogpt_platform/backend/backend/integrations/oauth/reddit.py new file mode 100644 index 0000000000..a69e1e62c7 --- /dev/null +++ b/autogpt_platform/backend/backend/integrations/oauth/reddit.py @@ -0,0 +1,208 @@ +import time +import urllib.parse +from typing import ClassVar, Optional + +from pydantic import SecretStr + +from backend.data.model import OAuth2Credentials +from backend.integrations.oauth.base import BaseOAuthHandler +from backend.integrations.providers import ProviderName +from backend.util.request import Requests +from backend.util.settings import Settings + +settings = Settings() + + +class RedditOAuthHandler(BaseOAuthHandler): + """ + Reddit OAuth 2.0 handler. + + Based on the documentation at: + - https://github.com/reddit-archive/reddit/wiki/OAuth2 + + Notes: + - Reddit requires `duration=permanent` to get refresh tokens + - Access tokens expire after 1 hour (3600 seconds) + - Reddit requires HTTP Basic Auth for token requests + - Reddit requires a unique User-Agent header + """ + + PROVIDER_NAME = ProviderName.REDDIT + DEFAULT_SCOPES: ClassVar[list[str]] = [ + "identity", # Get username, verify auth + "read", # Access posts and comments + "submit", # Submit new posts and comments + "edit", # Edit own posts and comments + "history", # Access user's post history + "privatemessages", # Access inbox and send private messages + "flair", # Access and set flair on posts/subreddits + ] + + AUTHORIZE_URL = "https://www.reddit.com/api/v1/authorize" + TOKEN_URL = "https://www.reddit.com/api/v1/access_token" + USERNAME_URL = "https://oauth.reddit.com/api/v1/me" + REVOKE_URL = "https://www.reddit.com/api/v1/revoke_token" + + def __init__(self, client_id: str, client_secret: str, redirect_uri: str): + self.client_id = client_id + self.client_secret = client_secret + self.redirect_uri = redirect_uri + + def get_login_url( + self, scopes: list[str], state: str, code_challenge: Optional[str] + ) -> str: + """Generate Reddit OAuth 2.0 authorization URL""" + scopes = self.handle_default_scopes(scopes) + + params = { + "response_type": "code", + "client_id": self.client_id, + "redirect_uri": self.redirect_uri, + "scope": " ".join(scopes), + "state": state, + "duration": "permanent", # Required for refresh tokens + } + + return f"{self.AUTHORIZE_URL}?{urllib.parse.urlencode(params)}" + + async def exchange_code_for_tokens( + self, code: str, scopes: list[str], code_verifier: Optional[str] + ) -> OAuth2Credentials: + """Exchange authorization code for access tokens""" + scopes = self.handle_default_scopes(scopes) + + headers = { + "Content-Type": "application/x-www-form-urlencoded", + "User-Agent": settings.config.reddit_user_agent, + } + + data = { + "grant_type": "authorization_code", + "code": code, + "redirect_uri": self.redirect_uri, + } + + # Reddit requires HTTP Basic Auth for token requests + auth = (self.client_id, self.client_secret) + + response = await Requests().post( + self.TOKEN_URL, headers=headers, data=data, auth=auth + ) + + if not response.ok: + error_text = response.text() + raise ValueError( + f"Reddit token exchange failed: {response.status} - {error_text}" + ) + + tokens = response.json() + + if "error" in tokens: + raise ValueError(f"Reddit OAuth error: {tokens.get('error')}") + + username = await self._get_username(tokens["access_token"]) + + return OAuth2Credentials( + provider=self.PROVIDER_NAME, + title=None, + username=username, + access_token=tokens["access_token"], + refresh_token=tokens.get("refresh_token"), + access_token_expires_at=int(time.time()) + tokens.get("expires_in", 3600), + refresh_token_expires_at=None, # Reddit refresh tokens don't expire + scopes=scopes, + ) + + async def _get_username(self, access_token: str) -> str: + """Get the username from the access token""" + headers = { + "Authorization": f"Bearer {access_token}", + "User-Agent": settings.config.reddit_user_agent, + } + + response = await Requests().get(self.USERNAME_URL, headers=headers) + + if not response.ok: + raise ValueError(f"Failed to get Reddit username: {response.status}") + + data = response.json() + return data.get("name", "unknown") + + async def _refresh_tokens( + self, credentials: OAuth2Credentials + ) -> OAuth2Credentials: + """Refresh access tokens using refresh token""" + if not credentials.refresh_token: + raise ValueError("No refresh token available") + + headers = { + "Content-Type": "application/x-www-form-urlencoded", + "User-Agent": settings.config.reddit_user_agent, + } + + data = { + "grant_type": "refresh_token", + "refresh_token": credentials.refresh_token.get_secret_value(), + } + + auth = (self.client_id, self.client_secret) + + response = await Requests().post( + self.TOKEN_URL, headers=headers, data=data, auth=auth + ) + + if not response.ok: + error_text = response.text() + raise ValueError( + f"Reddit token refresh failed: {response.status} - {error_text}" + ) + + tokens = response.json() + + if "error" in tokens: + raise ValueError(f"Reddit OAuth error: {tokens.get('error')}") + + username = await self._get_username(tokens["access_token"]) + + # Reddit may or may not return a new refresh token + new_refresh_token = tokens.get("refresh_token") + if new_refresh_token: + refresh_token: SecretStr | None = SecretStr(new_refresh_token) + elif credentials.refresh_token: + # Keep the existing refresh token + refresh_token = credentials.refresh_token + else: + refresh_token = None + + return OAuth2Credentials( + id=credentials.id, + provider=self.PROVIDER_NAME, + title=credentials.title, + username=username, + access_token=tokens["access_token"], + refresh_token=refresh_token, + access_token_expires_at=int(time.time()) + tokens.get("expires_in", 3600), + refresh_token_expires_at=None, + scopes=credentials.scopes, + ) + + async def revoke_tokens(self, credentials: OAuth2Credentials) -> bool: + """Revoke the access token""" + headers = { + "Content-Type": "application/x-www-form-urlencoded", + "User-Agent": settings.config.reddit_user_agent, + } + + data = { + "token": credentials.access_token.get_secret_value(), + "token_type_hint": "access_token", + } + + auth = (self.client_id, self.client_secret) + + response = await Requests().post( + self.REVOKE_URL, headers=headers, data=data, auth=auth + ) + + # Reddit returns 204 No Content on successful revocation + return response.ok diff --git a/autogpt_platform/backend/backend/util/settings.py b/autogpt_platform/backend/backend/util/settings.py index 0f17b1215c..7a51200eaf 100644 --- a/autogpt_platform/backend/backend/util/settings.py +++ b/autogpt_platform/backend/backend/util/settings.py @@ -264,7 +264,7 @@ class Config(UpdateTrackingModel["Config"], BaseSettings): ) reddit_user_agent: str = Field( - default="AutoGPT:1.0 (by /u/autogpt)", + default="web:AutoGPT:v0.6.0 (by /u/autogpt)", description="The user agent for the Reddit API", ) diff --git a/autogpt_platform/backend/gen_prisma_types_stub.py b/autogpt_platform/backend/gen_prisma_types_stub.py new file mode 100644 index 0000000000..3f6073b2ff --- /dev/null +++ b/autogpt_platform/backend/gen_prisma_types_stub.py @@ -0,0 +1,227 @@ +#!/usr/bin/env python3 +""" +Generate a lightweight stub for prisma/types.py that collapses all exported +symbols to Any. This prevents Pyright from spending time/budget on Prisma's +query DSL types while keeping runtime behavior unchanged. + +Usage: + poetry run gen-prisma-stub + +This script automatically finds the prisma package location and generates +the types.pyi stub file in the same directory as types.py. +""" + +from __future__ import annotations + +import ast +import importlib.util +import sys +from pathlib import Path +from typing import Iterable, Set + + +def _iter_assigned_names(target: ast.expr) -> Iterable[str]: + """Extract names from assignment targets (handles tuple unpacking).""" + if isinstance(target, ast.Name): + yield target.id + elif isinstance(target, (ast.Tuple, ast.List)): + for elt in target.elts: + yield from _iter_assigned_names(elt) + + +def _is_private(name: str) -> bool: + """Check if a name is private (starts with _ but not __).""" + return name.startswith("_") and not name.startswith("__") + + +def _is_safe_type_alias(node: ast.Assign) -> bool: + """Check if an assignment is a safe type alias that shouldn't be stubbed. + + Safe types are: + - Literal types (don't cause type budget issues) + - Simple type references (SortMode, SortOrder, etc.) + - TypeVar definitions + """ + if not node.value: + return False + + # Check if it's a Subscript (like Literal[...], Union[...], TypeVar[...]) + if isinstance(node.value, ast.Subscript): + # Get the base type name + if isinstance(node.value.value, ast.Name): + base_name = node.value.value.id + # Literal types are safe + if base_name == "Literal": + return True + # TypeVar is safe + if base_name == "TypeVar": + return True + elif isinstance(node.value.value, ast.Attribute): + # Handle typing_extensions.Literal etc. + if node.value.value.attr == "Literal": + return True + + # Check if it's a simple Name reference (like SortMode = _types.SortMode) + if isinstance(node.value, ast.Attribute): + return True + + # Check if it's a Call (like TypeVar(...)) + if isinstance(node.value, ast.Call): + if isinstance(node.value.func, ast.Name): + if node.value.func.id == "TypeVar": + return True + + return False + + +def collect_top_level_symbols( + tree: ast.Module, source_lines: list[str] +) -> tuple[Set[str], Set[str], list[str], Set[str]]: + """Collect all top-level symbols from an AST module. + + Returns: + Tuple of (class_names, function_names, safe_variable_sources, unsafe_variable_names) + safe_variable_sources contains the actual source code lines for safe variables + """ + classes: Set[str] = set() + functions: Set[str] = set() + safe_variable_sources: list[str] = [] + unsafe_variables: Set[str] = set() + + for node in tree.body: + if isinstance(node, ast.ClassDef): + if not _is_private(node.name): + classes.add(node.name) + elif isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)): + if not _is_private(node.name): + functions.add(node.name) + elif isinstance(node, ast.Assign): + is_safe = _is_safe_type_alias(node) + names = [] + for t in node.targets: + for n in _iter_assigned_names(t): + if not _is_private(n): + names.append(n) + if names: + if is_safe: + # Extract the source code for this assignment + start_line = node.lineno - 1 # 0-indexed + end_line = node.end_lineno if node.end_lineno else node.lineno + source = "\n".join(source_lines[start_line:end_line]) + safe_variable_sources.append(source) + else: + unsafe_variables.update(names) + elif isinstance(node, ast.AnnAssign) and node.target: + # Annotated assignments are always stubbed + for n in _iter_assigned_names(node.target): + if not _is_private(n): + unsafe_variables.add(n) + + return classes, functions, safe_variable_sources, unsafe_variables + + +def find_prisma_types_path() -> Path: + """Find the prisma types.py file in the installed package.""" + spec = importlib.util.find_spec("prisma") + if spec is None or spec.origin is None: + raise RuntimeError("Could not find prisma package. Is it installed?") + + prisma_dir = Path(spec.origin).parent + types_path = prisma_dir / "types.py" + + if not types_path.exists(): + raise RuntimeError(f"prisma/types.py not found at {types_path}") + + return types_path + + +def generate_stub(src_path: Path, stub_path: Path) -> int: + """Generate the .pyi stub file from the source types.py.""" + code = src_path.read_text(encoding="utf-8", errors="ignore") + source_lines = code.splitlines() + tree = ast.parse(code, filename=str(src_path)) + classes, functions, safe_variable_sources, unsafe_variables = ( + collect_top_level_symbols(tree, source_lines) + ) + + header = """\ +# -*- coding: utf-8 -*- +# Auto-generated stub file - DO NOT EDIT +# Generated by gen_prisma_types_stub.py +# +# This stub intentionally collapses complex Prisma query DSL types to Any. +# Prisma's generated types can explode Pyright's type inference budgets +# on large schemas. We collapse them to Any so the rest of the codebase +# can remain strongly typed while keeping runtime behavior unchanged. +# +# Safe types (Literal, TypeVar, simple references) are preserved from the +# original types.py to maintain proper type checking where possible. + +from __future__ import annotations +from typing import Any +from typing_extensions import Literal + +# Re-export commonly used typing constructs that may be imported from this module +from typing import TYPE_CHECKING, TypeVar, Generic, Union, Optional, List, Dict + +# Base type alias for stubbed Prisma types - allows any dict structure +_PrismaDict = dict[str, Any] + +""" + + lines = [header] + + # Include safe variable definitions (Literal types, TypeVars, etc.) + lines.append("# Safe type definitions preserved from original types.py") + for source in safe_variable_sources: + lines.append(source) + lines.append("") + + # Stub all classes and unsafe variables uniformly as dict[str, Any] aliases + # This allows: + # 1. Use in type annotations: x: SomeType + # 2. Constructor calls: SomeType(...) + # 3. Dict literal assignments: x: SomeType = {...} + lines.append( + "# Stubbed types (collapsed to dict[str, Any] to prevent type budget exhaustion)" + ) + all_stubbed = sorted(classes | unsafe_variables) + for name in all_stubbed: + lines.append(f"{name} = _PrismaDict") + + lines.append("") + + # Stub functions + for name in sorted(functions): + lines.append(f"def {name}(*args: Any, **kwargs: Any) -> Any: ...") + + lines.append("") + + stub_path.write_text("\n".join(lines), encoding="utf-8") + return ( + len(classes) + + len(functions) + + len(safe_variable_sources) + + len(unsafe_variables) + ) + + +def main() -> None: + """Main entry point.""" + try: + types_path = find_prisma_types_path() + stub_path = types_path.with_suffix(".pyi") + + print(f"Found prisma types.py at: {types_path}") + print(f"Generating stub at: {stub_path}") + + num_symbols = generate_stub(types_path, stub_path) + print(f"Generated {stub_path.name} with {num_symbols} Any-typed symbols") + + except Exception as e: + print(f"Error: {e}", file=sys.stderr) + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/autogpt_platform/backend/linter.py b/autogpt_platform/backend/linter.py index a86e6761f7..599aae4580 100644 --- a/autogpt_platform/backend/linter.py +++ b/autogpt_platform/backend/linter.py @@ -25,6 +25,9 @@ def run(*command: str) -> None: def lint(): + # Generate Prisma types stub before running pyright to prevent type budget exhaustion + run("gen-prisma-stub") + lint_step_args: list[list[str]] = [ ["ruff", "check", *TARGET_DIRS, "--exit-zero"], ["ruff", "format", "--diff", "--check", LIBS_DIR], @@ -49,4 +52,6 @@ def format(): run("ruff", "format", LIBS_DIR) run("isort", "--profile", "black", BACKEND_DIR) run("black", BACKEND_DIR) + # Generate Prisma types stub before running pyright to prevent type budget exhaustion + run("gen-prisma-stub") run("pyright", *TARGET_DIRS) diff --git a/autogpt_platform/backend/pyproject.toml b/autogpt_platform/backend/pyproject.toml index e8b8fd0ba5..21bf15e776 100644 --- a/autogpt_platform/backend/pyproject.toml +++ b/autogpt_platform/backend/pyproject.toml @@ -117,6 +117,7 @@ lint = "linter:lint" test = "run_tests:test" load-store-agents = "test.load_store_agents:run" export-api-schema = "backend.cli.generate_openapi_json:main" +gen-prisma-stub = "gen_prisma_types_stub:main" oauth-tool = "backend.cli.oauth_tool:cli" [tool.isort] @@ -134,6 +135,9 @@ ignore_patterns = [] [tool.pytest.ini_options] asyncio_mode = "auto" asyncio_default_fixture_loop_scope = "session" +# Disable syrupy plugin to avoid conflict with pytest-snapshot +# Both provide --snapshot-update argument causing ArgumentError +addopts = "-p no:syrupy" filterwarnings = [ "ignore:'audioop' is deprecated:DeprecationWarning:discord.player", "ignore:invalid escape sequence:DeprecationWarning:tweepy.api", diff --git a/autogpt_platform/backend/snapshots/grph_single b/autogpt_platform/backend/snapshots/grph_single index 7ba26f6171..7ce8695e6b 100644 --- a/autogpt_platform/backend/snapshots/grph_single +++ b/autogpt_platform/backend/snapshots/grph_single @@ -2,6 +2,7 @@ "created_at": "2025-09-04T13:37:00", "credentials_input_schema": { "properties": {}, + "required": [], "title": "TestGraphCredentialsInputSchema", "type": "object" }, diff --git a/autogpt_platform/backend/snapshots/grphs_all b/autogpt_platform/backend/snapshots/grphs_all index d54df2bc18..f69b45a6de 100644 --- a/autogpt_platform/backend/snapshots/grphs_all +++ b/autogpt_platform/backend/snapshots/grphs_all @@ -2,6 +2,7 @@ { "credentials_input_schema": { "properties": {}, + "required": [], "title": "TestGraphCredentialsInputSchema", "type": "object" }, diff --git a/autogpt_platform/backend/snapshots/lib_agts_search b/autogpt_platform/backend/snapshots/lib_agts_search index d1feb7d16d..c8e3cc73a6 100644 --- a/autogpt_platform/backend/snapshots/lib_agts_search +++ b/autogpt_platform/backend/snapshots/lib_agts_search @@ -4,6 +4,7 @@ "id": "test-agent-1", "graph_id": "test-agent-1", "graph_version": 1, + "owner_user_id": "3e53486c-cf57-477e-ba2a-cb02dc828e1a", "image_url": null, "creator_name": "Test Creator", "creator_image_url": "", @@ -41,6 +42,7 @@ "id": "test-agent-2", "graph_id": "test-agent-2", "graph_version": 1, + "owner_user_id": "3e53486c-cf57-477e-ba2a-cb02dc828e1a", "image_url": null, "creator_name": "Test Creator", "creator_image_url": "", diff --git a/autogpt_platform/backend/snapshots/sub_success b/autogpt_platform/backend/snapshots/sub_success index 13e2ec570d..268d577745 100644 --- a/autogpt_platform/backend/snapshots/sub_success +++ b/autogpt_platform/backend/snapshots/sub_success @@ -1,6 +1,7 @@ { "submissions": [ { + "listing_id": "test-listing-id", "agent_id": "test-agent-id", "agent_version": 1, "name": "Test Agent", diff --git a/autogpt_platform/docker-compose.platform.yml b/autogpt_platform/docker-compose.platform.yml index b2df626029..de6ecfd612 100644 --- a/autogpt_platform/docker-compose.platform.yml +++ b/autogpt_platform/docker-compose.platform.yml @@ -37,7 +37,7 @@ services: context: ../ dockerfile: autogpt_platform/backend/Dockerfile target: migrate - command: ["sh", "-c", "poetry run prisma generate && poetry run prisma migrate deploy"] + command: ["sh", "-c", "poetry run prisma generate && poetry run gen-prisma-stub && poetry run prisma migrate deploy"] develop: watch: - path: ./ diff --git a/autogpt_platform/frontend/package.json b/autogpt_platform/frontend/package.json index 1708ac9053..f881ebaf5b 100644 --- a/autogpt_platform/frontend/package.json +++ b/autogpt_platform/frontend/package.json @@ -46,14 +46,15 @@ "@radix-ui/react-scroll-area": "1.2.10", "@radix-ui/react-select": "2.2.6", "@radix-ui/react-separator": "1.1.7", + "@radix-ui/react-slider": "1.3.6", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-switch": "1.2.6", "@radix-ui/react-tabs": "1.1.13", "@radix-ui/react-toast": "1.2.15", "@radix-ui/react-tooltip": "1.2.8", - "@rjsf/core": "5.24.13", - "@rjsf/utils": "5.24.13", - "@rjsf/validator-ajv8": "5.24.13", + "@rjsf/core": "6.1.2", + "@rjsf/utils": "6.1.2", + "@rjsf/validator-ajv8": "6.1.2", "@sentry/nextjs": "10.27.0", "@supabase/ssr": "0.7.0", "@supabase/supabase-js": "2.78.0", @@ -91,7 +92,6 @@ "react-currency-input-field": "4.0.3", "react-day-picker": "9.11.1", "react-dom": "18.3.1", - "react-drag-drop-files": "2.4.0", "react-hook-form": "7.66.0", "react-icons": "5.5.0", "react-markdown": "9.0.3", diff --git a/autogpt_platform/frontend/pnpm-lock.yaml b/autogpt_platform/frontend/pnpm-lock.yaml index 355ffff129..4240d0d155 100644 --- a/autogpt_platform/frontend/pnpm-lock.yaml +++ b/autogpt_platform/frontend/pnpm-lock.yaml @@ -16,7 +16,7 @@ importers: version: 5.2.2(react-hook-form@7.66.0(react@18.3.1)) '@next/third-parties': specifier: 15.4.6 - version: 15.4.6(next@15.4.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 15.4.6(next@15.4.10(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@phosphor-icons/react': specifier: 2.1.10 version: 2.1.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -62,6 +62,9 @@ importers: '@radix-ui/react-separator': specifier: 1.1.7 version: 1.1.7(@types/react-dom@18.3.5(@types/react@18.3.17))(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slider': + specifier: 1.3.6 + version: 1.3.6(@types/react-dom@18.3.5(@types/react@18.3.17))(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-slot': specifier: 1.2.3 version: 1.2.3(@types/react@18.3.17)(react@18.3.1) @@ -78,17 +81,17 @@ importers: specifier: 1.2.8 version: 1.2.8(@types/react-dom@18.3.5(@types/react@18.3.17))(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@rjsf/core': - specifier: 5.24.13 - version: 5.24.13(@rjsf/utils@5.24.13(react@18.3.1))(react@18.3.1) + specifier: 6.1.2 + version: 6.1.2(@rjsf/utils@6.1.2(react@18.3.1))(react@18.3.1) '@rjsf/utils': - specifier: 5.24.13 - version: 5.24.13(react@18.3.1) + specifier: 6.1.2 + version: 6.1.2(react@18.3.1) '@rjsf/validator-ajv8': - specifier: 5.24.13 - version: 5.24.13(@rjsf/utils@5.24.13(react@18.3.1)) + specifier: 6.1.2 + version: 6.1.2(@rjsf/utils@6.1.2(react@18.3.1)) '@sentry/nextjs': specifier: 10.27.0 - version: 10.27.0(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(next@15.4.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.101.3(esbuild@0.25.9)) + version: 10.27.0(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(next@15.4.10(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.104.1(esbuild@0.25.12)) '@supabase/ssr': specifier: 0.7.0 version: 0.7.0(@supabase/supabase-js@2.78.0) @@ -106,13 +109,13 @@ importers: version: 0.2.4 '@vercel/analytics': specifier: 1.5.0 - version: 1.5.0(next@15.4.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 1.5.0(next@15.4.10(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@vercel/speed-insights': specifier: 1.2.0 - version: 1.2.0(next@15.4.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 1.2.0(next@15.4.10(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@xyflow/react': specifier: 12.9.2 - version: 12.9.2(@types/react@18.3.17)(immer@10.1.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 12.9.2(@types/react@18.3.17)(immer@11.1.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) boring-avatars: specifier: 1.11.2 version: 1.11.2 @@ -151,7 +154,7 @@ importers: version: 12.23.24(@emotion/is-prop-valid@1.2.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) geist: specifier: 1.5.1 - version: 1.5.1(next@15.4.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + version: 1.5.1(next@15.4.10(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) highlight.js: specifier: 11.11.1 version: 11.11.1 @@ -175,13 +178,13 @@ importers: version: 2.30.1 next: specifier: 15.4.10 - version: 15.4.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 15.4.10(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next-themes: specifier: 0.4.6 version: 0.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) nuqs: specifier: 2.7.2 - version: 2.7.2(next@15.4.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 2.7.2(next@15.4.10(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) party-js: specifier: 2.2.0 version: 2.2.0 @@ -197,9 +200,6 @@ importers: react-dom: specifier: 18.3.1 version: 18.3.1(react@18.3.1) - react-drag-drop-files: - specifier: 2.4.0 - version: 2.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-hook-form: specifier: 7.66.0 version: 7.66.0(react@18.3.1) @@ -265,7 +265,7 @@ importers: version: 3.25.76 zustand: specifier: 5.0.8 - version: 5.0.8(@types/react@18.3.17)(immer@10.1.3)(react@18.3.1)(use-sync-external-store@1.5.0(react@18.3.1)) + version: 5.0.8(@types/react@18.3.17)(immer@11.1.3)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) devDependencies: '@chromatic-com/storybook': specifier: 4.1.2 @@ -287,7 +287,7 @@ importers: version: 9.1.5(storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2)) '@storybook/nextjs': specifier: 9.1.5 - version: 9.1.5(esbuild@0.25.9)(next@15.4.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2))(type-fest@4.41.0)(typescript@5.9.3)(webpack-hot-middleware@2.26.1)(webpack@5.101.3(esbuild@0.25.9)) + version: 9.1.5(esbuild@0.25.12)(next@15.4.10(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2))(type-fest@4.41.0)(typescript@5.9.3)(webpack-hot-middleware@2.26.1)(webpack@5.104.1(esbuild@0.25.12)) '@tanstack/eslint-plugin-query': specifier: 5.91.2 version: 5.91.2(eslint@8.57.1)(typescript@5.9.3) @@ -411,16 +411,16 @@ packages: resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.28.4': - resolution: {integrity: sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==} + '@babel/compat-data@7.28.5': + resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} engines: {node: '>=6.9.0'} - '@babel/core@7.28.4': - resolution: {integrity: sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==} + '@babel/core@7.28.5': + resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} engines: {node: '>=6.9.0'} - '@babel/generator@7.28.3': - resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} + '@babel/generator@7.28.5': + resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} engines: {node: '>=6.9.0'} '@babel/helper-annotate-as-pure@7.27.3': @@ -431,14 +431,14 @@ packages: resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} engines: {node: '>=6.9.0'} - '@babel/helper-create-class-features-plugin@7.28.3': - resolution: {integrity: sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==} + '@babel/helper-create-class-features-plugin@7.28.5': + resolution: {integrity: sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-create-regexp-features-plugin@7.27.1': - resolution: {integrity: sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==} + '@babel/helper-create-regexp-features-plugin@7.28.5': + resolution: {integrity: sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -452,8 +452,8 @@ packages: resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} engines: {node: '>=6.9.0'} - '@babel/helper-member-expression-to-functions@7.27.1': - resolution: {integrity: sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==} + '@babel/helper-member-expression-to-functions@7.28.5': + resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} engines: {node: '>=6.9.0'} '@babel/helper-module-imports@7.27.1': @@ -494,8 +494,8 @@ packages: resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.27.1': - resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} '@babel/helper-validator-option@7.27.1': @@ -510,13 +510,13 @@ packages: resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} engines: {node: '>=6.9.0'} - '@babel/parser@7.28.4': - resolution: {integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==} + '@babel/parser@7.28.5': + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1': - resolution: {integrity: sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==} + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5': + resolution: {integrity: sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -615,8 +615,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-block-scoping@7.28.4': - resolution: {integrity: sha512-1yxmvN0MJHOhPVmAsmoW5liWwoILobu/d/ShymZmj867bAdxGbehIrew1DuLpw2Ukv+qDSSPQdYW1dLNE7t11A==} + '@babel/plugin-transform-block-scoping@7.28.5': + resolution: {integrity: sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -645,8 +645,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-destructuring@7.28.0': - resolution: {integrity: sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==} + '@babel/plugin-transform-destructuring@7.28.5': + resolution: {integrity: sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -681,8 +681,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-exponentiation-operator@7.27.1': - resolution: {integrity: sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==} + '@babel/plugin-transform-exponentiation-operator@7.28.5': + resolution: {integrity: sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -717,8 +717,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-logical-assignment-operators@7.27.1': - resolution: {integrity: sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==} + '@babel/plugin-transform-logical-assignment-operators@7.28.5': + resolution: {integrity: sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -741,8 +741,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-systemjs@7.27.1': - resolution: {integrity: sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==} + '@babel/plugin-transform-modules-systemjs@7.28.5': + resolution: {integrity: sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -795,8 +795,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-optional-chaining@7.27.1': - resolution: {integrity: sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==} + '@babel/plugin-transform-optional-chaining@7.28.5': + resolution: {integrity: sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -867,8 +867,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-runtime@7.28.3': - resolution: {integrity: sha512-Y6ab1kGqZ0u42Zv/4a7l0l72n9DKP/MKoKWaUSBylrhNZO2prYuqFOLbn5aW5SIFXwSH93yfjbgllL8lxuGKLg==} + '@babel/plugin-transform-runtime@7.28.5': + resolution: {integrity: sha512-20NUVgOrinudkIBzQ2bNxP08YpKprUkRTiRSd2/Z5GOdPImJGkoN4Z7IQe1T5AdyKI1i5L6RBmluqdSzvaq9/w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -903,8 +903,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-typescript@7.28.0': - resolution: {integrity: sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg==} + '@babel/plugin-transform-typescript@7.28.5': + resolution: {integrity: sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -933,8 +933,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0 - '@babel/preset-env@7.28.3': - resolution: {integrity: sha512-ROiDcM+GbYVPYBOeCR6uBXKkQpBExLl8k9HO1ygXEyds39j+vCCsjmj7S8GOniZQlEs81QlkdJZe76IpLSiqpg==} + '@babel/preset-env@7.28.5': + resolution: {integrity: sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -944,14 +944,14 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 - '@babel/preset-react@7.27.1': - resolution: {integrity: sha512-oJHWh2gLhU9dW9HHr42q0cI0/iHHXTLGe39qvpAZZzagHy0MzYLCnCVV0symeRvzmjHyVU7mw2K06E6u/JwbhA==} + '@babel/preset-react@7.28.5': + resolution: {integrity: sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/preset-typescript@7.27.1': - resolution: {integrity: sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ==} + '@babel/preset-typescript@7.28.5': + resolution: {integrity: sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -964,12 +964,12 @@ packages: resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.28.4': - resolution: {integrity: sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==} + '@babel/traverse@7.28.5': + resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} engines: {node: '>=6.9.0'} - '@babel/types@7.28.4': - resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} engines: {node: '>=6.9.0'} '@chromatic-com/storybook@4.1.2': @@ -986,14 +986,11 @@ packages: '@date-fns/tz@1.4.1': resolution: {integrity: sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==} - '@emnapi/core@1.7.1': - resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} + '@emnapi/core@1.8.1': + resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} - '@emnapi/runtime@1.5.0': - resolution: {integrity: sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==} - - '@emnapi/runtime@1.7.1': - resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} + '@emnapi/runtime@1.8.1': + resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} @@ -1004,334 +1001,171 @@ packages: '@emotion/memoize@0.8.1': resolution: {integrity: sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==} - '@emotion/unitless@0.8.1': - resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==} - '@epic-web/invariant@1.0.0': resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==} - '@esbuild/aix-ppc64@0.25.11': - resolution: {integrity: sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==} + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.25.9': - resolution: {integrity: sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.25.11': - resolution: {integrity: sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==} + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.25.9': - resolution: {integrity: sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.25.11': - resolution: {integrity: sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==} + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-arm@0.25.9': - resolution: {integrity: sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.25.11': - resolution: {integrity: sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==} + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/android-x64@0.25.9': - resolution: {integrity: sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.25.11': - resolution: {integrity: sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==} + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.25.9': - resolution: {integrity: sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.25.11': - resolution: {integrity: sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==} + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.25.9': - resolution: {integrity: sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.25.11': - resolution: {integrity: sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==} + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.25.9': - resolution: {integrity: sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.25.11': - resolution: {integrity: sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==} + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.9': - resolution: {integrity: sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.25.11': - resolution: {integrity: sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==} + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.25.9': - resolution: {integrity: sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.25.11': - resolution: {integrity: sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==} + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.25.9': - resolution: {integrity: sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.25.11': - resolution: {integrity: sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==} + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.25.9': - resolution: {integrity: sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.25.11': - resolution: {integrity: sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==} + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.25.9': - resolution: {integrity: sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.25.11': - resolution: {integrity: sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==} + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.25.9': - resolution: {integrity: sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.25.11': - resolution: {integrity: sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==} + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.25.9': - resolution: {integrity: sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.25.11': - resolution: {integrity: sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==} + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.25.9': - resolution: {integrity: sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.25.11': - resolution: {integrity: sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==} + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.25.9': - resolution: {integrity: sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.25.11': - resolution: {integrity: sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==} + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.25.9': - resolution: {integrity: sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-arm64@0.25.11': - resolution: {integrity: sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==} + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-arm64@0.25.9': - resolution: {integrity: sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.25.11': - resolution: {integrity: sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==} + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.9': - resolution: {integrity: sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.25.11': - resolution: {integrity: sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==} + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-arm64@0.25.9': - resolution: {integrity: sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.25.11': - resolution: {integrity: sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==} + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.9': - resolution: {integrity: sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openharmony-arm64@0.25.11': - resolution: {integrity: sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==} + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/openharmony-arm64@0.25.9': - resolution: {integrity: sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - - '@esbuild/sunos-x64@0.25.11': - resolution: {integrity: sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==} + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.25.9': - resolution: {integrity: sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.25.11': - resolution: {integrity: sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==} + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.25.9': - resolution: {integrity: sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.25.11': - resolution: {integrity: sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==} + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.25.9': - resolution: {integrity: sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.25.11': - resolution: {integrity: sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==} + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} engines: {node: '>=18'} cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.25.9': - resolution: {integrity: sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - - '@eslint-community/eslint-utils@4.9.0': - resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} + '@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.1': - resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.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} @@ -1354,11 +1188,11 @@ packages: '@floating-ui/core@1.7.3': resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} - '@floating-ui/dom@1.7.3': - resolution: {integrity: sha512-uZA413QEpNuhtb3/iIKoYMSK07keHPYeXF02Zhd6e213j+d1NamLix/mCLxBUDW/Gx52sPH2m+chlUsyaBs/Ag==} + '@floating-ui/dom@1.7.4': + resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} - '@floating-ui/react-dom@2.1.5': - resolution: {integrity: sha512-HDO/1/1oH9fjj4eLgegrlH3dklZpHtUYYFiVwMUwfGvk9jWDRWqkklA2/NFScknrcNSspbV868WjXORvreDX+Q==} + '@floating-ui/react-dom@2.1.6': + resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==} peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' @@ -1366,8 +1200,8 @@ packages: '@floating-ui/utils@0.2.10': resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} - '@gerrit0/mini-shiki@3.14.0': - resolution: {integrity: sha512-c5X8fwPLOtUS8TVdqhynz9iV0GlOtFUT1ppXYzUUlEXe4kbZ/mvMT8wXoT8kCwUka+zsiloq7sD3pZ3+QVTuNQ==} + '@gerrit0/mini-shiki@3.20.0': + resolution: {integrity: sha512-Wa57i+bMpK6PGJZ1f2myxo3iO+K/kZikcyvH8NIqNNZhQUbDav7V9LQmWOXhf946mz5c1NZ19WMsGYiDKTryzQ==} '@hookform/resolvers@5.2.2': resolution: {integrity: sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA==} @@ -1391,138 +1225,153 @@ packages: resolution: {integrity: sha512-AoFbSarOqFBYH+1TZ9Ahkm2IWYSi5v0pBk88fpV+5b3qGJukypX8PwvCWADjuyIccKg48/F73a6hTTkBzDQ2UA==} engines: {node: '>=16.0.0'} - '@ibm-cloud/openapi-ruleset@1.33.3': - resolution: {integrity: sha512-lOxglXIzUZwsw5WsbgZraxxzAYMdXYyiMNOioxYJYTd55ZuN4XEERoPdV5v1oPTdKedHEUSQu5siiSHToENFdA==} + '@ibm-cloud/openapi-ruleset@1.33.5': + resolution: {integrity: sha512-oT8USsTulFAA8FiBN0lA2rJqQI2lIt+HP2pdakGQXo3EviL2vqJTgpSCRwjl6mLJL158f1BVcdQUOEFGxomK3w==} engines: {node: '>=16.0.0'} - '@img/sharp-darwin-arm64@0.34.3': - resolution: {integrity: sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==} + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.34.3': - resolution: {integrity: sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==} + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.2.0': - resolution: {integrity: sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==} + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.2.0': - resolution: {integrity: sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==} + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.2.0': - resolution: {integrity: sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==} + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linux-arm@1.2.0': - resolution: {integrity: sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==} + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] - '@img/sharp-libvips-linux-ppc64@1.2.0': - resolution: {integrity: sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==} + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} cpu: [ppc64] os: [linux] - '@img/sharp-libvips-linux-s390x@1.2.0': - resolution: {integrity: sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==} + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] - '@img/sharp-libvips-linux-x64@1.2.0': - resolution: {integrity: sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==} + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] - '@img/sharp-libvips-linuxmusl-arm64@1.2.0': - resolution: {integrity: sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==} + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linuxmusl-x64@1.2.0': - resolution: {integrity: sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==} + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] - '@img/sharp-linux-arm64@0.34.3': - resolution: {integrity: sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==} + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linux-arm@0.34.3': - resolution: {integrity: sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==} + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - '@img/sharp-linux-ppc64@0.34.3': - resolution: {integrity: sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==} + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] - '@img/sharp-linux-s390x@0.34.3': - resolution: {integrity: sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==} + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - '@img/sharp-linux-x64@0.34.3': - resolution: {integrity: sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==} + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-linuxmusl-arm64@0.34.3': - resolution: {integrity: sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==} + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linuxmusl-x64@0.34.3': - resolution: {integrity: sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==} + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-wasm32@0.34.3': - resolution: {integrity: sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==} + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [wasm32] - '@img/sharp-win32-arm64@0.34.3': - resolution: {integrity: sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==} + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [win32] - '@img/sharp-win32-ia32@0.34.3': - resolution: {integrity: sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==} + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.34.3': - resolution: {integrity: sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==} + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [win32] - '@inquirer/ansi@1.0.1': - resolution: {integrity: sha512-yqq0aJW/5XPhi5xOAL1xRCpe1eh8UFVgYFpFsjEqmIR8rKLyP+HINvFXwUaxYICflJrVlxnp7lLN6As735kVpw==} + '@inquirer/ansi@1.0.2': + resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==} engines: {node: '>=18'} - '@inquirer/confirm@5.1.19': - resolution: {integrity: sha512-wQNz9cfcxrtEnUyG5PndC8g3gZ7lGDBzmWiXZkX8ot3vfZ+/BLjR8EvyGX4YzQLeVqtAlY/YScZpW7CW8qMoDQ==} + '@inquirer/confirm@5.1.21': + resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -1530,8 +1379,8 @@ packages: '@types/node': optional: true - '@inquirer/core@10.3.0': - resolution: {integrity: sha512-Uv2aPPPSK5jeCplQmQ9xadnFx2Zhj9b5Dj7bU6ZeCdDNNY11nhYy4btcSdtDguHqCT2h5oNeQTcUNSGGLA7NTA==} + '@inquirer/core@10.3.2': + resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -1539,12 +1388,12 @@ packages: '@types/node': optional: true - '@inquirer/figures@1.0.14': - resolution: {integrity: sha512-DbFgdt+9/OZYFM+19dbpXOSeAstPy884FPy1KjDu4anWwymZeOYhMY1mdFri172htv6mvc/uvIAAi7b7tvjJBQ==} + '@inquirer/figures@1.0.15': + resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==} engines: {node: '>=18'} - '@inquirer/type@3.0.9': - resolution: {integrity: sha512-QPaNt/nmE2bLGQa9b7wwyRJoLZ7pN6rcyXvzU0YCmivmJyq1BVo94G98tStRWkoD1RgDX5C+dPlhhHzNdu/W/w==} + '@inquirer/type@3.0.10': + resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -1572,8 +1421,8 @@ packages: '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - '@jridgewell/trace-mapping@0.3.30': - resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==} + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} '@jsep-plugin/assignment@1.3.0': resolution: {integrity: sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==} @@ -1868,8 +1717,8 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' - '@opentelemetry/semantic-conventions@1.37.0': - resolution: {integrity: sha512-JD6DerIKdJGmRp4jQyX5FlrQjA4tjOw1cvfsPAZXfOOEErMUHjPcPSICS+6WnM0nB0efSFARh0KAZss+bvExOA==} + '@opentelemetry/semantic-conventions@1.38.0': + resolution: {integrity: sha512-kocjix+/sSggfJhwXqClZ3i9Y/MI0fp7b+g7kCRm6psy2dsf8uApTRclwG18h8Avm7C9+fnt+O36PspJ/OzoWg==} engines: {node: '>=14'} '@opentelemetry/sql-common@0.41.2': @@ -2245,6 +2094,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-primitive@2.1.4': + resolution: {integrity: sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-radio-group@1.3.8': resolution: {integrity: sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==} peerDependencies: @@ -2310,6 +2172,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-slider@1.3.6': + resolution: {integrity: sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-slot@1.2.3': resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} peerDependencies: @@ -2319,6 +2194,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-slot@1.2.4': + resolution: {integrity: sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-switch@1.2.6': resolution: {integrity: sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==} peerDependencies: @@ -2468,8 +2352,8 @@ packages: '@radix-ui/rect@1.1.1': resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} - '@reduxjs/toolkit@2.9.0': - resolution: {integrity: sha512-fSfQlSRu9Z5yBkvsNhYF2rPS8cGXn/TZVrlwN1948QyZ8xMZ0JvP50S2acZNaf+o63u6aEeMjipFyksjIcWrog==} + '@reduxjs/toolkit@2.11.2': + resolution: {integrity: sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==} peerDependencies: react: ^16.9.0 || ^17.0.0 || ^18 || ^19 react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 @@ -2479,24 +2363,24 @@ packages: react-redux: optional: true - '@rjsf/core@5.24.13': - resolution: {integrity: sha512-ONTr14s7LFIjx2VRFLuOpagL76sM/HPy6/OhdBfq6UukINmTIs6+aFN0GgcR0aXQHFDXQ7f/fel0o/SO05Htdg==} - engines: {node: '>=14'} + '@rjsf/core@6.1.2': + resolution: {integrity: sha512-fcEO6kArMcVIzTBoBxNStqxzAL417NDw049nmNx11pIcMwUnU5sAkSW18c8kgZOT6v1xaZhQrY+X5cBzzHy9+g==} + engines: {node: '>=20'} peerDependencies: - '@rjsf/utils': ^5.24.x - react: ^16.14.0 || >=17 + '@rjsf/utils': ^6.x + react: '>=18' - '@rjsf/utils@5.24.13': - resolution: {integrity: sha512-rNF8tDxIwTtXzz5O/U23QU73nlhgQNYJ+Sv5BAwQOIyhIE2Z3S5tUiSVMwZHt0julkv/Ryfwi+qsD4FiE5rOuw==} - engines: {node: '>=14'} + '@rjsf/utils@6.1.2': + resolution: {integrity: sha512-Px3FIkE1KK0745Qng9v88RZ0O7hcLf/1JUu0j00g+r6C8Zyokna42Hz/5TKyyQSKJqgVYcj2Z47YroVLenUM3A==} + engines: {node: '>=20'} peerDependencies: - react: ^16.14.0 || >=17 + react: '>=18' - '@rjsf/validator-ajv8@5.24.13': - resolution: {integrity: sha512-oWHP7YK581M8I5cF1t+UXFavnv+bhcqjtL1a7MG/Kaffi0EwhgcYjODrD8SsnrhncsEYMqSECr4ZOEoirnEUWw==} - engines: {node: '>=14'} + '@rjsf/validator-ajv8@6.1.2': + resolution: {integrity: sha512-9P3np2d+TaZcFTEFLocbj19fqrAWB/bxtY0Y8EjP8Oiz8LL+/wUITaN3Wx9uxzWerJyphfpZXWhUS9XkllDLig==} + engines: {node: '>=20'} peerDependencies: - '@rjsf/utils': ^5.24.x + '@rjsf/utils': ^6.x '@rollup/plugin-commonjs@28.0.1': resolution: {integrity: sha512-+tNWdlWKbpB3WgBN7ijjYkq9X5uhjmcvyjEght4NmH5fAU++zfQzAJ6wumLS+dNcvwEZhKx2Z+skY8m7v0wGSA==} @@ -2516,113 +2400,128 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.52.2': - resolution: {integrity: sha512-o3pcKzJgSGt4d74lSZ+OCnHwkKBeAbFDmbEm5gg70eA8VkyCuC/zV9TwBnmw6VjDlRdF4Pshfb+WE9E6XY1PoQ==} + '@rollup/rollup-android-arm-eabi@4.55.1': + resolution: {integrity: sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.52.2': - resolution: {integrity: sha512-cqFSWO5tX2vhC9hJTK8WAiPIm4Q8q/cU8j2HQA0L3E1uXvBYbOZMhE2oFL8n2pKB5sOCHY6bBuHaRwG7TkfJyw==} + '@rollup/rollup-android-arm64@4.55.1': + resolution: {integrity: sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.52.2': - resolution: {integrity: sha512-vngduywkkv8Fkh3wIZf5nFPXzWsNsVu1kvtLETWxTFf/5opZmflgVSeLgdHR56RQh71xhPhWoOkEBvbehwTlVA==} + '@rollup/rollup-darwin-arm64@4.55.1': + resolution: {integrity: sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.52.2': - resolution: {integrity: sha512-h11KikYrUCYTrDj6h939hhMNlqU2fo/X4NB0OZcys3fya49o1hmFaczAiJWVAFgrM1NCP6RrO7lQKeVYSKBPSQ==} + '@rollup/rollup-darwin-x64@4.55.1': + resolution: {integrity: sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.52.2': - resolution: {integrity: sha512-/eg4CI61ZUkLXxMHyVlmlGrSQZ34xqWlZNW43IAU4RmdzWEx0mQJ2mN/Cx4IHLVZFL6UBGAh+/GXhgvGb+nVxw==} + '@rollup/rollup-freebsd-arm64@4.55.1': + resolution: {integrity: sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.52.2': - resolution: {integrity: sha512-QOWgFH5X9+p+S1NAfOqc0z8qEpJIoUHf7OWjNUGOeW18Mx22lAUOiA9b6r2/vpzLdfxi/f+VWsYjUOMCcYh0Ng==} + '@rollup/rollup-freebsd-x64@4.55.1': + resolution: {integrity: sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.52.2': - resolution: {integrity: sha512-kDWSPafToDd8LcBYd1t5jw7bD5Ojcu12S3uT372e5HKPzQt532vW+rGFFOaiR0opxePyUkHrwz8iWYEyH1IIQA==} + '@rollup/rollup-linux-arm-gnueabihf@4.55.1': + resolution: {integrity: sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.52.2': - resolution: {integrity: sha512-gKm7Mk9wCv6/rkzwCiUC4KnevYhlf8ztBrDRT9g/u//1fZLapSRc+eDZj2Eu2wpJ+0RzUKgtNijnVIB4ZxyL+w==} + '@rollup/rollup-linux-arm-musleabihf@4.55.1': + resolution: {integrity: sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.52.2': - resolution: {integrity: sha512-66lA8vnj5mB/rtDNwPgrrKUOtCLVQypkyDa2gMfOefXK6rcZAxKLO9Fy3GkW8VkPnENv9hBkNOFfGLf6rNKGUg==} + '@rollup/rollup-linux-arm64-gnu@4.55.1': + resolution: {integrity: sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.52.2': - resolution: {integrity: sha512-s+OPucLNdJHvuZHuIz2WwncJ+SfWHFEmlC5nKMUgAelUeBUnlB4wt7rXWiyG4Zn07uY2Dd+SGyVa9oyLkVGOjA==} + '@rollup/rollup-linux-arm64-musl@4.55.1': + resolution: {integrity: sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loong64-gnu@4.52.2': - resolution: {integrity: sha512-8wTRM3+gVMDLLDdaT6tKmOE3lJyRy9NpJUS/ZRWmLCmOPIJhVyXwjBo+XbrrwtV33Em1/eCTd5TuGJm4+DmYjw==} + '@rollup/rollup-linux-loong64-gnu@4.55.1': + resolution: {integrity: sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-ppc64-gnu@4.52.2': - resolution: {integrity: sha512-6yqEfgJ1anIeuP2P/zhtfBlDpXUb80t8DpbYwXQ3bQd95JMvUaqiX+fKqYqUwZXqdJDd8xdilNtsHM2N0cFm6A==} + '@rollup/rollup-linux-loong64-musl@4.55.1': + resolution: {integrity: sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.55.1': + resolution: {integrity: sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.52.2': - resolution: {integrity: sha512-sshYUiYVSEI2B6dp4jMncwxbrUqRdNApF2c3bhtLAU0qA8Lrri0p0NauOsTWh3yCCCDyBOjESHMExonp7Nzc0w==} + '@rollup/rollup-linux-ppc64-musl@4.55.1': + resolution: {integrity: sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.55.1': + resolution: {integrity: sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.52.2': - resolution: {integrity: sha512-duBLgd+3pqC4MMwBrKkFxaZerUxZcYApQVC5SdbF5/e/589GwVvlRUnyqMFbM8iUSb1BaoX/3fRL7hB9m2Pj8Q==} + '@rollup/rollup-linux-riscv64-musl@4.55.1': + resolution: {integrity: sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.52.2': - resolution: {integrity: sha512-tzhYJJidDUVGMgVyE+PmxENPHlvvqm1KILjjZhB8/xHYqAGeizh3GBGf9u6WdJpZrz1aCpIIHG0LgJgH9rVjHQ==} + '@rollup/rollup-linux-s390x-gnu@4.55.1': + resolution: {integrity: sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.52.2': - resolution: {integrity: sha512-opH8GSUuVcCSSyHHcl5hELrmnk4waZoVpgn/4FDao9iyE4WpQhyWJ5ryl5M3ocp4qkRuHfyXnGqg8M9oKCEKRA==} + '@rollup/rollup-linux-x64-gnu@4.55.1': + resolution: {integrity: sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.52.2': - resolution: {integrity: sha512-LSeBHnGli1pPKVJ79ZVJgeZWWZXkEe/5o8kcn23M8eMKCUANejchJbF/JqzM4RRjOJfNRhKJk8FuqL1GKjF5oQ==} + '@rollup/rollup-linux-x64-musl@4.55.1': + resolution: {integrity: sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==} cpu: [x64] os: [linux] - '@rollup/rollup-openharmony-arm64@4.52.2': - resolution: {integrity: sha512-uPj7MQ6/s+/GOpolavm6BPo+6CbhbKYyZHUDvZ/SmJM7pfDBgdGisFX3bY/CBDMg2ZO4utfhlApkSfZ92yXw7Q==} + '@rollup/rollup-openbsd-x64@4.55.1': + resolution: {integrity: sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.55.1': + resolution: {integrity: sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.52.2': - resolution: {integrity: sha512-Z9MUCrSgIaUeeHAiNkm3cQyst2UhzjPraR3gYYfOjAuZI7tcFRTOD+4cHLPoS/3qinchth+V56vtqz1Tv+6KPA==} + '@rollup/rollup-win32-arm64-msvc@4.55.1': + resolution: {integrity: sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.52.2': - resolution: {integrity: sha512-+GnYBmpjldD3XQd+HMejo+0gJGwYIOfFeoBQv32xF/RUIvccUz20/V6Otdv+57NE70D5pa8W/jVGDoGq0oON4A==} + '@rollup/rollup-win32-ia32-msvc@4.55.1': + resolution: {integrity: sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.52.2': - resolution: {integrity: sha512-ApXFKluSB6kDQkAqZOKXBjiaqdF1BlKi+/eqnYe9Ee7U2K3pUDKsIyr8EYm/QDHTJIM+4X+lI0gJc3TTRhd+dA==} + '@rollup/rollup-win32-x64-gnu@4.55.1': + resolution: {integrity: sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.52.2': - resolution: {integrity: sha512-ARz+Bs8kY6FtitYM96PqPEVvPXqEZmPZsSkXvyX19YzDqkCaIlhCieLLMI5hxO9SRZ2XtCtm8wxhy0iJ2jxNfw==} + '@rollup/rollup-win32-x64-msvc@4.55.1': + resolution: {integrity: sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==} cpu: [x64] os: [win32] @@ -2651,10 +2550,6 @@ packages: resolution: {integrity: sha512-tKSzHq1hNzB619Ssrqo25cqdQJ84R3xSSLsUWEnkGO/wcXJvpZy94gwdoS+KmH18BB1iRRRGtnMxZcUkiPSesw==} engines: {node: '>=18'} - '@sentry/babel-plugin-component-annotate@4.3.0': - resolution: {integrity: sha512-OuxqBprXRyhe8Pkfyz/4yHQJc5c3lm+TmYWSSx8u48g5yKewSQDOxkiLU5pAk3WnbLPy8XwU/PN+2BG0YFU9Nw==} - engines: {node: '>= 14'} - '@sentry/babel-plugin-component-annotate@4.6.1': resolution: {integrity: sha512-aSIk0vgBqv7PhX6/Eov+vlI4puCE0bRXzUG5HdCsHBpAfeMkI8Hva6kSOusnzKqs8bf04hU7s3Sf0XxGTj/1AA==} engines: {node: '>= 14'} @@ -2663,115 +2558,59 @@ packages: resolution: {integrity: sha512-G8q362DdKp9y1b5qkQEmhTFzyWTOVB0ps1rflok0N6bVA75IEmSDX1pqJsNuY3qy14VsVHYVwQBJQsNltQLS0g==} engines: {node: '>=18'} - '@sentry/bundler-plugin-core@4.3.0': - resolution: {integrity: sha512-dmR4DJhJ4jqVWGWppuTL2blNFqOZZnt4aLkewbD1myFG3KVfUx8CrMQWEmGjkgPOtj5TO6xH9PyTJjXC6o5tnA==} - engines: {node: '>= 14'} - '@sentry/bundler-plugin-core@4.6.1': resolution: {integrity: sha512-WPeRbnMXm927m4Kr69NTArPfI+p5/34FHftdCRI3LFPMyhZDzz6J3wLy4hzaVUgmMf10eLzmq2HGEMvpQmdynA==} engines: {node: '>= 14'} - '@sentry/cli-darwin@2.55.0': - resolution: {integrity: sha512-jGHE7SHHzqXUmnsmRLgorVH6nmMmTjQQXdPZbSL5tRtH8d3OIYrVNr5D72DSgD26XAPBDMV0ibqOQ9NKoiSpfA==} + '@sentry/cli-darwin@2.58.4': + resolution: {integrity: sha512-kbTD+P4X8O+nsNwPxCywtj3q22ecyRHWff98rdcmtRrvwz8CKi/T4Jxn/fnn2i4VEchy08OWBuZAqaA5Kh2hRQ==} engines: {node: '>=10'} os: [darwin] - '@sentry/cli-darwin@2.58.2': - resolution: {integrity: sha512-MArsb3zLhA2/cbd4rTm09SmTpnEuZCoZOpuZYkrpDw1qzBVJmRFA1W1hGAQ9puzBIk/ubY3EUhhzuU3zN2uD6w==} - engines: {node: '>=10'} - os: [darwin] - - '@sentry/cli-linux-arm64@2.55.0': - resolution: {integrity: sha512-jNB/0/gFcOuDCaY/TqeuEpsy/k52dwyk1SOV3s1ku4DUsln6govTppeAGRewY3T1Rj9B2vgIWTrnB8KVh9+Rgg==} + '@sentry/cli-linux-arm64@2.58.4': + resolution: {integrity: sha512-0g0KwsOozkLtzN8/0+oMZoOuQ0o7W6O+hx+ydVU1bktaMGKEJLMAWxOQNjsh1TcBbNIXVOKM/I8l0ROhaAb8Ig==} engines: {node: '>=10'} cpu: [arm64] os: [linux, freebsd, android] - '@sentry/cli-linux-arm64@2.58.2': - resolution: {integrity: sha512-ay3OeObnbbPrt45cjeUyQjsx5ain1laj1tRszWj37NkKu55NZSp4QCg1gGBZ0gBGhckI9nInEsmKtix00alw2g==} - engines: {node: '>=10'} - cpu: [arm64] - os: [linux, freebsd, android] - - '@sentry/cli-linux-arm@2.55.0': - resolution: {integrity: sha512-ATjU0PsiWADSPLF/kZroLZ7FPKd5W9TDWHVkKNwIUNTei702LFgTjNeRwOIzTgSvG3yTmVEqtwFQfFN/7hnVXQ==} + '@sentry/cli-linux-arm@2.58.4': + resolution: {integrity: sha512-rdQ8beTwnN48hv7iV7e7ZKucPec5NJkRdrrycMJMZlzGBPi56LqnclgsHySJ6Kfq506A2MNuQnKGaf/sBC9REA==} engines: {node: '>=10'} cpu: [arm] os: [linux, freebsd, android] - '@sentry/cli-linux-arm@2.58.2': - resolution: {integrity: sha512-HU9lTCzcHqCz/7Mt5n+cv+nFuJdc1hGD2h35Uo92GgxX3/IujNvOUfF+nMX9j6BXH6hUt73R5c0Ycq9+a3Parg==} - engines: {node: '>=10'} - cpu: [arm] - os: [linux, freebsd, android] - - '@sentry/cli-linux-i686@2.55.0': - resolution: {integrity: sha512-8LZjo6PncTM6bWdaggscNOi5r7F/fqRREsCwvd51dcjGj7Kp1plqo9feEzYQ+jq+KUzVCiWfHrUjddFmYyZJrg==} + '@sentry/cli-linux-i686@2.58.4': + resolution: {integrity: sha512-NseoIQAFtkziHyjZNPTu1Gm1opeQHt7Wm1LbLrGWVIRvUOzlslO9/8i6wETUZ6TjlQxBVRgd3Q0lRBG2A8rFYA==} engines: {node: '>=10'} cpu: [x86, ia32] os: [linux, freebsd, android] - '@sentry/cli-linux-i686@2.58.2': - resolution: {integrity: sha512-CN9p0nfDFsAT1tTGBbzOUGkIllwS3hygOUyTK7LIm9z+UHw5uNgNVqdM/3Vg+02ymjkjISNB3/+mqEM5osGXdA==} - engines: {node: '>=10'} - cpu: [x86, ia32] - os: [linux, freebsd, android] - - '@sentry/cli-linux-x64@2.55.0': - resolution: {integrity: sha512-5LUVvq74Yj2cZZy5g5o/54dcWEaX4rf3myTHy73AKhRj1PABtOkfexOLbF9xSrZy95WXWaXyeH+k5n5z/vtHfA==} + '@sentry/cli-linux-x64@2.58.4': + resolution: {integrity: sha512-d3Arz+OO/wJYTqCYlSN3Ktm+W8rynQ/IMtSZLK8nu0ryh5mJOh+9XlXY6oDXw4YlsM8qCRrNquR8iEI1Y/IH+Q==} engines: {node: '>=10'} cpu: [x64] os: [linux, freebsd, android] - '@sentry/cli-linux-x64@2.58.2': - resolution: {integrity: sha512-oX/LLfvWaJO50oBVOn4ZvG2SDWPq0MN8SV9eg5tt2nviq+Ryltfr7Rtoo+HfV+eyOlx1/ZXhq9Wm7OT3cQuz+A==} - engines: {node: '>=10'} - cpu: [x64] - os: [linux, freebsd, android] - - '@sentry/cli-win32-arm64@2.55.0': - resolution: {integrity: sha512-cWIQdzm1pfLwPARsV6dUb8TVd6Y3V1A2VWxjTons3Ift6GvtVmiAe0OWL8t2Yt95i8v61kTD/6Tq21OAaogqzA==} + '@sentry/cli-win32-arm64@2.58.4': + resolution: {integrity: sha512-bqYrF43+jXdDBh0f8HIJU3tbvlOFtGyRjHB8AoRuMQv9TEDUfENZyCelhdjA+KwDKYl48R1Yasb4EHNzsoO83w==} engines: {node: '>=10'} cpu: [arm64] os: [win32] - '@sentry/cli-win32-arm64@2.58.2': - resolution: {integrity: sha512-+cl3x2HPVMpoSVGVM1IDWlAEREZrrVQj4xBb0TRKII7g3hUxRsAIcsrr7+tSkie++0FuH4go/b5fGAv51OEF3w==} - engines: {node: '>=10'} - cpu: [arm64] - os: [win32] - - '@sentry/cli-win32-i686@2.55.0': - resolution: {integrity: sha512-ldepCn2t9r4I0wvgk7NRaA7coJyy4rTQAzM66u9j5nTEsUldf66xym6esd5ZZRAaJUjffqvHqUIr/lrieTIrVg==} + '@sentry/cli-win32-i686@2.58.4': + resolution: {integrity: sha512-3triFD6jyvhVcXOmGyttf+deKZcC1tURdhnmDUIBkiDPJKGT/N5xa4qAtHJlAB/h8L9jgYih9bvJnvvFVM7yug==} engines: {node: '>=10'} cpu: [x86, ia32] os: [win32] - '@sentry/cli-win32-i686@2.58.2': - resolution: {integrity: sha512-omFVr0FhzJ8oTJSg1Kf+gjLgzpYklY0XPfLxZ5iiMiYUKwF5uo1RJRdkUOiEAv0IqpUKnmKcmVCLaDxsWclB7Q==} - engines: {node: '>=10'} - cpu: [x86, ia32] - os: [win32] - - '@sentry/cli-win32-x64@2.55.0': - resolution: {integrity: sha512-4hPc/I/9tXx+HLTdTGwlagtAfDSIa2AoTUP30tl32NAYQhx9a6niUbPAemK2qfxesiufJ7D2djX83rCw6WnJVA==} + '@sentry/cli-win32-x64@2.58.4': + resolution: {integrity: sha512-cSzN4PjM1RsCZ4pxMjI0VI7yNCkxiJ5jmWncyiwHXGiXrV1eXYdQ3n1LhUYLZ91CafyprR0OhDcE+RVZ26Qb5w==} engines: {node: '>=10'} cpu: [x64] os: [win32] - '@sentry/cli-win32-x64@2.58.2': - resolution: {integrity: sha512-2NAFs9UxVbRztQbgJSP5i8TB9eJQ7xraciwj/93djrSMHSEbJ0vC47TME0iifgvhlHMs5vqETOKJtfbbpQAQFA==} - engines: {node: '>=10'} - cpu: [x64] - os: [win32] - - '@sentry/cli@2.55.0': - resolution: {integrity: sha512-cynvcIM2xL8ddwELyFRSpZQw4UtFZzoM2rId2l9vg7+wDREPDocMJB9lEQpBIo3eqhp9JswqUT037yjO6iJ5Sw==} - engines: {node: '>= 10'} - hasBin: true - - '@sentry/cli@2.58.2': - resolution: {integrity: sha512-U4u62V4vaTWF+o40Mih8aOpQKqKUbZQt9A3LorIJwaE3tO3XFLRI70eWtW2se1Qmy0RZ74zB14nYcFNFl2t4Rw==} + '@sentry/cli@2.58.4': + resolution: {integrity: sha512-ArDrpuS8JtDYEvwGleVE+FgR+qHaOp77IgdGSacz6SZy6Lv90uX0Nu4UrHCQJz8/xwIcNxSqnN22lq0dH4IqTg==} engines: {node: '>= 10'} hasBin: true @@ -2821,23 +2660,23 @@ packages: resolution: {integrity: sha512-uBfpOnzSNSd2ITMTMeX5bV9Jlci9iMyI+iOPuW8c3oc+0dITTN0OpKLyNd6nfm50bM5h/1qFVQrph+oFTrtuGQ==} engines: {node: '>=18'} - '@sentry/webpack-plugin@4.3.0': - resolution: {integrity: sha512-K4nU1SheK/tvyakBws2zfd+MN6hzmpW+wPTbSbDWn1+WL9+g9hsPh8hjFFiVe47AhhUoUZ3YgiH2HyeHXjHflA==} + '@sentry/webpack-plugin@4.6.1': + resolution: {integrity: sha512-CJgT/t2pQWsPsMx9VJ86goU/orCQhL2HhDj5ZYBol6fPPoEGeTqKOPCnv/xsbCAfGSp1uHpyRLTA/Gx96u7VVA==} engines: {node: '>= 14'} peerDependencies: webpack: '>=4.40.0' - '@shikijs/engine-oniguruma@3.14.0': - resolution: {integrity: sha512-TNcYTYMbJyy+ZjzWtt0bG5y4YyMIWC2nyePz+CFMWqm+HnZZyy9SWMgo8Z6KBJVIZnx8XUXS8U2afO6Y0g1Oug==} + '@shikijs/engine-oniguruma@3.21.0': + resolution: {integrity: sha512-OYknTCct6qiwpQDqDdf3iedRdzj6hFlOPv5hMvI+hkWfCKs5mlJ4TXziBG9nyabLwGulrUjHiCq3xCspSzErYQ==} - '@shikijs/langs@3.14.0': - resolution: {integrity: sha512-DIB2EQY7yPX1/ZH7lMcwrK5pl+ZkP/xoSpUzg9YC8R+evRCCiSQ7yyrvEyBsMnfZq4eBzLzBlugMyTAf13+pzg==} + '@shikijs/langs@3.21.0': + resolution: {integrity: sha512-g6mn5m+Y6GBJ4wxmBYqalK9Sp0CFkUqfNzUy2pJglUginz6ZpWbaWjDB4fbQ/8SHzFjYbtU6Ddlp1pc+PPNDVA==} - '@shikijs/themes@3.14.0': - resolution: {integrity: sha512-fAo/OnfWckNmv4uBoUu6dSlkcBc+SA1xzj5oUSaz5z3KqHtEbUypg/9xxgJARtM6+7RVm0Q6Xnty41xA1ma1IA==} + '@shikijs/themes@3.21.0': + resolution: {integrity: sha512-BAE4cr9EDiZyYzwIHEk7JTBJ9CzlPuM4PchfcA5ao1dWXb25nv6hYsoDiBq2aZK9E3dlt3WB78uI96UESD+8Mw==} - '@shikijs/types@3.14.0': - resolution: {integrity: sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ==} + '@shikijs/types@3.21.0': + resolution: {integrity: sha512-zGrWOxZ0/+0ovPY7PvBU2gIS9tmhSUUt30jAcNV0Bq0gb2S98gwfjIs1vxlmH5zM7/4YxLamT6ChlqqAJmPPjA==} '@shikijs/vscode-textmate@10.0.2': resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} @@ -2845,6 +2684,9 @@ packages: '@standard-schema/spec@1.0.0': resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@standard-schema/utils@0.3.0': resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} @@ -2967,8 +2809,8 @@ packages: '@storybook/global@5.0.0': resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==} - '@storybook/icons@1.4.0': - resolution: {integrity: sha512-Td73IeJxOyalzvjQL+JXx72jlIYHgs+REaHiREOqfpo3A2AYYG71AUbcv+lg7mEDIweKVCxsMQ0UKo634c8XeA==} + '@storybook/icons@1.6.0': + resolution: {integrity: sha512-hcFZIjW8yQz8O8//2WTIXylm5Xsgc+lW9ISLgUk1xGmptIJQRdlhVIXCpSyLrQaaRiyhQRaVg7l3BD9S216BHw==} engines: {node: '>=14.0.0'} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta @@ -3094,8 +2936,8 @@ packages: resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} engines: {node: '>=18'} - '@testing-library/jest-dom@6.8.0': - resolution: {integrity: sha512-WgXcWzVM6idy5JaftTVC8Vs83NKRmGJz4Hqs4oyOuO2J4r/y79vvKZsb+CaGyCSEbUPI6OsewfPd0G1A0/TUZQ==} + '@testing-library/jest-dom@6.9.1': + resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==} engines: {node: '>=14', npm: '>=6', yarn: '>=1'} '@testing-library/user-event@14.6.1': @@ -3125,14 +2967,14 @@ packages: '@types/canvas-confetti@1.9.0': resolution: {integrity: sha512-aBGj/dULrimR1XDZLtG9JwxX1b4HPRF6CX9Yfwh3NvstZEm1ZL7RBnel4keCPSqs1ANRu1u2Aoz9R+VmtjYuTg==} - '@types/chai@5.2.2': - resolution: {integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==} + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} '@types/connect@3.4.38': resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} - '@types/d3-array@3.2.1': - resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==} + '@types/d3-array@3.2.2': + resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} '@types/d3-color@3.1.3': resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} @@ -3245,8 +3087,8 @@ packages: '@types/pg@8.15.6': resolution: {integrity: sha512-NoaMtzhxOrubeL/7UZuNTrejB4MPAJ0RpxZqXQf2qXuVlTPuG6Y8p4u9dKRaue4yjmC7ZhzVO2/Yyyn25znrPQ==} - '@types/phoenix@1.6.6': - resolution: {integrity: sha512-PIzZZlEppgrpoT2QgbnDU+MMzuR6BbCjllj0bM70lWoejMeNJAxCchxnv7J3XFkI8MpygtRpzXrIlmWUBclP5A==} + '@types/phoenix@1.6.7': + resolution: {integrity: sha512-oN9ive//QSBkf19rfDv45M7eZPi0eEXylht2OLEXicu5b4KoQ1OzXIw+xDSGWxSxe1JmepRR/ZH283vsu518/Q==} '@types/prop-types@15.7.15': resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} @@ -3274,9 +3116,6 @@ packages: '@types/statuses@2.0.6': resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==} - '@types/stylis@4.2.5': - resolution: {integrity: sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==} - '@types/tedious@4.0.14': resolution: {integrity: sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw==} @@ -3295,137 +3134,63 @@ packages: '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} - '@typescript-eslint/eslint-plugin@8.48.1': - resolution: {integrity: sha512-X63hI1bxl5ohelzr0LY5coufyl0LJNthld+abwxpCoo6Gq+hSqhKwci7MUWkXo67mzgUK6YFByhmaHmUcuBJmA==} + '@typescript-eslint/eslint-plugin@8.52.0': + resolution: {integrity: sha512-okqtOgqu2qmZJ5iN4TWlgfF171dZmx2FzdOv2K/ixL2LZWDStL8+JgQerI2sa8eAEfoydG9+0V96m7V+P8yE1Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.48.1 + '@typescript-eslint/parser': ^8.52.0 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.48.1': - resolution: {integrity: sha512-PC0PDZfJg8sP7cmKe6L3QIL8GZwU5aRvUFedqSIpw3B+QjRSUZeeITC2M5XKeMXEzL6wccN196iy3JLwKNvDVA==} + '@typescript-eslint/parser@8.52.0': + resolution: {integrity: sha512-iIACsx8pxRnguSYhHiMn2PvhvfpopO9FXHyn1mG5txZIsAaB6F0KwbFnUQN3KCiG3Jcuad/Cao2FAs1Wp7vAyg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.43.0': - resolution: {integrity: sha512-htB/+D/BIGoNTQYffZw4uM4NzzuolCoaA/BusuSIcC8YjmBYQioew5VUZAYdAETPjeed0hqCaW7EHg+Robq8uw==} + '@typescript-eslint/project-service@8.52.0': + resolution: {integrity: sha512-xD0MfdSdEmeFa3OmVqonHi+Cciab96ls1UhIF/qX/O/gPu5KXD0bY9lu33jj04fjzrXHcuvjBcBC+D3SNSadaw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.46.2': - resolution: {integrity: sha512-PULOLZ9iqwI7hXcmL4fVfIsBi6AN9YxRc0frbvmg8f+4hQAjQ5GYNKK0DIArNo+rOKmR/iBYwkpBmnIwin4wBg==} + '@typescript-eslint/scope-manager@8.52.0': + resolution: {integrity: sha512-ixxqmmCcc1Nf8S0mS0TkJ/3LKcC8mruYJPOU6Ia2F/zUUR4pApW7LzrpU3JmtePbRUTes9bEqRc1Gg4iyRnDzA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.52.0': + resolution: {integrity: sha512-jl+8fzr/SdzdxWJznq5nvoI7qn2tNYV/ZBAEcaFMVXf+K6jmXvAFrgo/+5rxgnL152f//pDEAYAhhBAZGrVfwg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.48.1': - resolution: {integrity: sha512-HQWSicah4s9z2/HifRPQ6b6R7G+SBx64JlFQpgSSHWPKdvCZX57XCbszg/bapbRsOEv42q5tayTYcEFpACcX1w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/scope-manager@8.43.0': - resolution: {integrity: sha512-daSWlQ87ZhsjrbMLvpuuMAt3y4ba57AuvadcR7f3nl8eS3BjRc8L9VLxFLk92RL5xdXOg6IQ+qKjjqNEimGuAg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/scope-manager@8.46.2': - resolution: {integrity: sha512-LF4b/NmGvdWEHD2H4MsHD8ny6JpiVNDzrSZr3CsckEgCbAGZbYM4Cqxvi9L+WqDMT+51Ozy7lt2M+d0JLEuBqA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/scope-manager@8.48.1': - resolution: {integrity: sha512-rj4vWQsytQbLxC5Bf4XwZ0/CKd362DkWMUkviT7DCS057SK64D5lH74sSGzhI6PDD2HCEq02xAP9cX68dYyg1w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/tsconfig-utils@8.43.0': - resolution: {integrity: sha512-ALC2prjZcj2YqqL5X/bwWQmHA2em6/94GcbB/KKu5SX3EBDOsqztmmX1kMkvAJHzxk7TazKzJfFiEIagNV3qEA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/tsconfig-utils@8.46.2': - resolution: {integrity: sha512-a7QH6fw4S57+F5y2FIxxSDyi5M4UfGF+Jl1bCGd7+L4KsaUY80GsiF/t0UoRFDHAguKlBaACWJRmdrc6Xfkkag==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/tsconfig-utils@8.48.1': - resolution: {integrity: sha512-k0Jhs4CpEffIBm6wPaCXBAD7jxBtrHjrSgtfCjUvPp9AZ78lXKdTR8fxyZO5y4vWNlOvYXRtngSZNSn+H53Jkw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/type-utils@8.48.1': - resolution: {integrity: sha512-1jEop81a3LrJQLTf/1VfPQdhIY4PlGDBc/i67EVWObrtvcziysbLN3oReexHOM6N3jyXgCrkBsZpqwH0hiDOQg==} + '@typescript-eslint/type-utils@8.52.0': + resolution: {integrity: sha512-JD3wKBRWglYRQkAtsyGz1AewDu3mTc7NtRjR/ceTyGoPqmdS5oCdx/oZMWD5Zuqmo6/MpsYs0wp6axNt88/2EQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.43.0': - resolution: {integrity: sha512-vQ2FZaxJpydjSZJKiSW/LJsabFFvV7KgLC5DiLhkBcykhQj8iK9BOaDmQt74nnKdLvceM5xmhaTF+pLekrxEkw==} + '@typescript-eslint/types@8.52.0': + resolution: {integrity: sha512-LWQV1V4q9V4cT4H5JCIx3481iIFxH1UkVk+ZkGGAV1ZGcjGI9IoFOfg3O6ywz8QqCDEp7Inlg6kovMofsNRaGg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/types@8.46.2': - resolution: {integrity: sha512-lNCWCbq7rpg7qDsQrd3D6NyWYu+gkTENkG5IKYhUIcxSb59SQC/hEQ+MrG4sTgBVghTonNWq42bA/d4yYumldQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/types@8.48.1': - resolution: {integrity: sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/typescript-estree@8.43.0': - resolution: {integrity: sha512-7Vv6zlAhPb+cvEpP06WXXy/ZByph9iL6BQRBDj4kmBsW98AqEeQHlj/13X+sZOrKSo9/rNKH4Ul4f6EICREFdw==} + '@typescript-eslint/typescript-estree@8.52.0': + resolution: {integrity: sha512-XP3LClsCc0FsTK5/frGjolyADTh3QmsLp6nKd476xNI9CsSsLnmn4f0jrzNoAulmxlmNIpeXuHYeEQv61Q6qeQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/typescript-estree@8.46.2': - resolution: {integrity: sha512-f7rW7LJ2b7Uh2EiQ+7sza6RDZnajbNbemn54Ob6fRwQbgcIn+GWfyuHDHRYgRoZu1P4AayVScrRW+YfbTvPQoQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/typescript-estree@8.48.1': - resolution: {integrity: sha512-/9wQ4PqaefTK6POVTjJaYS0bynCgzh6ClJHGSBj06XEHjkfylzB+A3qvyaXnErEZSaxhIo4YdyBgq6j4RysxDg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/utils@8.43.0': - resolution: {integrity: sha512-S1/tEmkUeeswxd0GGcnwuVQPFWo8NzZTOMxCvw8BX7OMxnNae+i8Tm7REQen/SwUIPoPqfKn7EaZ+YLpiB3k9g==} + '@typescript-eslint/utils@8.52.0': + resolution: {integrity: sha512-wYndVMWkweqHpEpwPhwqE2lnD2DxC6WVLupU/DOt/0/v+/+iQbbzO3jOHjmBMnhu0DgLULvOaU4h4pwHYi2oRQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.46.2': - resolution: {integrity: sha512-sExxzucx0Tud5tE0XqR0lT0psBQvEpnpiul9XbGUB1QwpWJJAps1O/Z7hJxLGiZLBKMCutjTzDgmd1muEhBnVg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/utils@8.48.1': - resolution: {integrity: sha512-fAnhLrDjiVfey5wwFRwrweyRlCmdz5ZxXz2G/4cLn0YDLjTapmN4gcCsTBR1N2rWnZSDeWpYtgLDsJt+FpmcwA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/visitor-keys@8.43.0': - resolution: {integrity: sha512-T+S1KqRD4sg/bHfLwrpF/K3gQLBM1n7Rp7OjjikjTEssI2YJzQpi5WXoynOaQ93ERIuq3O8RBTOUYDKszUCEHw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/visitor-keys@8.46.2': - resolution: {integrity: sha512-tUFMXI4gxzzMXt4xpGJEsBsTox0XbNQ1y94EwlD/CuZwFcQP79xfQqMhau9HsRc/J0cAPA/HZt1dZPtGn9V/7w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/visitor-keys@8.48.1': - resolution: {integrity: sha512-BmxxndzEWhE4TIEEMBs8lP3MBWN3jFPs/p6gPm/wkv02o41hI6cq9AuSmGAaTTHPtA1FTi2jBre4A9rm5ZmX+Q==} + '@typescript-eslint/visitor-keys@8.52.0': + resolution: {integrity: sha512-ink3/Zofus34nmBsPjow63FP5M7IGff0RKAgqR6+CFpdk22M7aLwC9gOcLGYqr7MczLPzZVERW9hRog3O4n1sQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@ungap/structured-clone@1.3.0': @@ -3643,6 +3408,9 @@ packages: '@webassemblyjs/wast-printer@1.14.1': resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + '@x0k/json-schema-merge@1.0.2': + resolution: {integrity: sha512-1734qiJHNX3+cJGDMMw2yz7R+7kpbAtl5NdPs1c/0gO5kYT6s4dMbLXiIfpZNsOYhGZI3aH7FWrj4Zxz7epXNg==} + '@xtuc/ieee754@1.2.0': resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} @@ -3851,12 +3619,8 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - axe-core@4.10.3: - resolution: {integrity: sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==} - engines: {node: '>=4'} - - axe-core@4.11.0: - resolution: {integrity: sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ==} + axe-core@4.11.1: + resolution: {integrity: sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==} engines: {node: '>=4'} axe-html-reporter@2.2.11: @@ -3905,6 +3669,10 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + baseline-browser-mapping@2.9.11: + resolution: {integrity: sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==} + hasBin: true + better-opn@3.0.2: resolution: {integrity: sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==} engines: {node: '>=12.0.0'} @@ -3954,15 +3722,15 @@ packages: resolution: {integrity: sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==} engines: {node: '>= 0.10'} - browserify-sign@4.2.3: - resolution: {integrity: sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==} - engines: {node: '>= 0.12'} + browserify-sign@4.2.5: + resolution: {integrity: sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==} + engines: {node: '>= 0.10'} browserify-zlib@0.2.0: resolution: {integrity: sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==} - browserslist@4.25.4: - resolution: {integrity: sha512-4jYpcjabC606xJ3kw2QwGEZKX0Aw7sgQdZCvIK9dhVSPh76BKo+C+btT1RRofH7B+8iNpEbgGNVWiLki5q93yg==} + browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -4004,11 +3772,8 @@ packages: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} - camelize@1.0.1: - resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==} - - caniuse-lite@1.0.30001741: - resolution: {integrity: sha512-QGUGitqsc8ARjLdgAfxETDhRbJ0REsP6O3I96TAth/mVjh2cYzN2u+3AzPP3aVSm2FehEItaJw1xd+IGBXWeSw==} + caniuse-lite@1.0.30001762: + resolution: {integrity: sha512-PxZwGNvH7Ak8WX5iXzoK1KPZttBXNPuaOvI2ZYU7NrlM+d9Ov+TUvlLOBNGzVXAntMSMMlJPd+jY6ovrVjSmUw==} case-sensitive-paths-webpack-plugin@2.4.0: resolution: {integrity: sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==} @@ -4037,8 +3802,8 @@ packages: character-reference-invalid@2.0.1: resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} - check-error@2.1.1: - resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + check-error@2.1.3: + resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} engines: {node: '>= 16'} chokidar@3.6.0: @@ -4122,13 +3887,6 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - color-string@1.9.1: - resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} - - color@4.2.3: - resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} - engines: {node: '>=12.5.0'} - colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} @@ -4159,12 +3917,6 @@ packages: compare-versions@6.1.1: resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==} - compute-gcd@1.2.1: - resolution: {integrity: sha512-TwMbxBNz0l71+8Sc4czv13h4kEqnchV9igQZBi6QUaz09dnz13juGnnaWWJTRsP3brxOoxeB4SA2WELLw1hCtg==} - - compute-lcm@1.1.2: - resolution: {integrity: sha512-OFNPdQAXnQhDSKioX8/XYT6sdUlXwpeMjfd6ApxMJfyZ4GxmLR1xvMERctlYhlHwIiz6CSpBc2+qYKjHGZw4TQ==} - concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -4189,11 +3941,11 @@ packages: resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} engines: {node: '>=18'} - core-js-compat@3.45.1: - resolution: {integrity: sha512-tqTt5T4PzsMIZ430XGviK4vzYSoeNJ6CXODi6c/voxOT6IZqBht5/EKaSNnYiEjjRYxjVz7DQIsOsY0XNi8PIA==} + core-js-compat@3.47.0: + resolution: {integrity: sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==} - core-js-pure@3.45.1: - resolution: {integrity: sha512-OHnWFKgTUshEU8MK+lOs1H8kC8GkTi9Z1tvNkxrCcw9wl3MJIO7q2ld77wjWn4/xuGrVu2X+nME1iIIPBSdyEQ==} + core-js-pure@3.47.0: + resolution: {integrity: sha512-BcxeDbzUrRnXGYIVAGFtcGQVNpFcUhVjr6W7F8XktvQW2iJP9e66GP6xdKotCRFlrxBvNIBrhwKteRXqMV86Nw==} core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} @@ -4233,10 +3985,6 @@ packages: resolution: {integrity: sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==} engines: {node: '>= 0.10'} - css-color-keywords@1.0.0: - resolution: {integrity: sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==} - engines: {node: '>=4'} - css-loader@6.11.0: resolution: {integrity: sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==} engines: {node: '>= 12.13.0'} @@ -4252,9 +4000,6 @@ packages: css-select@4.3.0: resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} - css-to-react-native@3.2.0: - resolution: {integrity: sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==} - css-what@6.2.2: resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} engines: {node: '>= 6'} @@ -4267,8 +4012,8 @@ packages: engines: {node: '>=4'} hasBin: true - csstype@3.1.3: - resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} d3-array@3.2.4: resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} @@ -4421,8 +4166,8 @@ packages: des.js@1.1.0: resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==} - detect-libc@2.0.4: - resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} detect-node-es@1.1.0: @@ -4499,8 +4244,8 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - electron-to-chromium@1.5.214: - resolution: {integrity: sha512-TpvUNdha+X3ybfU78NoQatKvQEm1oq3lf2QbnmCEdw+Bd9RuIAY+hJTvq1avzHM0f7EJfnH3vbCnbzKzisc/9Q==} + electron-to-chromium@1.5.267: + resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} elliptic@6.6.1: resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} @@ -4531,8 +4276,8 @@ packages: endent@2.1.0: resolution: {integrity: sha512-r8VyPX7XL8U01Xgnb1CjZ3XV+z90cXIJ9JPE/R9SEC9vpw2P6CfsRPJmp20DppC5N7ZAMCmjYkJIa744Iyg96w==} - enhanced-resolve@5.18.3: - resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} + enhanced-resolve@5.18.4: + resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==} engines: {node: '>=10.13.0'} enquirer@2.4.1: @@ -4554,14 +4299,14 @@ packages: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} - error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} error-stack-parser@2.1.4: resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} - es-abstract@1.24.0: - resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} + es-abstract@1.24.1: + resolution: {integrity: sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==} engines: {node: '>= 0.4'} es-aggregate-error@1.0.14: @@ -4576,13 +4321,16 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-iterator-helpers@1.2.1: - resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} + es-iterator-helpers@1.2.2: + resolution: {integrity: sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w==} 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'} @@ -4599,8 +4347,8 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} - es-toolkit@1.39.10: - resolution: {integrity: sha512-E0iGnTtbDhkeczB0T+mxmoVlT4YNweEKBLq7oaU4p11mecdsZpNWOglI4895Vh4usbQ+LsJiuLuI2L0Vdmfm2w==} + es-toolkit@1.43.0: + resolution: {integrity: sha512-SKCT8AsWvYzBBuUqMk4NPwFlSdqLpJwmy6AP322ERn8W2YLIB6JBXnwMI2Qsh2gfphT3q7EKAxKb23cvFHFwKA==} es6-promise@3.3.1: resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==} @@ -4610,13 +4358,8 @@ packages: peerDependencies: esbuild: '>=0.12 <1' - esbuild@0.25.11: - resolution: {integrity: sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==} - engines: {node: '>=18'} - hasBin: true - - esbuild@0.25.9: - resolution: {integrity: sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==} + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} engines: {node: '>=18'} hasBin: true @@ -4744,8 +4487,8 @@ packages: engines: {node: '>=4'} hasBin: true - esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} engines: {node: '>=0.10'} esrecurse@4.3.0: @@ -4826,11 +4569,11 @@ packages: fast-safe-stringify@2.1.1: resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} - fast-uri@3.0.6: - resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} - fastq@1.19.1: - resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} @@ -4930,8 +4673,8 @@ packages: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} - fs-extra@11.3.2: - resolution: {integrity: sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==} + fs-extra@11.3.3: + resolution: {integrity: sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==} engines: {node: '>=14.14'} fs-monkey@1.1.0: @@ -5014,10 +4757,6 @@ packages: glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - glob@10.4.5: - resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} - hasBin: true - glob@10.5.0: resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} hasBin: true @@ -5026,10 +4765,6 @@ packages: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported - glob@9.3.5: - resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==} - engines: {node: '>=16 || 14 >=14.17'} - globals@13.24.0: resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} engines: {node: '>=8'} @@ -5052,8 +4787,8 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - graphql@16.11.0: - resolution: {integrity: sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==} + graphql@16.12.0: + resolution: {integrity: sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} has-bigints@1.1.0: @@ -5158,8 +4893,8 @@ packages: html-url-attributes@3.0.1: resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==} - html-webpack-plugin@5.6.4: - resolution: {integrity: sha512-V/PZeWsqhfpE27nKeX9EO2sbR+D17A+tLf6qU+ht66jdUsN0QLKJN27Z+1+gHrVMKgndBahes0PU6rRihDgHTw==} + html-webpack-plugin@5.6.5: + resolution: {integrity: sha512-4xynFbKNNk+WlzXeQQ+6YYsH2g7mpfPszQZUi3ovKlj+pDmngQ7vRXjrrmGROabmKwyQkcgcX5hqfOwHbFmK5g==} engines: {node: '>=10.13.0'} peerDependencies: '@rspack/core': 0.x || 1.x @@ -5209,8 +4944,11 @@ packages: engines: {node: '>=16.x'} hasBin: true - immer@10.1.3: - resolution: {integrity: sha512-tmjF/k8QDKydUlm3mZU+tjM6zeq9/fFpPqH9SzWmBnVVKsPBg/V66qsMwb3/Bo90cgUN+ghdVBess+hPsxUyRw==} + immer@10.2.0: + resolution: {integrity: sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==} + + immer@11.1.3: + resolution: {integrity: sha512-6jQTc5z0KJFtr1UgFpIL3N9XSC3saRaI9PwWtzM2pSqkNGtiNkYY2OSwkOGDK2XcTRcLb1pi/aNkKZz0nxVH4Q==} immer@9.0.21: resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==} @@ -5219,8 +4957,8 @@ packages: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} - import-in-the-middle@2.0.0: - resolution: {integrity: sha512-yNZhyQYqXpkT0AKq3F3KLasUSK4fHvebNH5hOsKQw2dhGSALvQ4U0BqUc5suziKvydO5u5hgN2hy1RJaho8U5A==} + import-in-the-middle@2.0.1: + resolution: {integrity: sha512-bruMpJ7xz+9jwGzrwEhWgvRrlKRYCRDBrfU+ur3FcasYXLJDxTruJ//8g2Noj+QFyRBeqbpj8Bhn4Fbw6HjvhA==} imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} @@ -5240,8 +4978,8 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - inline-style-parser@0.2.4: - resolution: {integrity: sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==} + inline-style-parser@0.2.7: + resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} @@ -5268,9 +5006,6 @@ packages: is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - is-arrayish@0.3.2: - resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} - is-async-function@2.1.1: resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} engines: {node: '>= 0.4'} @@ -5326,10 +5061,6 @@ packages: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} - is-generator-function@1.1.0: - resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} - engines: {node: '>= 0.4'} - is-generator-function@1.1.2: resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} engines: {node: '>= 0.4'} @@ -5446,8 +5177,8 @@ packages: resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} hasBin: true - jiti@2.5.1: - resolution: {integrity: sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==} + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true js-tokens@4.0.0: @@ -5457,15 +5188,14 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + jsep@1.4.0: resolution: {integrity: sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==} engines: {node: '>= 10.16.0'} - jsesc@3.0.2: - resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} - engines: {node: '>=6'} - hasBin: true - jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -5477,13 +5207,6 @@ packages: json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - json-schema-compare@0.2.2: - resolution: {integrity: sha512-c4WYmDKyJXhs7WWvAWm3uIYnfyWFoIp+JEoX34rctVvEkMYCPGhXtvmFFXiffBbxfZsvQ0RNnV5H7GvDF5HCqQ==} - - json-schema-merge-allof@0.8.1: - resolution: {integrity: sha512-CTUKmIlPJbsWfzRRnOXz+0MjIqvnleIXwFTzz+t9T86HnYX/Rozria6ZVGLktAU9e+NygNljveP+yxqtQp/Q4w==} - engines: {node: '>=12.0.0'} - json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -5572,8 +5295,8 @@ packages: linkify-it@5.0.0: resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} - loader-runner@4.3.0: - resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} + loader-runner@4.3.1: + resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==} engines: {node: '>=6.11.5'} loader-utils@2.0.4: @@ -5596,8 +5319,8 @@ packages: resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - lodash-es@4.17.21: - resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + lodash-es@4.17.22: + resolution: {integrity: sha512-XEawp1t0gxSi9x01glktRZ5HDy0HXqrM0x5pXQM98EaI0NxO6jVM7omDOxsuEo5UIASAnm2bRp1Jt/e0a2XU8Q==} lodash.camelcase@4.3.0: resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} @@ -5670,8 +5393,8 @@ packages: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true - magic-string@0.30.19: - resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==} + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} magic-string@0.30.8: resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==} @@ -5688,11 +5411,14 @@ packages: markdown-table@3.0.4: resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} - markdown-to-jsx@7.7.13: - resolution: {integrity: sha512-DiueEq2bttFcSxUs85GJcQVrOr0+VVsPfj9AEUPqmExJ3f8P/iQNvZHltV4tm1XVhu1kl0vWBZWT3l99izRMaA==} + markdown-to-jsx@8.0.0: + resolution: {integrity: sha512-hWEaRxeCDjes1CVUQqU+Ov0mCqBqkGhLKjL98KdbwHSgEWZZSJQeGlJQatVfeZ3RaxrfTrZZ3eczl2dhp5c/pA==} engines: {node: '>= 10'} peerDependencies: react: '>= 0.14.0' + peerDependenciesMeta: + react: + optional: true math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} @@ -5740,8 +5466,8 @@ packages: mdast-util-phrasing@4.1.0: resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} - mdast-util-to-hast@13.2.0: - resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==} + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} mdast-util-to-markdown@2.1.2: resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} @@ -5890,10 +5616,6 @@ packages: resolution: {integrity: sha512-sauLxniAmvnhhRjFwPNnJKaPFYyddAgbYdeUpHULtCT/GhzdCx/MDNy+Y40lBxTQUrMzDE8e0S43Z5uqfO0REg==} engines: {node: '>=10'} - minimatch@8.0.4: - resolution: {integrity: sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==} - engines: {node: '>=16 || 14 >=14.17'} - minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} @@ -5901,10 +5623,6 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - minipass@4.2.8: - resolution: {integrity: sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==} - engines: {node: '>=8'} - minipass@7.1.2: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} @@ -5915,11 +5633,11 @@ packages: moment@2.30.1: resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} - motion-dom@12.23.23: - resolution: {integrity: sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==} + motion-dom@12.24.8: + resolution: {integrity: sha512-wX64WITk6gKOhaTqhsFqmIkayLAAx45SVFiMnJIxIrH5uqyrwrxjrfo8WX9Kh8CaUAixjeMn82iH0W0QT9wD5w==} - motion-utils@12.23.6: - resolution: {integrity: sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==} + motion-utils@12.23.28: + resolution: {integrity: sha512-0W6cWd5Okoyf8jmessVK3spOmbyE0yTdNKujHctHH9XdAE4QDuZ1/LjSXC68rrhsJU+TkzXURC5OdSWh9ibOwQ==} ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -6025,8 +5743,8 @@ packages: node-readfiles@0.2.0: resolution: {integrity: sha512-SU00ZarexNlE4Rjdm83vglt5Y9yiQ+XI1XpflWlb7q7UTN1JUItm69xMeiQCTxtTfnzt+83T8Cx+vI2ED++VDA==} - node-releases@2.0.20: - resolution: {integrity: sha512-7gK6zSXEH6neM212JgfYFXe+GmZQM+fia5SsusuBIUgnPheLFBmIPhtFoAQRj8/7wASYQnbDlHPVwY0BefoFgA==} + node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} @@ -6195,8 +5913,8 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} - parse-asn1@5.1.7: - resolution: {integrity: sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==} + parse-asn1@5.1.9: + resolution: {integrity: sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==} engines: {node: '>= 0.10'} parse-entities@4.0.2: @@ -6318,8 +6036,8 @@ packages: peerDependencies: postcss: ^8.0.0 - postcss-js@4.0.1: - resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} + postcss-js@4.1.0: + resolution: {integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==} engines: {node: ^12 || ^14 || >= 16} peerDependencies: postcss: ^8.4.21 @@ -6383,8 +6101,8 @@ packages: resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} engines: {node: '>=4'} - postcss-selector-parser@7.1.0: - resolution: {integrity: sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==} + postcss-selector-parser@7.1.1: + resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} engines: {node: '>=4'} postcss-value-parser@4.2.0: @@ -6394,10 +6112,6 @@ packages: resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} engines: {node: ^10 || ^12 || >=14} - postcss@8.4.49: - resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} - engines: {node: ^10 || ^12 || >=14} - postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} @@ -6406,8 +6120,8 @@ packages: resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} engines: {node: '>=4'} - postgres-bytea@1.0.0: - resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} + postgres-bytea@1.0.1: + resolution: {integrity: sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==} engines: {node: '>=0.10.0'} postgres-date@1.0.7: @@ -6523,8 +6237,8 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - qs@6.14.0: - resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + qs@6.14.1: + resolution: {integrity: sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==} engines: {node: '>=0.6'} querystring-es3@0.2.1: @@ -6569,12 +6283,6 @@ packages: peerDependencies: react: ^18.3.1 - react-drag-drop-files@2.4.0: - resolution: {integrity: sha512-MGPV3HVVnwXEXq3gQfLtSU3jz5j5jrabvGedokpiSEMoONrDHgYl/NpIOlfsqGQ4zBv1bzzv7qbKURZNOX32PA==} - peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 - react-hook-form@7.66.0: resolution: {integrity: sha512-xXBqsWGKrY46ZqaHDo+ZUYiMUgi8suYu5kdrS20EG8KiL7VRQitEbNjm+UcrDYrNi1YLyfpmAeGjCZYXLT9YBw==} engines: {node: '>=18.0.0'} @@ -6636,8 +6344,8 @@ packages: '@types/react': optional: true - react-remove-scroll@2.7.1: - resolution: {integrity: sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==} + react-remove-scroll@2.7.2: + resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==} engines: {node: '>=10'} peerDependencies: '@types/react': '*' @@ -6727,8 +6435,8 @@ packages: reftools@1.1.9: resolution: {integrity: sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w==} - regenerate-unicode-properties@10.2.0: - resolution: {integrity: sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==} + regenerate-unicode-properties@10.2.2: + resolution: {integrity: sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==} engines: {node: '>=4'} regenerate@1.4.2: @@ -6741,15 +6449,15 @@ packages: resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} - regexpu-core@6.2.0: - resolution: {integrity: sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==} + regexpu-core@6.4.0: + resolution: {integrity: sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==} engines: {node: '>=4'} regjsgen@0.8.0: resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} - regjsparser@0.12.0: - resolution: {integrity: sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==} + regjsparser@0.13.0: + resolution: {integrity: sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==} hasBin: true rehype-autolink-headings@7.1.0: @@ -6816,11 +6524,6 @@ packages: resolution: {integrity: sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==} engines: {node: '>=12'} - resolve@1.22.10: - resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} - engines: {node: '>= 0.4'} - hasBin: true - resolve@1.22.11: resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} engines: {node: '>= 0.4'} @@ -6850,8 +6553,8 @@ packages: resolution: {integrity: sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==} engines: {node: '>= 0.8'} - rollup@4.52.2: - resolution: {integrity: sha512-I25/2QgoROE1vYV+NQ1En9T9UFB9Cmfm2CJ83zZOlaDpvz29wGQSZXWKw7MiNXau7wYgB/T9fVIdIuEQ+KbiiA==} + rollup@4.55.1: + resolution: {integrity: sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -6882,8 +6585,8 @@ packages: safe-stable-stringify@1.1.1: resolution: {integrity: sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw==} - sass-loader@16.0.5: - resolution: {integrity: sha512-oL+CMBXrj6BZ/zOq4os+UECPL+bWqt6OAC6DWS8Ln8GZRcMDjlJ4JC3FBDuHJdYaFWIdKNIBYmtZtK2MaMkNIw==} + sass-loader@16.0.6: + resolution: {integrity: sha512-sglGzId5gmlfxNs4gK2U3h7HlVRfx278YK6Ono5lwzuvi1jxig80YiuHkaDBVsYIKFhx8wN7XSCI0M2IDS/3qA==} engines: {node: '>= 18.12.0'} peerDependencies: '@rspack/core': 0.x || 1.x @@ -6910,19 +6613,14 @@ packages: resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} engines: {node: '>= 10.13.0'} - schema-utils@4.3.2: - resolution: {integrity: sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==} + schema-utils@4.3.3: + resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} engines: {node: '>= 10.13.0'} semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.7.2: - resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} - engines: {node: '>=10'} - hasBin: true - semver@7.7.3: resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} engines: {node: '>=10'} @@ -6951,11 +6649,8 @@ packages: engines: {node: '>= 0.10'} hasBin: true - shallowequal@1.1.0: - resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} - - sharp@0.34.3: - resolution: {integrity: sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==} + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} shebang-command@2.0.0: @@ -7019,9 +6714,6 @@ packages: resolution: {integrity: sha512-LH7FpTAkeD+y5xQC4fzS+tFtaNlvt3Ib1zKzvhjv/Y+cioV4zIuw4IZr2yhRLu67CWL7FR9/6KXKnjRoZTvGGQ==} engines: {node: '>=12'} - simple-swizzle@0.2.2: - resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} - slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -7150,8 +6842,8 @@ packages: resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} engines: {node: '>=8'} - strip-indent@4.0.0: - resolution: {integrity: sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==} + strip-indent@4.1.1: + resolution: {integrity: sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==} engines: {node: '>=12'} strip-json-comments@3.1.1: @@ -7164,18 +6856,11 @@ packages: peerDependencies: webpack: ^5.0.0 - style-to-js@1.1.17: - resolution: {integrity: sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA==} + style-to-js@1.1.21: + resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} - style-to-object@1.0.9: - resolution: {integrity: sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw==} - - styled-components@6.1.19: - resolution: {integrity: sha512-1v/e3Dl1BknC37cXMhwGomhO8AkYmN41CqyX9xhUDxry1ns3BFQy2lLDRQXJRdVVWB9OHemv/53xaStimvWyuA==} - engines: {node: '>= 16'} - peerDependencies: - react: '>= 16.8.0' - react-dom: '>= 16.8.0' + style-to-object@1.0.14: + resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} styled-jsx@5.1.6: resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} @@ -7203,11 +6888,8 @@ packages: babel-plugin-macros: optional: true - stylis@4.3.2: - resolution: {integrity: sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==} - - sucrase@3.35.0: - resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} + sucrase@3.35.1: + resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} engines: {node: '>=16 || 14 >=14.17'} hasBin: true @@ -7246,12 +6928,12 @@ packages: engines: {node: '>=14.0.0'} hasBin: true - tapable@2.2.3: - resolution: {integrity: sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==} + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} - terser-webpack-plugin@5.3.14: - resolution: {integrity: sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==} + terser-webpack-plugin@5.3.16: + resolution: {integrity: sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==} engines: {node: '>= 10.13.0'} peerDependencies: '@swc/core': '*' @@ -7266,8 +6948,8 @@ packages: uglify-js: optional: true - terser@5.44.0: - resolution: {integrity: sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==} + terser@5.44.1: + resolution: {integrity: sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==} engines: {node: '>=10'} hasBin: true @@ -7299,15 +6981,15 @@ packages: resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} engines: {node: '>=14.0.0'} - tinyspy@4.0.3: - resolution: {integrity: sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==} + tinyspy@4.0.4: + resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} engines: {node: '>=14.0.0'} - tldts-core@7.0.17: - resolution: {integrity: sha512-DieYoGrP78PWKsrXr8MZwtQ7GLCUeLxihtjC1jZsW1DnvSMdKPitJSe8OSYDM2u5H6g3kWJZpePqkp43TfLh0g==} + tldts-core@7.0.19: + resolution: {integrity: sha512-lJX2dEWx0SGH4O6p+7FPwYmJ/bu1JbcGJ8RLaG9b7liIgZ85itUVEPbMtWRVrde/0fnDPEPHW10ZsKW3kVsE9A==} - tldts@7.0.17: - resolution: {integrity: sha512-Y1KQBgDd/NUc+LfOtKS6mNsC9CCaH+m2P1RoIZy7RAPo3C3/t8X45+zgut31cRZtZ3xKPjfn3TkGTrctC2TQIQ==} + tldts@7.0.19: + resolution: {integrity: sha512-8PWx8tvC4jDB39BQw1m4x8y5MH1BcQ5xHeL2n7UVFulMPH/3Q0uiamahFJ3lXA0zO2SUyRXuVVbWSDmstlt9YA==} hasBin: true to-buffer@1.2.2: @@ -7335,8 +7017,8 @@ packages: trough@2.2.0: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} - ts-api-utils@2.1.0: - resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + ts-api-utils@2.4.0: + resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==} engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' @@ -7372,9 +7054,6 @@ packages: tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - tslib@2.6.2: - resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -7429,8 +7108,8 @@ packages: peerDependencies: typedoc: 0.28.x - typedoc@0.28.14: - resolution: {integrity: sha512-ftJYPvpVfQvFzpkoSfHLkJybdA/geDJ8BGQt/ZnkkhnBYoYW6lBgPQXu6vqLxO4X75dA55hX8Af847H5KXlEFA==} + typedoc@0.28.15: + resolution: {integrity: sha512-mw2/2vTL7MlT+BVo43lOsufkkd2CJO4zeOSuWQQsiXoV2VuEn7f6IZp2jsUDPmBMABpgR0R5jlcJ2OGEFYmkyg==} engines: {node: '>= 18', pnpm: '>= 10'} hasBin: true peerDependencies: @@ -7459,12 +7138,12 @@ packages: resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} engines: {node: '>=4'} - unicode-match-property-value-ecmascript@2.2.0: - resolution: {integrity: sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==} + unicode-match-property-value-ecmascript@2.2.1: + resolution: {integrity: sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==} engines: {node: '>=4'} - unicode-property-aliases-ecmascript@2.1.0: - resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==} + unicode-property-aliases-ecmascript@2.2.0: + resolution: {integrity: sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==} engines: {node: '>=4'} unicorn-magic@0.1.0: @@ -7477,8 +7156,8 @@ packages: unist-util-find-after@5.0.0: resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} - unist-util-is@6.0.0: - resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} unist-util-position@5.0.0: resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} @@ -7489,8 +7168,8 @@ packages: unist-util-stringify-position@4.0.0: resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} - unist-util-visit-parents@6.0.1: - resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==} + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} unist-util-visit@5.0.0: resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} @@ -7512,8 +7191,8 @@ packages: until-async@3.0.2: resolution: {integrity: sha512-IiSk4HlzAMqTUseHHe3VhIGyuFmN90zMTpD3Z3y8jeQbzLIq500MVM7Jq2vUAnTKAFPJrqwkzr6PoTcPhGcOiw==} - update-browserslist-db@1.1.3: - resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -7548,8 +7227,8 @@ packages: '@types/react': optional: true - use-sync-external-store@1.5.0: - resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==} + use-sync-external-store@1.6.0: + resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -7578,23 +7257,8 @@ packages: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true - validate.io-array@1.0.6: - resolution: {integrity: sha512-DeOy7CnPEziggrOO5CZhVKJw6S3Yi7e9e65R1Nl/RTN1vTQKnzjfvks0/8kQ40FP/dsjRAOd4hxmJ7uLa6vxkg==} - - validate.io-function@1.0.2: - resolution: {integrity: sha512-LlFybRJEriSuBnUhQyG5bwglhh50EpTL2ul23MPIuR1odjO7XaMLFV8vHGwp7AZciFxtYOeiSCT5st+XSPONiQ==} - - validate.io-integer-array@1.0.0: - resolution: {integrity: sha512-mTrMk/1ytQHtCY0oNO3dztafHYyGU88KL+jRxWuzfOmQb+4qqnWmI+gykvGp8usKZOM0H7keJHEbRaFiYA0VrA==} - - validate.io-integer@1.0.5: - resolution: {integrity: sha512-22izsYSLojN/P6bppBqhgUDjCkr5RY2jd+N2a3DCAUey8ydvrZ/OkGvFPR7qfOpwR2LC5p4Ngzxz36g5Vgr/hQ==} - - validate.io-number@1.0.3: - resolution: {integrity: sha512-kRAyotcbNaSYoDnXvb4MHg/0a1egJdLwS6oJ38TJY7aw9n93Fl/3blIXdyYvPOp55CNxywooG/3BcrwNrBpcSg==} - - validator@13.15.20: - resolution: {integrity: sha512-KxPOq3V2LmfQPP4eqf3Mq/zrT0Dqp2Vmx2Bn285LwVahLc+CsxOM0crBHczm8ijlcjZ0Q5Xd6LW3z3odTPnlrw==} + validator@13.15.26: + resolution: {integrity: sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA==} engines: {node: '>= 0.10'} vaul@1.1.2: @@ -7621,8 +7285,8 @@ packages: warning@4.0.3: resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==} - watchpack@2.4.4: - resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==} + watchpack@2.5.0: + resolution: {integrity: sha512-e6vZvY6xboSwLz2GD36c16+O/2Z6fKvIf4pOXptw2rY9MVwE/TXc6RGqxD3I3x0a28lwBY7DE+76uTPSsBrrCA==} engines: {node: '>=10.13.0'} web-namespaces@2.0.1: @@ -7653,8 +7317,8 @@ packages: webpack-virtual-modules@0.6.2: resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} - webpack@5.101.3: - resolution: {integrity: sha512-7b0dTKR3Ed//AD/6kkx/o7duS8H3f1a4w3BYpIriX4BzIhjkn4teo05cptsxvLesHFKK5KObnadmCHBwGc+51A==} + webpack@5.104.1: + resolution: {integrity: sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==} engines: {node: '>=10.13.0'} hasBin: true peerDependencies: @@ -7706,8 +7370,8 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@8.18.3: - resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + ws@8.19.0: + resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -7737,8 +7401,8 @@ packages: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} - yaml@2.8.1: - resolution: {integrity: sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==} + yaml@2.8.2: + resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} engines: {node: '>= 14.6'} hasBin: true @@ -7754,8 +7418,8 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - yocto-queue@1.2.1: - resolution: {integrity: sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==} + yocto-queue@1.2.2: + resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} engines: {node: '>=12.20'} yoctocolors-cjs@2.1.3: @@ -7842,23 +7506,23 @@ snapshots: '@babel/code-frame@7.27.1': dependencies: - '@babel/helper-validator-identifier': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.28.4': {} + '@babel/compat-data@7.28.5': {} - '@babel/core@7.28.4': + '@babel/core@7.28.5': dependencies: '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 + '@babel/generator': 7.28.5 '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.4 + '@babel/parser': 7.28.5 '@babel/template': 7.27.2 - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 debug: 4.4.3 @@ -7868,49 +7532,49 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.28.3': + '@babel/generator@7.28.5': dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.30 + '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 '@babel/helper-annotate-as-pure@7.27.3': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 '@babel/helper-compilation-targets@7.27.2': dependencies: - '@babel/compat-data': 7.28.4 + '@babel/compat-data': 7.28.5 '@babel/helper-validator-option': 7.27.1 - browserslist: 4.25.4 + browserslist: 4.28.1 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.28.3(@babel/core@7.28.4)': + '@babel/helper-create-class-features-plugin@7.28.5(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.27.1 + '@babel/helper-member-expression-to-functions': 7.28.5 '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.4) + '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/helper-create-regexp-features-plugin@7.27.1(@babel/core@7.28.4)': + '@babel/helper-create-regexp-features-plugin@7.28.5(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-annotate-as-pure': 7.27.3 - regexpu-core: 6.2.0 + regexpu-core: 6.4.0 semver: 6.3.1 - '@babel/helper-define-polyfill-provider@0.6.5(@babel/core@7.28.4)': + '@babel/helper-define-polyfill-provider@0.6.5(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 debug: 4.4.3 @@ -7921,646 +7585,646 @@ snapshots: '@babel/helper-globals@7.28.0': {} - '@babel/helper-member-expression-to-functions@7.27.1': + '@babel/helper-member-expression-to-functions@7.28.5': dependencies: - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helper-module-imports@7.27.1': dependencies: - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.4)': + '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helper-optimise-call-expression@7.27.1': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 '@babel/helper-plugin-utils@7.27.1': {} - '@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.28.4)': + '@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-wrap-function': 7.28.3 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color - '@babel/helper-replace-supers@7.27.1(@babel/core@7.28.4)': + '@babel/helper-replace-supers@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 - '@babel/helper-member-expression-to-functions': 7.27.1 + '@babel/core': 7.28.5 + '@babel/helper-member-expression-to-functions': 7.28.5 '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helper-skip-transparent-expression-wrappers@7.27.1': dependencies: - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helper-string-parser@7.27.1': {} - '@babel/helper-validator-identifier@7.27.1': {} + '@babel/helper-validator-identifier@7.28.5': {} '@babel/helper-validator-option@7.27.1': {} '@babel/helper-wrap-function@7.28.3': dependencies: '@babel/template': 7.27.2 - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helpers@7.28.4': dependencies: '@babel/template': 7.27.2 - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 - '@babel/parser@7.28.4': + '@babel/parser@7.28.5': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-transform-optional-chaining': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-optional-chaining': 7.28.5(@babel/core@7.28.5) transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3(@babel/core@7.28.4)': + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.4)': + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 - '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.28.4)': + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.28.4)': + '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-import-assertions@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-syntax-import-assertions@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.28.4)': + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-async-generator-functions@7.28.0(@babel/core@7.28.4)': + '@babel/plugin-transform-async-generator-functions@7.28.0(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.4) - '@babel/traverse': 7.28.4 + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.5) + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-async-to-generator@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-async-to-generator@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-module-imports': 7.27.1 '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.4) + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.5) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-block-scoping@7.28.4(@babel/core@7.28.4)': + '@babel/plugin-transform-block-scoping@7.28.5(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-class-properties@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-class-properties@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-class-static-block@7.28.3(@babel/core@7.28.4)': + '@babel/plugin-transform-class-static-block@7.28.3(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-classes@7.28.4(@babel/core@7.28.4)': + '@babel/plugin-transform-classes@7.28.4(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-globals': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.4) - '@babel/traverse': 7.28.4 + '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-computed-properties@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-computed-properties@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 '@babel/template': 7.27.2 - '@babel/plugin-transform-destructuring@7.28.0(@babel/core@7.28.4)': + '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-dotall-regex@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-dotall-regex@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-explicit-resource-management@7.28.0(@babel/core@7.28.4)': + '@babel/plugin-transform-explicit-resource-management@7.28.0(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.4) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-exponentiation-operator@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-exponentiation-operator@7.28.5(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-for-of@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-for-of@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-function-name@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-function-name@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-json-strings@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-json-strings@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-literals@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-literals@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-logical-assignment-operators@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-logical-assignment-operators@7.28.5(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-systemjs@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-modules-systemjs@7.28.5(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-named-capturing-groups-regex@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-named-capturing-groups-regex@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-new-target@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-new-target@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-nullish-coalescing-operator@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-nullish-coalescing-operator@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-numeric-separator@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-numeric-separator@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-object-rest-spread@7.28.4(@babel/core@7.28.4)': + '@babel/plugin-transform-object-rest-spread@7.28.4(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.4) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.4) - '@babel/traverse': 7.28.4 + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.5) + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-object-super@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-object-super@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.4) + '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-optional-catch-binding@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-optional-catch-binding@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-optional-chaining@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-optional-chaining@7.28.5(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-parameters@7.27.7(@babel/core@7.28.4)': + '@babel/plugin-transform-parameters@7.27.7(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-private-methods@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-private-methods@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-private-property-in-object@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-private-property-in-object@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-property-literals@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-property-literals@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-react-display-name@7.28.0(@babel/core@7.28.4)': + '@babel/plugin-transform-react-display-name@7.28.0(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-react-jsx-development@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-react-jsx-development@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 - '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.5) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-react-jsx@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-react-jsx@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-module-imports': 7.27.1 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.4) - '@babel/types': 7.28.4 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) + '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-react-pure-annotations@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-react-pure-annotations@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-regenerator@7.28.4(@babel/core@7.28.4)': + '@babel/plugin-transform-regenerator@7.28.4(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-regexp-modifiers@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-regexp-modifiers@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-runtime@7.28.3(@babel/core@7.28.4)': + '@babel/plugin-transform-runtime@7.28.5(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-module-imports': 7.27.1 '@babel/helper-plugin-utils': 7.27.1 - babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.28.4) - babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.28.4) - babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.4) + babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.28.5) + babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.28.5) + babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.5) semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-spread@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-spread@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-typescript@7.28.0(@babel/core@7.28.4)': + '@babel/plugin-transform-typescript@7.28.5(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-unicode-property-regex@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-unicode-property-regex@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-unicode-sets-regex@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-unicode-sets-regex@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) '@babel/helper-plugin-utils': 7.27.1 - '@babel/preset-env@7.28.3(@babel/core@7.28.4)': + '@babel/preset-env@7.28.5(@babel/core@7.28.5)': dependencies: - '@babel/compat-data': 7.28.4 - '@babel/core': 7.28.4 + '@babel/compat-data': 7.28.5 + '@babel/core': 7.28.5 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.28.3(@babel/core@7.28.4) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.4) - '@babel/plugin-syntax-import-assertions': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.28.4) - '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-async-generator-functions': 7.28.0(@babel/core@7.28.4) - '@babel/plugin-transform-async-to-generator': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-block-scoping': 7.28.4(@babel/core@7.28.4) - '@babel/plugin-transform-class-properties': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-class-static-block': 7.28.3(@babel/core@7.28.4) - '@babel/plugin-transform-classes': 7.28.4(@babel/core@7.28.4) - '@babel/plugin-transform-computed-properties': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.4) - '@babel/plugin-transform-dotall-regex': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-explicit-resource-management': 7.28.0(@babel/core@7.28.4) - '@babel/plugin-transform-exponentiation-operator': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-json-strings': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-logical-assignment-operators': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-modules-systemjs': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-nullish-coalescing-operator': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-numeric-separator': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-object-rest-spread': 7.28.4(@babel/core@7.28.4) - '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-optional-catch-binding': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-optional-chaining': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.4) - '@babel/plugin-transform-private-methods': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-private-property-in-object': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-property-literals': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-regenerator': 7.28.4(@babel/core@7.28.4) - '@babel/plugin-transform-regexp-modifiers': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-reserved-words': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-spread': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-typeof-symbol': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-unicode-escapes': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-unicode-property-regex': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-unicode-sets-regex': 7.27.1(@babel/core@7.28.4) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.28.4) - babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.28.4) - babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.28.4) - babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.4) - core-js-compat: 3.45.1 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.28.5(@babel/core@7.28.5) + '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.28.3(@babel/core@7.28.5) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.5) + '@babel/plugin-syntax-import-assertions': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.28.5) + '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-async-generator-functions': 7.28.0(@babel/core@7.28.5) + '@babel/plugin-transform-async-to-generator': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-block-scoping': 7.28.5(@babel/core@7.28.5) + '@babel/plugin-transform-class-properties': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-class-static-block': 7.28.3(@babel/core@7.28.5) + '@babel/plugin-transform-classes': 7.28.4(@babel/core@7.28.5) + '@babel/plugin-transform-computed-properties': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5) + '@babel/plugin-transform-dotall-regex': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-explicit-resource-management': 7.28.0(@babel/core@7.28.5) + '@babel/plugin-transform-exponentiation-operator': 7.28.5(@babel/core@7.28.5) + '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-json-strings': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-logical-assignment-operators': 7.28.5(@babel/core@7.28.5) + '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-modules-systemjs': 7.28.5(@babel/core@7.28.5) + '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-nullish-coalescing-operator': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-numeric-separator': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-object-rest-spread': 7.28.4(@babel/core@7.28.5) + '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-optional-catch-binding': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-optional-chaining': 7.28.5(@babel/core@7.28.5) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.5) + '@babel/plugin-transform-private-methods': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-private-property-in-object': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-property-literals': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-regenerator': 7.28.4(@babel/core@7.28.5) + '@babel/plugin-transform-regexp-modifiers': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-reserved-words': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-spread': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-typeof-symbol': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-unicode-escapes': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-unicode-property-regex': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-unicode-sets-regex': 7.27.1(@babel/core@7.28.5) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.28.5) + babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.28.5) + babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.28.5) + babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.5) + core-js-compat: 3.47.0 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.28.4)': + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 esutils: 2.0.3 - '@babel/preset-react@7.27.1(@babel/core@7.28.4)': + '@babel/preset-react@7.28.5(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-transform-react-display-name': 7.28.0(@babel/core@7.28.4) - '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-react-pure-annotations': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-react-display-name': 7.28.0(@babel/core@7.28.5) + '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-react-pure-annotations': 7.27.1(@babel/core@7.28.5) transitivePeerDependencies: - supports-color - '@babel/preset-typescript@7.27.1(@babel/core@7.28.4)': + '@babel/preset-typescript@7.28.5(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-typescript': 7.28.0(@babel/core@7.28.4) + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.5) transitivePeerDependencies: - supports-color @@ -8569,25 +8233,25 @@ snapshots: '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 - '@babel/traverse@7.28.4': + '@babel/traverse@7.28.5': dependencies: '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 + '@babel/generator': 7.28.5 '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.4 + '@babel/parser': 7.28.5 '@babel/template': 7.27.2 - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 debug: 4.4.3 transitivePeerDependencies: - supports-color - '@babel/types@7.28.4': + '@babel/types@7.28.5': dependencies: '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 '@chromatic-com/storybook@4.1.2(storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2))': dependencies: @@ -8607,18 +8271,13 @@ snapshots: '@date-fns/tz@1.4.1': {} - '@emnapi/core@1.7.1': + '@emnapi/core@1.8.1': dependencies: '@emnapi/wasi-threads': 1.1.0 tslib: 2.8.1 optional: true - '@emnapi/runtime@1.5.0': - dependencies: - tslib: 2.8.1 - optional: true - - '@emnapi/runtime@1.7.1': + '@emnapi/runtime@1.8.1': dependencies: tslib: 2.8.1 optional: true @@ -8631,176 +8290,96 @@ snapshots: '@emotion/is-prop-valid@1.2.2': dependencies: '@emotion/memoize': 0.8.1 + optional: true - '@emotion/memoize@0.8.1': {} - - '@emotion/unitless@0.8.1': {} + '@emotion/memoize@0.8.1': + optional: true '@epic-web/invariant@1.0.0': {} - '@esbuild/aix-ppc64@0.25.11': + '@esbuild/aix-ppc64@0.25.12': optional: true - '@esbuild/aix-ppc64@0.25.9': + '@esbuild/android-arm64@0.25.12': optional: true - '@esbuild/android-arm64@0.25.11': + '@esbuild/android-arm@0.25.12': optional: true - '@esbuild/android-arm64@0.25.9': + '@esbuild/android-x64@0.25.12': optional: true - '@esbuild/android-arm@0.25.11': + '@esbuild/darwin-arm64@0.25.12': optional: true - '@esbuild/android-arm@0.25.9': + '@esbuild/darwin-x64@0.25.12': optional: true - '@esbuild/android-x64@0.25.11': + '@esbuild/freebsd-arm64@0.25.12': optional: true - '@esbuild/android-x64@0.25.9': + '@esbuild/freebsd-x64@0.25.12': optional: true - '@esbuild/darwin-arm64@0.25.11': + '@esbuild/linux-arm64@0.25.12': optional: true - '@esbuild/darwin-arm64@0.25.9': + '@esbuild/linux-arm@0.25.12': optional: true - '@esbuild/darwin-x64@0.25.11': + '@esbuild/linux-ia32@0.25.12': optional: true - '@esbuild/darwin-x64@0.25.9': + '@esbuild/linux-loong64@0.25.12': optional: true - '@esbuild/freebsd-arm64@0.25.11': + '@esbuild/linux-mips64el@0.25.12': optional: true - '@esbuild/freebsd-arm64@0.25.9': + '@esbuild/linux-ppc64@0.25.12': optional: true - '@esbuild/freebsd-x64@0.25.11': + '@esbuild/linux-riscv64@0.25.12': optional: true - '@esbuild/freebsd-x64@0.25.9': + '@esbuild/linux-s390x@0.25.12': optional: true - '@esbuild/linux-arm64@0.25.11': + '@esbuild/linux-x64@0.25.12': optional: true - '@esbuild/linux-arm64@0.25.9': + '@esbuild/netbsd-arm64@0.25.12': optional: true - '@esbuild/linux-arm@0.25.11': + '@esbuild/netbsd-x64@0.25.12': optional: true - '@esbuild/linux-arm@0.25.9': + '@esbuild/openbsd-arm64@0.25.12': optional: true - '@esbuild/linux-ia32@0.25.11': + '@esbuild/openbsd-x64@0.25.12': optional: true - '@esbuild/linux-ia32@0.25.9': + '@esbuild/openharmony-arm64@0.25.12': optional: true - '@esbuild/linux-loong64@0.25.11': + '@esbuild/sunos-x64@0.25.12': optional: true - '@esbuild/linux-loong64@0.25.9': + '@esbuild/win32-arm64@0.25.12': optional: true - '@esbuild/linux-mips64el@0.25.11': + '@esbuild/win32-ia32@0.25.12': optional: true - '@esbuild/linux-mips64el@0.25.9': + '@esbuild/win32-x64@0.25.12': optional: true - '@esbuild/linux-ppc64@0.25.11': - optional: true - - '@esbuild/linux-ppc64@0.25.9': - optional: true - - '@esbuild/linux-riscv64@0.25.11': - optional: true - - '@esbuild/linux-riscv64@0.25.9': - optional: true - - '@esbuild/linux-s390x@0.25.11': - optional: true - - '@esbuild/linux-s390x@0.25.9': - optional: true - - '@esbuild/linux-x64@0.25.11': - optional: true - - '@esbuild/linux-x64@0.25.9': - optional: true - - '@esbuild/netbsd-arm64@0.25.11': - optional: true - - '@esbuild/netbsd-arm64@0.25.9': - optional: true - - '@esbuild/netbsd-x64@0.25.11': - optional: true - - '@esbuild/netbsd-x64@0.25.9': - optional: true - - '@esbuild/openbsd-arm64@0.25.11': - optional: true - - '@esbuild/openbsd-arm64@0.25.9': - optional: true - - '@esbuild/openbsd-x64@0.25.11': - optional: true - - '@esbuild/openbsd-x64@0.25.9': - optional: true - - '@esbuild/openharmony-arm64@0.25.11': - optional: true - - '@esbuild/openharmony-arm64@0.25.9': - optional: true - - '@esbuild/sunos-x64@0.25.11': - optional: true - - '@esbuild/sunos-x64@0.25.9': - optional: true - - '@esbuild/win32-arm64@0.25.11': - optional: true - - '@esbuild/win32-arm64@0.25.9': - optional: true - - '@esbuild/win32-ia32@0.25.11': - optional: true - - '@esbuild/win32-ia32@0.25.9': - optional: true - - '@esbuild/win32-x64@0.25.11': - optional: true - - '@esbuild/win32-x64@0.25.9': - optional: true - - '@eslint-community/eslint-utils@4.9.0(eslint@8.57.1)': + '@eslint-community/eslint-utils@4.9.1(eslint@8.57.1)': dependencies: eslint: 8.57.1 eslint-visitor-keys: 3.4.3 - '@eslint-community/regexpp@4.12.1': {} - '@eslint-community/regexpp@4.12.2': {} '@eslint/eslintrc@2.1.4': @@ -8811,7 +8390,7 @@ snapshots: globals: 13.24.0 ignore: 5.3.2 import-fresh: 3.3.1 - js-yaml: 4.1.0 + js-yaml: 4.1.1 minimatch: 3.1.2 strip-json-comments: 3.1.1 transitivePeerDependencies: @@ -8827,25 +8406,25 @@ snapshots: dependencies: '@floating-ui/utils': 0.2.10 - '@floating-ui/dom@1.7.3': + '@floating-ui/dom@1.7.4': dependencies: '@floating-ui/core': 1.7.3 '@floating-ui/utils': 0.2.10 - '@floating-ui/react-dom@2.1.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@floating-ui/react-dom@2.1.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@floating-ui/dom': 1.7.3 + '@floating-ui/dom': 1.7.4 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) '@floating-ui/utils@0.2.10': {} - '@gerrit0/mini-shiki@3.14.0': + '@gerrit0/mini-shiki@3.20.0': dependencies: - '@shikijs/engine-oniguruma': 3.14.0 - '@shikijs/langs': 3.14.0 - '@shikijs/themes': 3.14.0 - '@shikijs/types': 3.14.0 + '@shikijs/engine-oniguruma': 3.21.0 + '@shikijs/langs': 3.21.0 + '@shikijs/themes': 3.21.0 + '@shikijs/types': 3.21.0 '@shikijs/vscode-textmate': 10.0.2 '@hookform/resolvers@5.2.2(react-hook-form@7.66.0(react@18.3.1))': @@ -8867,7 +8446,7 @@ snapshots: '@ibm-cloud/openapi-ruleset-utilities@1.9.0': {} - '@ibm-cloud/openapi-ruleset@1.33.3': + '@ibm-cloud/openapi-ruleset@1.33.5': dependencies: '@ibm-cloud/openapi-ruleset-utilities': 1.9.0 '@stoplight/spectral-formats': 1.8.2 @@ -8880,110 +8459,121 @@ snapshots: loglevel: 1.9.2 loglevel-plugin-prefix: 0.8.4 minimatch: 6.2.0 - validator: 13.15.20 + validator: 13.15.26 transitivePeerDependencies: - encoding - '@img/sharp-darwin-arm64@0.34.3': + '@img/colour@1.0.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.2.0 + '@img/sharp-libvips-darwin-arm64': 1.2.4 optional: true - '@img/sharp-darwin-x64@0.34.3': + '@img/sharp-darwin-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.2.0 + '@img/sharp-libvips-darwin-x64': 1.2.4 optional: true - '@img/sharp-libvips-darwin-arm64@1.2.0': + '@img/sharp-libvips-darwin-arm64@1.2.4': optional: true - '@img/sharp-libvips-darwin-x64@1.2.0': + '@img/sharp-libvips-darwin-x64@1.2.4': optional: true - '@img/sharp-libvips-linux-arm64@1.2.0': + '@img/sharp-libvips-linux-arm64@1.2.4': optional: true - '@img/sharp-libvips-linux-arm@1.2.0': + '@img/sharp-libvips-linux-arm@1.2.4': optional: true - '@img/sharp-libvips-linux-ppc64@1.2.0': + '@img/sharp-libvips-linux-ppc64@1.2.4': optional: true - '@img/sharp-libvips-linux-s390x@1.2.0': + '@img/sharp-libvips-linux-riscv64@1.2.4': optional: true - '@img/sharp-libvips-linux-x64@1.2.0': + '@img/sharp-libvips-linux-s390x@1.2.4': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.2.0': + '@img/sharp-libvips-linux-x64@1.2.4': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.2.0': + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': optional: true - '@img/sharp-linux-arm64@0.34.3': + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.2.0 + '@img/sharp-libvips-linux-arm64': 1.2.4 optional: true - '@img/sharp-linux-arm@0.34.3': + '@img/sharp-linux-arm@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.2.0 + '@img/sharp-libvips-linux-arm': 1.2.4 optional: true - '@img/sharp-linux-ppc64@0.34.3': + '@img/sharp-linux-ppc64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-ppc64': 1.2.0 + '@img/sharp-libvips-linux-ppc64': 1.2.4 optional: true - '@img/sharp-linux-s390x@0.34.3': + '@img/sharp-linux-riscv64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.2.0 + '@img/sharp-libvips-linux-riscv64': 1.2.4 optional: true - '@img/sharp-linux-x64@0.34.3': + '@img/sharp-linux-s390x@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.2.0 + '@img/sharp-libvips-linux-s390x': 1.2.4 optional: true - '@img/sharp-linuxmusl-arm64@0.34.3': + '@img/sharp-linux-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.2.0 + '@img/sharp-libvips-linux-x64': 1.2.4 optional: true - '@img/sharp-linuxmusl-x64@0.34.3': + '@img/sharp-linuxmusl-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.2.0 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 optional: true - '@img/sharp-wasm32@0.34.3': + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.5.0 + '@emnapi/runtime': 1.8.1 optional: true - '@img/sharp-win32-arm64@0.34.3': + '@img/sharp-win32-arm64@0.34.5': optional: true - '@img/sharp-win32-ia32@0.34.3': + '@img/sharp-win32-ia32@0.34.5': optional: true - '@img/sharp-win32-x64@0.34.3': + '@img/sharp-win32-x64@0.34.5': optional: true - '@inquirer/ansi@1.0.1': {} + '@inquirer/ansi@1.0.2': {} - '@inquirer/confirm@5.1.19(@types/node@24.10.0)': + '@inquirer/confirm@5.1.21(@types/node@24.10.0)': dependencies: - '@inquirer/core': 10.3.0(@types/node@24.10.0) - '@inquirer/type': 3.0.9(@types/node@24.10.0) + '@inquirer/core': 10.3.2(@types/node@24.10.0) + '@inquirer/type': 3.0.10(@types/node@24.10.0) optionalDependencies: '@types/node': 24.10.0 - '@inquirer/core@10.3.0(@types/node@24.10.0)': + '@inquirer/core@10.3.2(@types/node@24.10.0)': dependencies: - '@inquirer/ansi': 1.0.1 - '@inquirer/figures': 1.0.14 - '@inquirer/type': 3.0.9(@types/node@24.10.0) + '@inquirer/ansi': 1.0.2 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@24.10.0) cli-width: 4.1.0 mute-stream: 2.0.0 signal-exit: 4.1.0 @@ -8992,9 +8582,9 @@ snapshots: optionalDependencies: '@types/node': 24.10.0 - '@inquirer/figures@1.0.14': {} + '@inquirer/figures@1.0.15': {} - '@inquirer/type@3.0.9(@types/node@24.10.0)': + '@inquirer/type@3.0.10(@types/node@24.10.0)': optionalDependencies: '@types/node': 24.10.0 @@ -9010,23 +8600,23 @@ snapshots: '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.30 + '@jridgewell/trace-mapping': 0.3.31 '@jridgewell/remapping@2.3.5': dependencies: '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.30 + '@jridgewell/trace-mapping': 0.3.31 '@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/source-map@0.3.11': dependencies: '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.30 + '@jridgewell/trace-mapping': 0.3.31 '@jridgewell/sourcemap-codec@1.5.5': {} - '@jridgewell/trace-mapping@0.3.30': + '@jridgewell/trace-mapping@0.3.31': dependencies: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 @@ -9060,8 +8650,8 @@ snapshots: '@napi-rs/wasm-runtime@0.2.12': dependencies: - '@emnapi/core': 1.7.1 - '@emnapi/runtime': 1.7.1 + '@emnapi/core': 1.8.1 + '@emnapi/runtime': 1.8.1 '@tybys/wasm-util': 0.10.1 optional: true @@ -9097,9 +8687,9 @@ snapshots: '@next/swc-win32-x64-msvc@15.4.8': optional: true - '@next/third-parties@15.4.6(next@15.4.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': + '@next/third-parties@15.4.6(next@15.4.10(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': dependencies: - next: 15.4.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 15.4.10(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 third-party-capital: 1.0.20 @@ -9113,7 +8703,7 @@ snapshots: '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.19.1 + fastq: 1.20.1 '@nolyfill/is-core-module@1.0.39': {} @@ -9139,7 +8729,7 @@ snapshots: '@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 '@opentelemetry/instrumentation-amqplib@0.55.0(@opentelemetry/api@1.9.0)': dependencies: @@ -9154,7 +8744,7 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) '@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 '@types/connect': 3.4.38 transitivePeerDependencies: - supports-color @@ -9171,7 +8761,7 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) '@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 transitivePeerDependencies: - supports-color @@ -9202,7 +8792,7 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) '@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 transitivePeerDependencies: - supports-color @@ -9211,7 +8801,7 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) '@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 forwarded-parse: 2.1.2 transitivePeerDependencies: - supports-color @@ -9228,7 +8818,7 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 transitivePeerDependencies: - supports-color @@ -9236,7 +8826,7 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 transitivePeerDependencies: - supports-color @@ -9245,7 +8835,7 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) '@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 transitivePeerDependencies: - supports-color @@ -9275,7 +8865,7 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 '@opentelemetry/sql-common': 0.41.2(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color @@ -9293,7 +8883,7 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) '@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 '@opentelemetry/sql-common': 0.41.2(@opentelemetry/api@1.9.0) '@types/pg': 8.15.6 '@types/pg-pool': 2.0.6 @@ -9305,7 +8895,7 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0) '@opentelemetry/redis-common': 0.38.2 - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 transitivePeerDependencies: - supports-color @@ -9322,7 +8912,7 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) '@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 transitivePeerDependencies: - supports-color @@ -9330,7 +8920,7 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/api-logs': 0.208.0 - import-in-the-middle: 2.0.0 + import-in-the-middle: 2.0.1 require-in-the-middle: 8.0.1 transitivePeerDependencies: - supports-color @@ -9341,16 +8931,16 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 '@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) '@opentelemetry/resources': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 - '@opentelemetry/semantic-conventions@1.37.0': {} + '@opentelemetry/semantic-conventions@1.38.0': {} '@opentelemetry/sql-common@0.41.2(@opentelemetry/api@1.9.0)': dependencies: @@ -9378,15 +8968,15 @@ snapshots: '@orval/core@7.13.0(openapi-types@12.1.3)(typescript@5.9.3)': dependencies: '@apidevtools/swagger-parser': 12.1.0(openapi-types@12.1.3) - '@ibm-cloud/openapi-ruleset': 1.33.3 + '@ibm-cloud/openapi-ruleset': 1.33.5 '@stoplight/spectral-core': 1.20.0 acorn: 8.15.0 chalk: 4.1.2 compare-versions: 6.1.1 debug: 4.4.3 - esbuild: 0.25.11 + esbuild: 0.25.12 esutils: 2.0.3 - fs-extra: 11.3.2 + fs-extra: 11.3.3 globby: 11.1.0 lodash.isempty: 4.4.0 lodash.uniq: 4.5.0 @@ -9395,7 +8985,7 @@ snapshots: micromatch: 4.0.8 openapi3-ts: 4.5.0 swagger2openapi: 7.0.8 - typedoc: 0.28.14(typescript@5.9.3) + typedoc: 0.28.15(typescript@5.9.3) transitivePeerDependencies: - encoding - openapi-types @@ -9416,7 +9006,7 @@ snapshots: dependencies: '@orval/core': 7.13.0(openapi-types@12.1.3)(typescript@5.9.3) '@orval/zod': 7.13.0(openapi-types@12.1.3)(typescript@5.9.3) - fs-extra: 11.3.2 + fs-extra: 11.3.3 lodash.uniq: 4.5.0 openapi3-ts: 4.5.0 transitivePeerDependencies: @@ -9492,17 +9082,17 @@ snapshots: dependencies: playwright: 1.56.1 - '@pmmmwh/react-refresh-webpack-plugin@0.5.17(react-refresh@0.14.2)(type-fest@4.41.0)(webpack-hot-middleware@2.26.1)(webpack@5.101.3(esbuild@0.25.9))': + '@pmmmwh/react-refresh-webpack-plugin@0.5.17(react-refresh@0.14.2)(type-fest@4.41.0)(webpack-hot-middleware@2.26.1)(webpack@5.104.1(esbuild@0.25.12))': dependencies: ansi-html: 0.0.9 - core-js-pure: 3.45.1 + core-js-pure: 3.47.0 error-stack-parser: 2.1.4 html-entities: 2.6.0 loader-utils: 2.0.4 react-refresh: 0.14.2 - schema-utils: 4.3.2 + schema-utils: 4.3.3 source-map: 0.7.6 - webpack: 5.101.3(esbuild@0.25.9) + webpack: 5.104.1(esbuild@0.25.12) optionalDependencies: type-fest: 4.41.0 webpack-hot-middleware: 2.26.1 @@ -9641,7 +9231,7 @@ snapshots: aria-hidden: 1.2.6 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.7.1(@types/react@18.3.17)(react@18.3.1) + react-remove-scroll: 2.7.2(@types/react@18.3.17)(react@18.3.1) optionalDependencies: '@types/react': 18.3.17 '@types/react-dom': 18.3.5(@types/react@18.3.17) @@ -9738,7 +9328,7 @@ snapshots: aria-hidden: 1.2.6 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.7.1(@types/react@18.3.17)(react@18.3.1) + react-remove-scroll: 2.7.2(@types/react@18.3.17)(react@18.3.1) optionalDependencies: '@types/react': 18.3.17 '@types/react-dom': 18.3.5(@types/react@18.3.17) @@ -9761,14 +9351,14 @@ snapshots: aria-hidden: 1.2.6 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.7.1(@types/react@18.3.17)(react@18.3.1) + react-remove-scroll: 2.7.2(@types/react@18.3.17)(react@18.3.1) optionalDependencies: '@types/react': 18.3.17 '@types/react-dom': 18.3.5(@types/react@18.3.17) '@radix-ui/react-popper@1.2.8(@types/react-dom@18.3.5(@types/react@18.3.17))(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@floating-ui/react-dom': 2.1.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@floating-ui/react-dom': 2.1.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-arrow': 1.1.7(@types/react-dom@18.3.5(@types/react@18.3.17))(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.17)(react@18.3.1) '@radix-ui/react-context': 1.1.2(@types/react@18.3.17)(react@18.3.1) @@ -9813,6 +9403,15 @@ snapshots: '@types/react': 18.3.17 '@types/react-dom': 18.3.5(@types/react@18.3.17) + '@radix-ui/react-primitive@2.1.4(@types/react-dom@18.3.5(@types/react@18.3.17))(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-slot': 1.2.4(@types/react@18.3.17)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.17 + '@types/react-dom': 18.3.5(@types/react@18.3.17) + '@radix-ui/react-radio-group@1.3.8(@types/react-dom@18.3.5(@types/react@18.3.17))(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -9889,7 +9488,7 @@ snapshots: aria-hidden: 1.2.6 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.7.1(@types/react@18.3.17)(react@18.3.1) + react-remove-scroll: 2.7.2(@types/react@18.3.17)(react@18.3.1) optionalDependencies: '@types/react': 18.3.17 '@types/react-dom': 18.3.5(@types/react@18.3.17) @@ -9903,6 +9502,25 @@ snapshots: '@types/react': 18.3.17 '@types/react-dom': 18.3.5(@types/react@18.3.17) + '@radix-ui/react-slider@1.3.6(@types/react-dom@18.3.5(@types/react@18.3.17))(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.5(@types/react@18.3.17))(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.5(@types/react@18.3.17))(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.17)(react@18.3.1) + '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.17)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.17 + '@types/react-dom': 18.3.5(@types/react@18.3.17) + '@radix-ui/react-slot@1.2.3(@types/react@18.3.17)(react@18.3.1)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.17)(react@18.3.1) @@ -9910,6 +9528,13 @@ snapshots: optionalDependencies: '@types/react': 18.3.17 + '@radix-ui/react-slot@1.2.4(@types/react@18.3.17)(react@18.3.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.17)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.17 + '@radix-ui/react-switch@1.2.6(@types/react-dom@18.3.5(@types/react@18.3.17))(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -10012,7 +9637,7 @@ snapshots: '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@18.3.17)(react@18.3.1)': dependencies: react: 18.3.1 - use-sync-external-store: 1.5.0(react@18.3.1) + use-sync-external-store: 1.6.0(react@18.3.1) optionalDependencies: '@types/react': 18.3.17 @@ -10053,11 +9678,11 @@ snapshots: '@radix-ui/rect@1.1.1': {} - '@reduxjs/toolkit@2.9.0(react-redux@9.2.0(@types/react@18.3.17)(react@18.3.1)(redux@5.0.1))(react@18.3.1)': + '@reduxjs/toolkit@2.11.2(react-redux@9.2.0(@types/react@18.3.17)(react@18.3.1)(redux@5.0.1))(react@18.3.1)': dependencies: - '@standard-schema/spec': 1.0.0 + '@standard-schema/spec': 1.1.0 '@standard-schema/utils': 0.3.0 - immer: 10.1.3 + immer: 11.1.3 redux: 5.0.1 redux-thunk: 3.1.0(redux@5.0.1) reselect: 5.1.1 @@ -10065,116 +9690,126 @@ snapshots: react: 18.3.1 react-redux: 9.2.0(@types/react@18.3.17)(react@18.3.1)(redux@5.0.1) - '@rjsf/core@5.24.13(@rjsf/utils@5.24.13(react@18.3.1))(react@18.3.1)': + '@rjsf/core@6.1.2(@rjsf/utils@6.1.2(react@18.3.1))(react@18.3.1)': dependencies: - '@rjsf/utils': 5.24.13(react@18.3.1) + '@rjsf/utils': 6.1.2(react@18.3.1) lodash: 4.17.21 - lodash-es: 4.17.21 - markdown-to-jsx: 7.7.13(react@18.3.1) + lodash-es: 4.17.22 + markdown-to-jsx: 8.0.0(react@18.3.1) prop-types: 15.8.1 react: 18.3.1 - '@rjsf/utils@5.24.13(react@18.3.1)': + '@rjsf/utils@6.1.2(react@18.3.1)': dependencies: - json-schema-merge-allof: 0.8.1 + '@x0k/json-schema-merge': 1.0.2 + fast-uri: 3.1.0 jsonpointer: 5.0.1 lodash: 4.17.21 - lodash-es: 4.17.21 + lodash-es: 4.17.22 react: 18.3.1 react-is: 18.3.1 - '@rjsf/validator-ajv8@5.24.13(@rjsf/utils@5.24.13(react@18.3.1))': + '@rjsf/validator-ajv8@6.1.2(@rjsf/utils@6.1.2(react@18.3.1))': dependencies: - '@rjsf/utils': 5.24.13(react@18.3.1) + '@rjsf/utils': 6.1.2(react@18.3.1) ajv: 8.17.1 ajv-formats: 2.1.1(ajv@8.17.1) lodash: 4.17.21 - lodash-es: 4.17.21 + lodash-es: 4.17.22 - '@rollup/plugin-commonjs@28.0.1(rollup@4.52.2)': + '@rollup/plugin-commonjs@28.0.1(rollup@4.55.1)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.52.2) + '@rollup/pluginutils': 5.3.0(rollup@4.55.1) commondir: 1.0.1 estree-walker: 2.0.2 fdir: 6.5.0(picomatch@4.0.3) is-reference: 1.2.1 - magic-string: 0.30.19 + magic-string: 0.30.21 picomatch: 4.0.3 optionalDependencies: - rollup: 4.52.2 + rollup: 4.55.1 - '@rollup/pluginutils@5.3.0(rollup@4.52.2)': + '@rollup/pluginutils@5.3.0(rollup@4.55.1)': dependencies: '@types/estree': 1.0.8 estree-walker: 2.0.2 picomatch: 4.0.3 optionalDependencies: - rollup: 4.52.2 + rollup: 4.55.1 - '@rollup/rollup-android-arm-eabi@4.52.2': + '@rollup/rollup-android-arm-eabi@4.55.1': optional: true - '@rollup/rollup-android-arm64@4.52.2': + '@rollup/rollup-android-arm64@4.55.1': optional: true - '@rollup/rollup-darwin-arm64@4.52.2': + '@rollup/rollup-darwin-arm64@4.55.1': optional: true - '@rollup/rollup-darwin-x64@4.52.2': + '@rollup/rollup-darwin-x64@4.55.1': optional: true - '@rollup/rollup-freebsd-arm64@4.52.2': + '@rollup/rollup-freebsd-arm64@4.55.1': optional: true - '@rollup/rollup-freebsd-x64@4.52.2': + '@rollup/rollup-freebsd-x64@4.55.1': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.52.2': + '@rollup/rollup-linux-arm-gnueabihf@4.55.1': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.52.2': + '@rollup/rollup-linux-arm-musleabihf@4.55.1': optional: true - '@rollup/rollup-linux-arm64-gnu@4.52.2': + '@rollup/rollup-linux-arm64-gnu@4.55.1': optional: true - '@rollup/rollup-linux-arm64-musl@4.52.2': + '@rollup/rollup-linux-arm64-musl@4.55.1': optional: true - '@rollup/rollup-linux-loong64-gnu@4.52.2': + '@rollup/rollup-linux-loong64-gnu@4.55.1': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.52.2': + '@rollup/rollup-linux-loong64-musl@4.55.1': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.52.2': + '@rollup/rollup-linux-ppc64-gnu@4.55.1': optional: true - '@rollup/rollup-linux-riscv64-musl@4.52.2': + '@rollup/rollup-linux-ppc64-musl@4.55.1': optional: true - '@rollup/rollup-linux-s390x-gnu@4.52.2': + '@rollup/rollup-linux-riscv64-gnu@4.55.1': optional: true - '@rollup/rollup-linux-x64-gnu@4.52.2': + '@rollup/rollup-linux-riscv64-musl@4.55.1': optional: true - '@rollup/rollup-linux-x64-musl@4.52.2': + '@rollup/rollup-linux-s390x-gnu@4.55.1': optional: true - '@rollup/rollup-openharmony-arm64@4.52.2': + '@rollup/rollup-linux-x64-gnu@4.55.1': optional: true - '@rollup/rollup-win32-arm64-msvc@4.52.2': + '@rollup/rollup-linux-x64-musl@4.55.1': optional: true - '@rollup/rollup-win32-ia32-msvc@4.52.2': + '@rollup/rollup-openbsd-x64@4.55.1': optional: true - '@rollup/rollup-win32-x64-gnu@4.52.2': + '@rollup/rollup-openharmony-arm64@4.55.1': optional: true - '@rollup/rollup-win32-x64-msvc@4.52.2': + '@rollup/rollup-win32-arm64-msvc@4.55.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.55.1': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.55.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.55.1': optional: true '@rtsao/scc@1.1.0': {} @@ -10201,8 +9836,6 @@ snapshots: '@sentry-internal/browser-utils': 10.27.0 '@sentry/core': 10.27.0 - '@sentry/babel-plugin-component-annotate@4.3.0': {} - '@sentry/babel-plugin-component-annotate@4.6.1': {} '@sentry/browser@10.27.0': @@ -10213,25 +9846,11 @@ snapshots: '@sentry-internal/replay-canvas': 10.27.0 '@sentry/core': 10.27.0 - '@sentry/bundler-plugin-core@4.3.0': - dependencies: - '@babel/core': 7.28.4 - '@sentry/babel-plugin-component-annotate': 4.3.0 - '@sentry/cli': 2.55.0 - dotenv: 16.6.1 - find-up: 5.0.0 - glob: 9.3.5 - magic-string: 0.30.8 - unplugin: 1.0.1 - transitivePeerDependencies: - - encoding - - supports-color - '@sentry/bundler-plugin-core@4.6.1': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@sentry/babel-plugin-component-annotate': 4.6.1 - '@sentry/cli': 2.58.2 + '@sentry/cli': 2.58.4 dotenv: 16.6.1 find-up: 5.0.0 glob: 10.5.0 @@ -10241,55 +9860,31 @@ snapshots: - encoding - supports-color - '@sentry/cli-darwin@2.55.0': + '@sentry/cli-darwin@2.58.4': optional: true - '@sentry/cli-darwin@2.58.2': + '@sentry/cli-linux-arm64@2.58.4': optional: true - '@sentry/cli-linux-arm64@2.55.0': + '@sentry/cli-linux-arm@2.58.4': optional: true - '@sentry/cli-linux-arm64@2.58.2': + '@sentry/cli-linux-i686@2.58.4': optional: true - '@sentry/cli-linux-arm@2.55.0': + '@sentry/cli-linux-x64@2.58.4': optional: true - '@sentry/cli-linux-arm@2.58.2': + '@sentry/cli-win32-arm64@2.58.4': optional: true - '@sentry/cli-linux-i686@2.55.0': + '@sentry/cli-win32-i686@2.58.4': optional: true - '@sentry/cli-linux-i686@2.58.2': + '@sentry/cli-win32-x64@2.58.4': optional: true - '@sentry/cli-linux-x64@2.55.0': - optional: true - - '@sentry/cli-linux-x64@2.58.2': - optional: true - - '@sentry/cli-win32-arm64@2.55.0': - optional: true - - '@sentry/cli-win32-arm64@2.58.2': - optional: true - - '@sentry/cli-win32-i686@2.55.0': - optional: true - - '@sentry/cli-win32-i686@2.58.2': - optional: true - - '@sentry/cli-win32-x64@2.55.0': - optional: true - - '@sentry/cli-win32-x64@2.58.2': - optional: true - - '@sentry/cli@2.55.0': + '@sentry/cli@2.58.4': dependencies: https-proxy-agent: 5.0.1 node-fetch: 2.7.0 @@ -10297,56 +9892,36 @@ snapshots: proxy-from-env: 1.1.0 which: 2.0.2 optionalDependencies: - '@sentry/cli-darwin': 2.55.0 - '@sentry/cli-linux-arm': 2.55.0 - '@sentry/cli-linux-arm64': 2.55.0 - '@sentry/cli-linux-i686': 2.55.0 - '@sentry/cli-linux-x64': 2.55.0 - '@sentry/cli-win32-arm64': 2.55.0 - '@sentry/cli-win32-i686': 2.55.0 - '@sentry/cli-win32-x64': 2.55.0 - transitivePeerDependencies: - - encoding - - supports-color - - '@sentry/cli@2.58.2': - dependencies: - https-proxy-agent: 5.0.1 - node-fetch: 2.7.0 - progress: 2.0.3 - proxy-from-env: 1.1.0 - which: 2.0.2 - optionalDependencies: - '@sentry/cli-darwin': 2.58.2 - '@sentry/cli-linux-arm': 2.58.2 - '@sentry/cli-linux-arm64': 2.58.2 - '@sentry/cli-linux-i686': 2.58.2 - '@sentry/cli-linux-x64': 2.58.2 - '@sentry/cli-win32-arm64': 2.58.2 - '@sentry/cli-win32-i686': 2.58.2 - '@sentry/cli-win32-x64': 2.58.2 + '@sentry/cli-darwin': 2.58.4 + '@sentry/cli-linux-arm': 2.58.4 + '@sentry/cli-linux-arm64': 2.58.4 + '@sentry/cli-linux-i686': 2.58.4 + '@sentry/cli-linux-x64': 2.58.4 + '@sentry/cli-win32-arm64': 2.58.4 + '@sentry/cli-win32-i686': 2.58.4 + '@sentry/cli-win32-x64': 2.58.4 transitivePeerDependencies: - encoding - supports-color '@sentry/core@10.27.0': {} - '@sentry/nextjs@10.27.0(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(next@15.4.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.101.3(esbuild@0.25.9))': + '@sentry/nextjs@10.27.0(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(next@15.4.10(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.104.1(esbuild@0.25.12))': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/semantic-conventions': 1.37.0 - '@rollup/plugin-commonjs': 28.0.1(rollup@4.52.2) + '@opentelemetry/semantic-conventions': 1.38.0 + '@rollup/plugin-commonjs': 28.0.1(rollup@4.55.1) '@sentry-internal/browser-utils': 10.27.0 '@sentry/bundler-plugin-core': 4.6.1 '@sentry/core': 10.27.0 '@sentry/node': 10.27.0 - '@sentry/opentelemetry': 10.27.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.37.0) + '@sentry/opentelemetry': 10.27.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0) '@sentry/react': 10.27.0(react@18.3.1) '@sentry/vercel-edge': 10.27.0 - '@sentry/webpack-plugin': 4.3.0(webpack@5.101.3(esbuild@0.25.9)) - next: 15.4.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@sentry/webpack-plugin': 4.6.1(webpack@5.104.1(esbuild@0.25.12)) + next: 15.4.10(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) resolve: 1.22.8 - rollup: 4.52.2 + rollup: 4.55.1 stacktrace-parser: 0.1.11 transitivePeerDependencies: - '@opentelemetry/context-async-hooks' @@ -10357,7 +9932,7 @@ snapshots: - supports-color - webpack - '@sentry/node-core@10.27.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.37.0)': + '@sentry/node-core@10.27.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0)': dependencies: '@apm-js-collab/tracing-hooks': 0.3.1 '@opentelemetry/api': 1.9.0 @@ -10366,10 +9941,10 @@ snapshots: '@opentelemetry/instrumentation': 0.208.0(@opentelemetry/api@1.9.0) '@opentelemetry/resources': 2.2.0(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-base': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 '@sentry/core': 10.27.0 - '@sentry/opentelemetry': 10.27.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.37.0) - import-in-the-middle: 2.0.0 + '@sentry/opentelemetry': 10.27.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0) + import-in-the-middle: 2.0.1 transitivePeerDependencies: - supports-color @@ -10403,23 +9978,23 @@ snapshots: '@opentelemetry/instrumentation-undici': 0.19.0(@opentelemetry/api@1.9.0) '@opentelemetry/resources': 2.2.0(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-base': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 '@prisma/instrumentation': 6.19.0(@opentelemetry/api@1.9.0) '@sentry/core': 10.27.0 - '@sentry/node-core': 10.27.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.37.0) - '@sentry/opentelemetry': 10.27.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.37.0) - import-in-the-middle: 2.0.0 + '@sentry/node-core': 10.27.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0) + '@sentry/opentelemetry': 10.27.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0) + import-in-the-middle: 2.0.1 minimatch: 9.0.5 transitivePeerDependencies: - supports-color - '@sentry/opentelemetry@10.27.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.37.0)': + '@sentry/opentelemetry@10.27.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/context-async-hooks': 2.2.0(@opentelemetry/api@1.9.0) '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-base': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 '@sentry/core': 10.27.0 '@sentry/react@10.27.0(react@18.3.1)': @@ -10435,30 +10010,30 @@ snapshots: '@opentelemetry/resources': 2.2.0(@opentelemetry/api@1.9.0) '@sentry/core': 10.27.0 - '@sentry/webpack-plugin@4.3.0(webpack@5.101.3(esbuild@0.25.9))': + '@sentry/webpack-plugin@4.6.1(webpack@5.104.1(esbuild@0.25.12))': dependencies: - '@sentry/bundler-plugin-core': 4.3.0 + '@sentry/bundler-plugin-core': 4.6.1 unplugin: 1.0.1 uuid: 9.0.1 - webpack: 5.101.3(esbuild@0.25.9) + webpack: 5.104.1(esbuild@0.25.12) transitivePeerDependencies: - encoding - supports-color - '@shikijs/engine-oniguruma@3.14.0': + '@shikijs/engine-oniguruma@3.21.0': dependencies: - '@shikijs/types': 3.14.0 + '@shikijs/types': 3.21.0 '@shikijs/vscode-textmate': 10.0.2 - '@shikijs/langs@3.14.0': + '@shikijs/langs@3.21.0': dependencies: - '@shikijs/types': 3.14.0 + '@shikijs/types': 3.21.0 - '@shikijs/themes@3.14.0': + '@shikijs/themes@3.21.0': dependencies: - '@shikijs/types': 3.14.0 + '@shikijs/types': 3.21.0 - '@shikijs/types@3.14.0': + '@shikijs/types@3.21.0': dependencies: '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 @@ -10467,6 +10042,8 @@ snapshots: '@standard-schema/spec@1.0.0': {} + '@standard-schema/spec@1.1.0': {} + '@standard-schema/utils@0.3.0': {} '@stoplight/better-ajv-errors@1.0.3(ajv@8.17.1)': @@ -10486,7 +10063,7 @@ snapshots: dependencies: '@stoplight/json': 3.21.7 '@stoplight/path': 1.3.2 - '@stoplight/types': 13.20.0 + '@stoplight/types': 13.6.0 '@types/urijs': 1.19.26 dependency-graph: 0.11.0 fast-memoize: 2.5.2 @@ -10499,7 +10076,7 @@ snapshots: dependencies: '@stoplight/ordered-object-literal': 1.0.5 '@stoplight/path': 1.3.2 - '@stoplight/types': 13.20.0 + '@stoplight/types': 13.6.0 jsonc-parser: 2.2.1 lodash: 4.17.21 safe-stable-stringify: 1.1.1 @@ -10600,7 +10177,7 @@ snapshots: dependencies: '@stoplight/json': 3.21.7 '@stoplight/path': 1.3.2 - '@stoplight/types': 13.20.0 + '@stoplight/types': 13.6.0 abort-controller: 3.0.0 lodash: 4.17.21 node-fetch: 2.7.0 @@ -10635,14 +10212,14 @@ snapshots: '@storybook/addon-a11y@9.1.5(storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2))': dependencies: '@storybook/global': 5.0.0 - axe-core: 4.10.3 + axe-core: 4.11.1 storybook: 9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2) '@storybook/addon-docs@9.1.5(@types/react@18.3.17)(storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2))': dependencies: '@mdx-js/react': 3.1.1(@types/react@18.3.17)(react@18.3.1) '@storybook/csf-plugin': 9.1.5(storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2)) - '@storybook/icons': 1.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/icons': 1.6.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@storybook/react-dom-shim': 9.1.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2)) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -10662,22 +10239,22 @@ snapshots: dependencies: storybook: 9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2) - '@storybook/builder-webpack5@9.1.5(esbuild@0.25.9)(storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2))(typescript@5.9.3)': + '@storybook/builder-webpack5@9.1.5(esbuild@0.25.12)(storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2))(typescript@5.9.3)': dependencies: '@storybook/core-webpack': 9.1.5(storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2)) case-sensitive-paths-webpack-plugin: 2.4.0 cjs-module-lexer: 1.4.3 - css-loader: 6.11.0(webpack@5.101.3(esbuild@0.25.9)) + css-loader: 6.11.0(webpack@5.104.1(esbuild@0.25.12)) es-module-lexer: 1.7.0 - fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.9.3)(webpack@5.101.3(esbuild@0.25.9)) - html-webpack-plugin: 5.6.4(webpack@5.101.3(esbuild@0.25.9)) - magic-string: 0.30.19 + fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.9.3)(webpack@5.104.1(esbuild@0.25.12)) + html-webpack-plugin: 5.6.5(webpack@5.104.1(esbuild@0.25.12)) + magic-string: 0.30.21 storybook: 9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2) - style-loader: 3.3.4(webpack@5.101.3(esbuild@0.25.9)) - terser-webpack-plugin: 5.3.14(esbuild@0.25.9)(webpack@5.101.3(esbuild@0.25.9)) + style-loader: 3.3.4(webpack@5.104.1(esbuild@0.25.12)) + terser-webpack-plugin: 5.3.16(esbuild@0.25.12)(webpack@5.104.1(esbuild@0.25.12)) ts-dedent: 2.2.0 - webpack: 5.101.3(esbuild@0.25.9) - webpack-dev-middleware: 6.1.3(webpack@5.101.3(esbuild@0.25.9)) + webpack: 5.104.1(esbuild@0.25.12) + webpack-dev-middleware: 6.1.3(webpack@5.104.1(esbuild@0.25.12)) webpack-hot-middleware: 2.26.1 webpack-virtual-modules: 0.6.2 optionalDependencies: @@ -10701,53 +10278,53 @@ snapshots: '@storybook/global@5.0.0': {} - '@storybook/icons@1.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@storybook/icons@1.6.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@storybook/nextjs@9.1.5(esbuild@0.25.9)(next@15.4.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2))(type-fest@4.41.0)(typescript@5.9.3)(webpack-hot-middleware@2.26.1)(webpack@5.101.3(esbuild@0.25.9))': + '@storybook/nextjs@9.1.5(esbuild@0.25.12)(next@15.4.10(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2))(type-fest@4.41.0)(typescript@5.9.3)(webpack-hot-middleware@2.26.1)(webpack@5.104.1(esbuild@0.25.12))': dependencies: - '@babel/core': 7.28.4 - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.28.4) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.28.4) - '@babel/plugin-syntax-import-assertions': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-class-properties': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-numeric-separator': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-object-rest-spread': 7.28.4(@babel/core@7.28.4) - '@babel/plugin-transform-runtime': 7.28.3(@babel/core@7.28.4) - '@babel/preset-env': 7.28.3(@babel/core@7.28.4) - '@babel/preset-react': 7.27.1(@babel/core@7.28.4) - '@babel/preset-typescript': 7.27.1(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.28.5) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.28.5) + '@babel/plugin-syntax-import-assertions': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-class-properties': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-numeric-separator': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-object-rest-spread': 7.28.4(@babel/core@7.28.5) + '@babel/plugin-transform-runtime': 7.28.5(@babel/core@7.28.5) + '@babel/preset-env': 7.28.5(@babel/core@7.28.5) + '@babel/preset-react': 7.28.5(@babel/core@7.28.5) + '@babel/preset-typescript': 7.28.5(@babel/core@7.28.5) '@babel/runtime': 7.28.4 - '@pmmmwh/react-refresh-webpack-plugin': 0.5.17(react-refresh@0.14.2)(type-fest@4.41.0)(webpack-hot-middleware@2.26.1)(webpack@5.101.3(esbuild@0.25.9)) - '@storybook/builder-webpack5': 9.1.5(esbuild@0.25.9)(storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2))(typescript@5.9.3) - '@storybook/preset-react-webpack': 9.1.5(esbuild@0.25.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2))(typescript@5.9.3) + '@pmmmwh/react-refresh-webpack-plugin': 0.5.17(react-refresh@0.14.2)(type-fest@4.41.0)(webpack-hot-middleware@2.26.1)(webpack@5.104.1(esbuild@0.25.12)) + '@storybook/builder-webpack5': 9.1.5(esbuild@0.25.12)(storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2))(typescript@5.9.3) + '@storybook/preset-react-webpack': 9.1.5(esbuild@0.25.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2))(typescript@5.9.3) '@storybook/react': 9.1.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2))(typescript@5.9.3) '@types/semver': 7.7.1 - babel-loader: 9.2.1(@babel/core@7.28.4)(webpack@5.101.3(esbuild@0.25.9)) - css-loader: 6.11.0(webpack@5.101.3(esbuild@0.25.9)) + babel-loader: 9.2.1(@babel/core@7.28.5)(webpack@5.104.1(esbuild@0.25.12)) + css-loader: 6.11.0(webpack@5.104.1(esbuild@0.25.12)) image-size: 2.0.2 loader-utils: 3.3.1 - next: 15.4.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - node-polyfill-webpack-plugin: 2.0.1(webpack@5.101.3(esbuild@0.25.9)) + next: 15.4.10(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + node-polyfill-webpack-plugin: 2.0.1(webpack@5.104.1(esbuild@0.25.12)) postcss: 8.5.6 - postcss-loader: 8.2.0(postcss@8.5.6)(typescript@5.9.3)(webpack@5.101.3(esbuild@0.25.9)) + postcss-loader: 8.2.0(postcss@8.5.6)(typescript@5.9.3)(webpack@5.104.1(esbuild@0.25.12)) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) react-refresh: 0.14.2 resolve-url-loader: 5.0.0 - sass-loader: 16.0.5(webpack@5.101.3(esbuild@0.25.9)) - semver: 7.7.2 + sass-loader: 16.0.6(webpack@5.104.1(esbuild@0.25.12)) + semver: 7.7.3 storybook: 9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2) - style-loader: 3.3.4(webpack@5.101.3(esbuild@0.25.9)) - styled-jsx: 5.1.7(@babel/core@7.28.4)(react@18.3.1) + style-loader: 3.3.4(webpack@5.104.1(esbuild@0.25.12)) + styled-jsx: 5.1.7(@babel/core@7.28.5)(react@18.3.1) tsconfig-paths: 4.2.0 tsconfig-paths-webpack-plugin: 4.2.0 optionalDependencies: typescript: 5.9.3 - webpack: 5.101.3(esbuild@0.25.9) + webpack: 5.104.1(esbuild@0.25.12) transitivePeerDependencies: - '@rspack/core' - '@swc/core' @@ -10766,21 +10343,21 @@ snapshots: - webpack-hot-middleware - webpack-plugin-serve - '@storybook/preset-react-webpack@9.1.5(esbuild@0.25.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2))(typescript@5.9.3)': + '@storybook/preset-react-webpack@9.1.5(esbuild@0.25.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2))(typescript@5.9.3)': dependencies: '@storybook/core-webpack': 9.1.5(storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2)) - '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.9.3)(webpack@5.101.3(esbuild@0.25.9)) + '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.9.3)(webpack@5.104.1(esbuild@0.25.12)) '@types/semver': 7.7.1 find-up: 7.0.0 - magic-string: 0.30.19 + magic-string: 0.30.21 react: 18.3.1 react-docgen: 7.1.1 react-dom: 18.3.1(react@18.3.1) - resolve: 1.22.10 - semver: 7.7.2 + resolve: 1.22.11 + semver: 7.7.3 storybook: 9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2) tsconfig-paths: 4.2.0 - webpack: 5.101.3(esbuild@0.25.9) + webpack: 5.104.1(esbuild@0.25.12) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -10790,7 +10367,7 @@ snapshots: - uglify-js - webpack-cli - '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.9.3)(webpack@5.101.3(esbuild@0.25.9))': + '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.9.3)(webpack@5.104.1(esbuild@0.25.12))': dependencies: debug: 4.4.3 endent: 2.1.0 @@ -10800,7 +10377,7 @@ snapshots: react-docgen-typescript: 2.4.0(typescript@5.9.3) tslib: 2.8.1 typescript: 5.9.3 - webpack: 5.101.3(esbuild@0.25.9) + webpack: 5.104.1(esbuild@0.25.12) transitivePeerDependencies: - supports-color @@ -10842,10 +10419,10 @@ snapshots: '@supabase/realtime-js@2.78.0': dependencies: '@supabase/node-fetch': 2.6.15 - '@types/phoenix': 1.6.6 + '@types/phoenix': 1.6.7 '@types/ws': 8.18.1 tslib: 2.8.1 - ws: 8.18.3 + ws: 8.19.0 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -10878,7 +10455,7 @@ snapshots: '@tanstack/eslint-plugin-query@5.91.2(eslint@8.57.1)(typescript@5.9.3)': dependencies: - '@typescript-eslint/utils': 8.46.2(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/utils': 8.52.0(eslint@8.57.1)(typescript@5.9.3) eslint: 8.57.1 transitivePeerDependencies: - supports-color @@ -10918,7 +10495,7 @@ snapshots: picocolors: 1.1.1 pretty-format: 27.5.1 - '@testing-library/jest-dom@6.8.0': + '@testing-library/jest-dom@6.9.1': dependencies: '@adobe/css-tools': 4.4.4 aria-query: 5.3.2 @@ -10940,36 +10517,37 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.28.0 '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 '@types/babel__traverse@7.28.0': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 '@types/canvas-confetti@1.9.0': {} - '@types/chai@5.2.2': + '@types/chai@5.2.3': dependencies: '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 '@types/connect@3.4.38': dependencies: '@types/node': 24.10.0 - '@types/d3-array@3.2.1': {} + '@types/d3-array@3.2.2': {} '@types/d3-color@3.1.3': {} @@ -11084,7 +10662,7 @@ snapshots: pg-protocol: 1.10.3 pg-types: 2.2.0 - '@types/phoenix@1.6.6': {} + '@types/phoenix@1.6.7': {} '@types/prop-types@15.7.15': {} @@ -11103,7 +10681,7 @@ snapshots: '@types/react@18.3.17': dependencies: '@types/prop-types': 15.7.15 - csstype: 3.1.3 + csstype: 3.2.3 '@types/resolve@1.20.6': {} @@ -11111,8 +10689,6 @@ snapshots: '@types/statuses@2.0.6': {} - '@types/stylis@4.2.5': {} - '@types/tedious@4.0.14': dependencies: '@types/node': 24.10.0 @@ -11129,200 +10705,95 @@ snapshots: dependencies: '@types/node': 24.10.0 - '@typescript-eslint/eslint-plugin@8.48.1(@typescript-eslint/parser@8.48.1(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.52.0(@typescript-eslint/parser@8.52.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.48.1(eslint@8.57.1)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.48.1 - '@typescript-eslint/type-utils': 8.48.1(eslint@8.57.1)(typescript@5.9.3) - '@typescript-eslint/utils': 8.48.1(eslint@8.57.1)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.48.1 + '@typescript-eslint/parser': 8.52.0(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.52.0 + '@typescript-eslint/type-utils': 8.52.0(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/utils': 8.52.0(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.52.0 eslint: 8.57.1 - graphemer: 1.4.0 ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.1.0(typescript@5.9.3) + ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.48.1(eslint@8.57.1)(typescript@5.9.3)': + '@typescript-eslint/parser@8.52.0(eslint@8.57.1)(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.48.1 - '@typescript-eslint/types': 8.48.1 - '@typescript-eslint/typescript-estree': 8.48.1(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.48.1 + '@typescript-eslint/scope-manager': 8.52.0 + '@typescript-eslint/types': 8.52.0 + '@typescript-eslint/typescript-estree': 8.52.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.52.0 debug: 4.4.3 eslint: 8.57.1 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.43.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.52.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.43.0(typescript@5.9.3) - '@typescript-eslint/types': 8.48.1 + '@typescript-eslint/tsconfig-utils': 8.52.0(typescript@5.9.3) + '@typescript-eslint/types': 8.52.0 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.46.2(typescript@5.9.3)': + '@typescript-eslint/scope-manager@8.52.0': dependencies: - '@typescript-eslint/tsconfig-utils': 8.46.2(typescript@5.9.3) - '@typescript-eslint/types': 8.48.1 - debug: 4.4.3 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color + '@typescript-eslint/types': 8.52.0 + '@typescript-eslint/visitor-keys': 8.52.0 - '@typescript-eslint/project-service@8.48.1(typescript@5.9.3)': - dependencies: - '@typescript-eslint/tsconfig-utils': 8.48.1(typescript@5.9.3) - '@typescript-eslint/types': 8.48.1 - debug: 4.4.3 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/scope-manager@8.43.0': - dependencies: - '@typescript-eslint/types': 8.43.0 - '@typescript-eslint/visitor-keys': 8.43.0 - - '@typescript-eslint/scope-manager@8.46.2': - dependencies: - '@typescript-eslint/types': 8.46.2 - '@typescript-eslint/visitor-keys': 8.46.2 - - '@typescript-eslint/scope-manager@8.48.1': - dependencies: - '@typescript-eslint/types': 8.48.1 - '@typescript-eslint/visitor-keys': 8.48.1 - - '@typescript-eslint/tsconfig-utils@8.43.0(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.52.0(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/tsconfig-utils@8.46.2(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.52.0(eslint@8.57.1)(typescript@5.9.3)': dependencies: - typescript: 5.9.3 - - '@typescript-eslint/tsconfig-utils@8.48.1(typescript@5.9.3)': - dependencies: - typescript: 5.9.3 - - '@typescript-eslint/type-utils@8.48.1(eslint@8.57.1)(typescript@5.9.3)': - dependencies: - '@typescript-eslint/types': 8.48.1 - '@typescript-eslint/typescript-estree': 8.48.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.48.1(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/types': 8.52.0 + '@typescript-eslint/typescript-estree': 8.52.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.52.0(eslint@8.57.1)(typescript@5.9.3) debug: 4.4.3 eslint: 8.57.1 - ts-api-utils: 2.1.0(typescript@5.9.3) + ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.43.0': {} + '@typescript-eslint/types@8.52.0': {} - '@typescript-eslint/types@8.46.2': {} - - '@typescript-eslint/types@8.48.1': {} - - '@typescript-eslint/typescript-estree@8.43.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.52.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.43.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.43.0(typescript@5.9.3) - '@typescript-eslint/types': 8.43.0 - '@typescript-eslint/visitor-keys': 8.43.0 - debug: 4.4.3 - fast-glob: 3.3.3 - is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.7.3 - ts-api-utils: 2.1.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/typescript-estree@8.46.2(typescript@5.9.3)': - dependencies: - '@typescript-eslint/project-service': 8.46.2(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.46.2(typescript@5.9.3) - '@typescript-eslint/types': 8.46.2 - '@typescript-eslint/visitor-keys': 8.46.2 - debug: 4.4.3 - fast-glob: 3.3.3 - is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.7.3 - ts-api-utils: 2.1.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/typescript-estree@8.48.1(typescript@5.9.3)': - dependencies: - '@typescript-eslint/project-service': 8.48.1(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.48.1(typescript@5.9.3) - '@typescript-eslint/types': 8.48.1 - '@typescript-eslint/visitor-keys': 8.48.1 + '@typescript-eslint/project-service': 8.52.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.52.0(typescript@5.9.3) + '@typescript-eslint/types': 8.52.0 + '@typescript-eslint/visitor-keys': 8.52.0 debug: 4.4.3 minimatch: 9.0.5 semver: 7.7.3 tinyglobby: 0.2.15 - ts-api-utils: 2.1.0(typescript@5.9.3) + ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.43.0(eslint@8.57.1)(typescript@5.9.3)': + '@typescript-eslint/utils@8.52.0(eslint@8.57.1)(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@8.57.1) - '@typescript-eslint/scope-manager': 8.43.0 - '@typescript-eslint/types': 8.43.0 - '@typescript-eslint/typescript-estree': 8.43.0(typescript@5.9.3) + '@eslint-community/eslint-utils': 4.9.1(eslint@8.57.1) + '@typescript-eslint/scope-manager': 8.52.0 + '@typescript-eslint/types': 8.52.0 + '@typescript-eslint/typescript-estree': 8.52.0(typescript@5.9.3) eslint: 8.57.1 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.46.2(eslint@8.57.1)(typescript@5.9.3)': + '@typescript-eslint/visitor-keys@8.52.0': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@8.57.1) - '@typescript-eslint/scope-manager': 8.46.2 - '@typescript-eslint/types': 8.46.2 - '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.3) - eslint: 8.57.1 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@8.48.1(eslint@8.57.1)(typescript@5.9.3)': - dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@8.57.1) - '@typescript-eslint/scope-manager': 8.48.1 - '@typescript-eslint/types': 8.48.1 - '@typescript-eslint/typescript-estree': 8.48.1(typescript@5.9.3) - eslint: 8.57.1 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/visitor-keys@8.43.0': - dependencies: - '@typescript-eslint/types': 8.43.0 - eslint-visitor-keys: 4.2.1 - - '@typescript-eslint/visitor-keys@8.46.2': - dependencies: - '@typescript-eslint/types': 8.46.2 - eslint-visitor-keys: 4.2.1 - - '@typescript-eslint/visitor-keys@8.48.1': - dependencies: - '@typescript-eslint/types': 8.48.1 + '@typescript-eslint/types': 8.52.0 eslint-visitor-keys: 4.2.1 '@ungap/structured-clone@1.3.0': {} @@ -11386,19 +10857,19 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@vercel/analytics@1.5.0(next@15.4.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': + '@vercel/analytics@1.5.0(next@15.4.10(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': optionalDependencies: - next: 15.4.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 15.4.10(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 - '@vercel/speed-insights@1.2.0(next@15.4.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': + '@vercel/speed-insights@1.2.0(next@15.4.10(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': optionalDependencies: - next: 15.4.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 15.4.10(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 '@vitest/expect@3.2.4': dependencies: - '@types/chai': 5.2.2 + '@types/chai': 5.2.3 '@vitest/spy': 3.2.4 '@vitest/utils': 3.2.4 chai: 5.3.3 @@ -11408,7 +10879,7 @@ snapshots: dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 - magic-string: 0.30.19 + magic-string: 0.30.21 optionalDependencies: msw: 2.11.6(@types/node@24.10.0)(typescript@5.9.3) @@ -11418,7 +10889,7 @@ snapshots: '@vitest/spy@3.2.4': dependencies: - tinyspy: 4.0.3 + tinyspy: 4.0.4 '@vitest/utils@3.2.4': dependencies: @@ -11502,17 +10973,21 @@ snapshots: '@webassemblyjs/ast': 1.14.1 '@xtuc/long': 4.2.2 + '@x0k/json-schema-merge@1.0.2': + dependencies: + '@types/json-schema': 7.0.15 + '@xtuc/ieee754@1.2.0': {} '@xtuc/long@4.2.2': {} - '@xyflow/react@12.9.2(@types/react@18.3.17)(immer@10.1.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@xyflow/react@12.9.2(@types/react@18.3.17)(immer@11.1.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@xyflow/system': 0.0.72 classcat: 5.0.5 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - zustand: 4.5.7(@types/react@18.3.17)(immer@10.1.3)(react@18.3.1) + zustand: 4.5.7(@types/react@18.3.17)(immer@11.1.3)(react@18.3.1) transitivePeerDependencies: - '@types/react' - immer @@ -11589,7 +11064,7 @@ snapshots: ajv@8.17.1: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.0.6 + fast-uri: 3.1.0 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -11642,7 +11117,7 @@ snapshots: call-bind: 1.0.8 call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.1 es-object-atoms: 1.1.1 get-intrinsic: 1.3.0 is-string: 1.1.1 @@ -11654,7 +11129,7 @@ snapshots: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.1 es-errors: 1.3.0 es-object-atoms: 1.1.1 es-shim-unscopables: 1.1.0 @@ -11664,7 +11139,7 @@ snapshots: call-bind: 1.0.8 call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.1 es-errors: 1.3.0 es-object-atoms: 1.1.1 es-shim-unscopables: 1.1.0 @@ -11673,21 +11148,21 @@ snapshots: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.1 es-shim-unscopables: 1.1.0 array.prototype.flatmap@1.3.3: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.1 es-shim-unscopables: 1.1.0 array.prototype.tosorted@1.1.4: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.1 es-errors: 1.3.0 es-shim-unscopables: 1.1.0 @@ -11696,7 +11171,7 @@ snapshots: array-buffer-byte-length: 1.0.2 call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.1 es-errors: 1.3.0 get-intrinsic: 1.3.0 is-array-buffer: 3.0.5 @@ -11731,54 +11206,52 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 - axe-core@4.10.3: {} + axe-core@4.11.1: {} - axe-core@4.11.0: {} - - axe-html-reporter@2.2.11(axe-core@4.11.0): + axe-html-reporter@2.2.11(axe-core@4.11.1): dependencies: - axe-core: 4.11.0 + axe-core: 4.11.1 mustache: 4.2.0 axe-playwright@2.2.2(playwright@1.56.1): dependencies: '@types/junit-report-builder': 3.0.2 - axe-core: 4.11.0 - axe-html-reporter: 2.2.11(axe-core@4.11.0) + axe-core: 4.11.1 + axe-html-reporter: 2.2.11(axe-core@4.11.1) junit-report-builder: 5.1.1 picocolors: 1.1.1 playwright: 1.56.1 axobject-query@4.1.0: {} - babel-loader@9.2.1(@babel/core@7.28.4)(webpack@5.101.3(esbuild@0.25.9)): + babel-loader@9.2.1(@babel/core@7.28.5)(webpack@5.104.1(esbuild@0.25.12)): dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 find-cache-dir: 4.0.0 - schema-utils: 4.3.2 - webpack: 5.101.3(esbuild@0.25.9) + schema-utils: 4.3.3 + webpack: 5.104.1(esbuild@0.25.12) - babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.4): + babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.5): dependencies: - '@babel/compat-data': 7.28.4 - '@babel/core': 7.28.4 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.4) + '@babel/compat-data': 7.28.5 + '@babel/core': 7.28.5 + '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.5) semver: 6.3.1 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs3@0.13.0(@babel/core@7.28.4): + babel-plugin-polyfill-corejs3@0.13.0(@babel/core@7.28.5): dependencies: - '@babel/core': 7.28.4 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.4) - core-js-compat: 3.45.1 + '@babel/core': 7.28.5 + '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.5) + core-js-compat: 3.47.0 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-regenerator@0.6.5(@babel/core@7.28.4): + babel-plugin-polyfill-regenerator@0.6.5(@babel/core@7.28.5): dependencies: - '@babel/core': 7.28.4 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.5) transitivePeerDependencies: - supports-color @@ -11788,6 +11261,8 @@ snapshots: base64-js@1.5.1: {} + baseline-browser-mapping@2.9.11: {} + better-opn@3.0.2: dependencies: open: 8.4.2 @@ -11847,16 +11322,15 @@ snapshots: randombytes: 2.1.0 safe-buffer: 5.2.1 - browserify-sign@4.2.3: + browserify-sign@4.2.5: dependencies: bn.js: 5.2.2 browserify-rsa: 4.1.1 create-hash: 1.2.0 create-hmac: 1.1.7 elliptic: 6.6.1 - hash-base: 3.0.5 inherits: 2.0.4 - parse-asn1: 5.1.7 + parse-asn1: 5.1.9 readable-stream: 2.3.8 safe-buffer: 5.2.1 @@ -11864,12 +11338,13 @@ snapshots: dependencies: pako: 1.0.11 - browserslist@4.25.4: + browserslist@4.28.1: dependencies: - caniuse-lite: 1.0.30001741 - electron-to-chromium: 1.5.214 - node-releases: 2.0.20 - update-browserslist-db: 1.1.3(browserslist@4.25.4) + baseline-browser-mapping: 2.9.11 + caniuse-lite: 1.0.30001762 + electron-to-chromium: 1.5.267 + node-releases: 2.0.27 + update-browserslist-db: 1.2.3(browserslist@4.28.1) buffer-from@1.1.2: {} @@ -11910,9 +11385,7 @@ snapshots: camelcase-css@2.0.1: {} - camelize@1.0.1: {} - - caniuse-lite@1.0.30001741: {} + caniuse-lite@1.0.30001762: {} case-sensitive-paths-webpack-plugin@2.4.0: {} @@ -11921,7 +11394,7 @@ snapshots: chai@5.3.3: dependencies: assertion-error: 2.0.1 - check-error: 2.1.1 + check-error: 2.1.3 deep-eql: 5.0.2 loupe: 3.2.1 pathval: 2.0.1 @@ -11939,7 +11412,7 @@ snapshots: character-reference-invalid@2.0.1: {} - check-error@2.1.1: {} + check-error@2.1.3: {} chokidar@3.6.0: dependencies: @@ -11998,7 +11471,7 @@ snapshots: '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.17)(react@18.3.1) '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.5(@types/react@18.3.17))(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-id': 1.1.1(@types/react@18.3.17)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.5(@types/react@18.3.17))(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.5(@types/react@18.3.17))(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) transitivePeerDependencies: @@ -12011,18 +11484,6 @@ snapshots: color-name@1.1.4: {} - color-string@1.9.1: - dependencies: - color-name: 1.1.4 - simple-swizzle: 0.2.2 - optional: true - - color@4.2.3: - dependencies: - color-convert: 2.0.1 - color-string: 1.9.1 - optional: true - colorette@2.0.20: {} comma-separated-tokens@2.0.3: {} @@ -12041,19 +11502,6 @@ snapshots: compare-versions@6.1.1: {} - compute-gcd@1.2.1: - dependencies: - validate.io-array: 1.0.6 - validate.io-function: 1.0.2 - validate.io-integer-array: 1.0.0 - - compute-lcm@1.1.2: - dependencies: - compute-gcd: 1.2.1 - validate.io-array: 1.0.6 - validate.io-function: 1.0.2 - validate.io-integer-array: 1.0.0 - concat-map@0.0.1: {} concurrently@9.2.1: @@ -12075,11 +11523,11 @@ snapshots: cookie@1.0.2: {} - core-js-compat@3.45.1: + core-js-compat@3.47.0: dependencies: - browserslist: 4.25.4 + browserslist: 4.28.1 - core-js-pure@3.45.1: {} + core-js-pure@3.47.0: {} core-util-is@1.0.3: {} @@ -12095,7 +11543,7 @@ snapshots: dependencies: env-paths: 2.2.1 import-fresh: 3.3.1 - js-yaml: 4.1.0 + js-yaml: 4.1.1 parse-json: 5.2.0 optionalDependencies: typescript: 5.9.3 @@ -12136,7 +11584,7 @@ snapshots: crypto-browserify@3.12.1: dependencies: browserify-cipher: 1.0.1 - browserify-sign: 4.2.3 + browserify-sign: 4.2.5 create-ecdh: 4.0.4 create-hash: 1.2.0 create-hmac: 1.1.7 @@ -12148,9 +11596,7 @@ snapshots: randombytes: 2.1.0 randomfill: 1.0.4 - css-color-keywords@1.0.0: {} - - css-loader@6.11.0(webpack@5.101.3(esbuild@0.25.9)): + css-loader@6.11.0(webpack@5.104.1(esbuild@0.25.12)): dependencies: icss-utils: 5.1.0(postcss@8.5.6) postcss: 8.5.6 @@ -12159,9 +11605,9 @@ snapshots: postcss-modules-scope: 3.2.1(postcss@8.5.6) postcss-modules-values: 4.0.0(postcss@8.5.6) postcss-value-parser: 4.2.0 - semver: 7.7.2 + semver: 7.7.3 optionalDependencies: - webpack: 5.101.3(esbuild@0.25.9) + webpack: 5.104.1(esbuild@0.25.12) css-select@4.3.0: dependencies: @@ -12171,19 +11617,13 @@ snapshots: domutils: 2.8.0 nth-check: 2.1.1 - css-to-react-native@3.2.0: - dependencies: - camelize: 1.0.1 - css-color-keywords: 1.0.0 - postcss-value-parser: 4.2.0 - css-what@6.2.2: {} css.escape@1.5.1: {} cssesc@3.0.0: {} - csstype@3.1.3: {} + csstype@3.2.3: {} d3-array@3.2.4: dependencies: @@ -12320,7 +11760,7 @@ snapshots: inherits: 2.0.4 minimalistic-assert: 1.0.1 - detect-libc@2.0.4: + detect-libc@2.1.2: optional: true detect-node-es@1.1.0: {} @@ -12398,7 +11838,7 @@ snapshots: eastasianwidth@0.2.0: {} - electron-to-chromium@1.5.214: {} + electron-to-chromium@1.5.267: {} elliptic@6.6.1: dependencies: @@ -12434,10 +11874,10 @@ snapshots: fast-json-parse: 1.0.3 objectorarray: 1.0.5 - enhanced-resolve@5.18.3: + enhanced-resolve@5.18.4: dependencies: graceful-fs: 4.2.11 - tapable: 2.2.3 + tapable: 2.3.0 enquirer@2.4.1: dependencies: @@ -12452,7 +11892,7 @@ snapshots: env-paths@2.2.1: {} - error-ex@1.3.2: + error-ex@1.3.4: dependencies: is-arrayish: 0.2.1 @@ -12460,7 +11900,7 @@ snapshots: dependencies: stackframe: 1.3.4 - es-abstract@1.24.0: + es-abstract@1.24.1: dependencies: array-buffer-byte-length: 1.0.2 arraybuffer.prototype.slice: 1.0.4 @@ -12521,7 +11961,7 @@ snapshots: dependencies: define-data-property: 1.1.4 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.1 es-errors: 1.3.0 function-bind: 1.1.2 globalthis: 1.0.4 @@ -12532,12 +11972,12 @@ snapshots: es-errors@1.3.0: {} - es-iterator-helpers@1.2.1: + es-iterator-helpers@1.2.2: dependencies: call-bind: 1.0.8 call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.1 es-errors: 1.3.0 es-set-tostringtag: 2.1.0 function-bind: 1.1.2 @@ -12553,6 +11993,8 @@ snapshots: es-module-lexer@1.7.0: {} + es-module-lexer@2.0.0: {} + es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 @@ -12574,74 +12016,45 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 - es-toolkit@1.39.10: {} + es-toolkit@1.43.0: {} es6-promise@3.3.1: {} - esbuild-register@3.6.0(esbuild@0.25.9): + esbuild-register@3.6.0(esbuild@0.25.12): dependencies: debug: 4.4.3 - esbuild: 0.25.9 + esbuild: 0.25.12 transitivePeerDependencies: - supports-color - esbuild@0.25.11: + esbuild@0.25.12: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.11 - '@esbuild/android-arm': 0.25.11 - '@esbuild/android-arm64': 0.25.11 - '@esbuild/android-x64': 0.25.11 - '@esbuild/darwin-arm64': 0.25.11 - '@esbuild/darwin-x64': 0.25.11 - '@esbuild/freebsd-arm64': 0.25.11 - '@esbuild/freebsd-x64': 0.25.11 - '@esbuild/linux-arm': 0.25.11 - '@esbuild/linux-arm64': 0.25.11 - '@esbuild/linux-ia32': 0.25.11 - '@esbuild/linux-loong64': 0.25.11 - '@esbuild/linux-mips64el': 0.25.11 - '@esbuild/linux-ppc64': 0.25.11 - '@esbuild/linux-riscv64': 0.25.11 - '@esbuild/linux-s390x': 0.25.11 - '@esbuild/linux-x64': 0.25.11 - '@esbuild/netbsd-arm64': 0.25.11 - '@esbuild/netbsd-x64': 0.25.11 - '@esbuild/openbsd-arm64': 0.25.11 - '@esbuild/openbsd-x64': 0.25.11 - '@esbuild/openharmony-arm64': 0.25.11 - '@esbuild/sunos-x64': 0.25.11 - '@esbuild/win32-arm64': 0.25.11 - '@esbuild/win32-ia32': 0.25.11 - '@esbuild/win32-x64': 0.25.11 - - esbuild@0.25.9: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.9 - '@esbuild/android-arm': 0.25.9 - '@esbuild/android-arm64': 0.25.9 - '@esbuild/android-x64': 0.25.9 - '@esbuild/darwin-arm64': 0.25.9 - '@esbuild/darwin-x64': 0.25.9 - '@esbuild/freebsd-arm64': 0.25.9 - '@esbuild/freebsd-x64': 0.25.9 - '@esbuild/linux-arm': 0.25.9 - '@esbuild/linux-arm64': 0.25.9 - '@esbuild/linux-ia32': 0.25.9 - '@esbuild/linux-loong64': 0.25.9 - '@esbuild/linux-mips64el': 0.25.9 - '@esbuild/linux-ppc64': 0.25.9 - '@esbuild/linux-riscv64': 0.25.9 - '@esbuild/linux-s390x': 0.25.9 - '@esbuild/linux-x64': 0.25.9 - '@esbuild/netbsd-arm64': 0.25.9 - '@esbuild/netbsd-x64': 0.25.9 - '@esbuild/openbsd-arm64': 0.25.9 - '@esbuild/openbsd-x64': 0.25.9 - '@esbuild/openharmony-arm64': 0.25.9 - '@esbuild/sunos-x64': 0.25.9 - '@esbuild/win32-arm64': 0.25.9 - '@esbuild/win32-ia32': 0.25.9 - '@esbuild/win32-x64': 0.25.9 + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 escalade@3.2.0: {} @@ -12653,12 +12066,12 @@ snapshots: dependencies: '@next/eslint-plugin-next': 15.5.7 '@rushstack/eslint-patch': 1.15.0 - '@typescript-eslint/eslint-plugin': 8.48.1(@typescript-eslint/parser@8.48.1(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3) - '@typescript-eslint/parser': 8.48.1(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.52.0(@typescript-eslint/parser@8.52.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/parser': 8.52.0(eslint@8.57.1)(typescript@5.9.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.1(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.52.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) eslint-plugin-react: 7.37.5(eslint@8.57.1) eslint-plugin-react-hooks: 5.2.0(eslint@8.57.1) @@ -12688,22 +12101,22 @@ snapshots: tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.1(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.52.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.48.1(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.52.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.48.1(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/parser': 8.52.0(eslint@8.57.1)(typescript@5.9.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.52.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -12714,7 +12127,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.48.1(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.52.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -12726,7 +12139,7 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.48.1(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/parser': 8.52.0(eslint@8.57.1)(typescript@5.9.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -12738,7 +12151,7 @@ snapshots: array-includes: 3.1.9 array.prototype.flatmap: 1.3.3 ast-types-flow: 0.0.8 - axe-core: 4.11.0 + axe-core: 4.11.1 axobject-query: 4.1.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 @@ -12762,7 +12175,7 @@ snapshots: array.prototype.flatmap: 1.3.3 array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 - es-iterator-helpers: 1.2.1 + es-iterator-helpers: 1.2.2 eslint: 8.57.1 estraverse: 5.3.0 hasown: 2.0.2 @@ -12779,7 +12192,7 @@ snapshots: eslint-plugin-storybook@9.1.5(eslint@8.57.1)(storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2))(typescript@5.9.3): dependencies: - '@typescript-eslint/utils': 8.43.0(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/utils': 8.52.0(eslint@8.57.1)(typescript@5.9.3) eslint: 8.57.1 storybook: 9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2) transitivePeerDependencies: @@ -12802,8 +12215,8 @@ snapshots: eslint@8.57.1: dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@8.57.1) - '@eslint-community/regexpp': 4.12.1 + '@eslint-community/eslint-utils': 4.9.1(eslint@8.57.1) + '@eslint-community/regexpp': 4.12.2 '@eslint/eslintrc': 2.1.4 '@eslint/js': 8.57.1 '@humanwhocodes/config-array': 0.13.0 @@ -12819,7 +12232,7 @@ snapshots: eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 - esquery: 1.6.0 + esquery: 1.7.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 6.0.1 @@ -12831,7 +12244,7 @@ snapshots: imurmurhash: 0.1.4 is-glob: 4.0.3 is-path-inside: 3.0.3 - js-yaml: 4.1.0 + js-yaml: 4.1.1 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 lodash.merge: 4.6.2 @@ -12851,7 +12264,7 @@ snapshots: esprima@4.0.1: {} - esquery@1.6.0: + esquery@1.7.0: dependencies: estraverse: 5.3.0 @@ -12930,9 +12343,9 @@ snapshots: fast-safe-stringify@2.1.1: {} - fast-uri@3.0.6: {} + fast-uri@3.1.0: {} - fastq@1.19.1: + fastq@1.20.1: dependencies: reusify: 1.1.0 @@ -13007,7 +12420,7 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - fork-ts-checker-webpack-plugin@8.0.0(typescript@5.9.3)(webpack@5.101.3(esbuild@0.25.9)): + fork-ts-checker-webpack-plugin@8.0.0(typescript@5.9.3)(webpack@5.104.1(esbuild@0.25.12)): dependencies: '@babel/code-frame': 7.27.1 chalk: 4.1.2 @@ -13020,16 +12433,16 @@ snapshots: node-abort-controller: 3.1.1 schema-utils: 3.3.0 semver: 7.7.3 - tapable: 2.2.3 + tapable: 2.3.0 typescript: 5.9.3 - webpack: 5.101.3(esbuild@0.25.9) + webpack: 5.104.1(esbuild@0.25.12) forwarded-parse@2.1.2: {} framer-motion@12.23.24(@emotion/is-prop-valid@1.2.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - motion-dom: 12.23.23 - motion-utils: 12.23.6 + motion-dom: 12.24.8 + motion-utils: 12.23.28 tslib: 2.8.1 optionalDependencies: '@emotion/is-prop-valid': 1.2.2 @@ -13042,7 +12455,7 @@ snapshots: jsonfile: 6.2.0 universalify: 2.0.1 - fs-extra@11.3.2: + fs-extra@11.3.3: dependencies: graceful-fs: 4.2.11 jsonfile: 6.2.0 @@ -13071,9 +12484,9 @@ snapshots: functions-have-names@1.2.3: {} - geist@1.5.1(next@15.4.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)): + geist@1.5.1(next@15.4.10(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)): dependencies: - next: 15.4.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 15.4.10(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) generator-function@2.0.1: {} @@ -13125,15 +12538,6 @@ snapshots: glob-to-regexp@0.4.1: {} - glob@10.4.5: - dependencies: - foreground-child: 3.3.1 - jackspeak: 3.4.3 - minimatch: 9.0.5 - minipass: 7.1.2 - package-json-from-dist: 1.0.1 - path-scurry: 1.11.1 - glob@10.5.0: dependencies: foreground-child: 3.3.1 @@ -13152,13 +12556,6 @@ snapshots: once: 1.4.0 path-is-absolute: 1.0.1 - glob@9.3.5: - dependencies: - fs.realpath: 1.0.0 - minimatch: 8.0.4 - minipass: 4.2.8 - path-scurry: 1.11.1 - globals@13.24.0: dependencies: type-fest: 0.20.2 @@ -13183,7 +12580,7 @@ snapshots: graphemer@1.4.0: {} - graphql@16.11.0: {} + graphql@16.12.0: {} has-bigints@1.1.0: {} @@ -13283,7 +12680,7 @@ snapshots: mdast-util-mdxjs-esm: 2.0.1 property-information: 7.1.0 space-separated-tokens: 2.0.2 - style-to-js: 1.1.17 + style-to-js: 1.1.21 unist-util-position: 5.0.0 vfile-message: 4.0.3 transitivePeerDependencies: @@ -13338,19 +12735,19 @@ snapshots: he: 1.2.0 param-case: 3.0.4 relateurl: 0.2.7 - terser: 5.44.0 + terser: 5.44.1 html-url-attributes@3.0.1: {} - html-webpack-plugin@5.6.4(webpack@5.101.3(esbuild@0.25.9)): + html-webpack-plugin@5.6.5(webpack@5.104.1(esbuild@0.25.12)): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 lodash: 4.17.21 pretty-error: 4.0.0 - tapable: 2.2.3 + tapable: 2.3.0 optionalDependencies: - webpack: 5.101.3(esbuild@0.25.9) + webpack: 5.104.1(esbuild@0.25.12) htmlparser2@6.1.0: dependencies: @@ -13384,7 +12781,9 @@ snapshots: image-size@2.0.2: {} - immer@10.1.3: {} + immer@10.2.0: {} + + immer@11.1.3: {} immer@9.0.21: {} @@ -13393,7 +12792,7 @@ snapshots: parent-module: 1.0.1 resolve-from: 4.0.0 - import-in-the-middle@2.0.0: + import-in-the-middle@2.0.1: dependencies: acorn: 8.15.0 acorn-import-attributes: 1.9.5(acorn@8.15.0) @@ -13413,7 +12812,7 @@ snapshots: inherits@2.0.4: {} - inline-style-parser@0.2.4: {} + inline-style-parser@0.2.7: {} internal-slot@1.1.0: dependencies: @@ -13443,9 +12842,6 @@ snapshots: is-arrayish@0.2.1: {} - is-arrayish@0.3.2: - optional: true - is-async-function@2.1.1: dependencies: async-function: 1.0.0 @@ -13500,13 +12896,6 @@ snapshots: is-fullwidth-code-point@3.0.0: {} - is-generator-function@1.1.0: - dependencies: - call-bound: 1.0.4 - get-proto: 1.0.1 - has-tostringtag: 1.0.2 - safe-regex-test: 1.1.0 - is-generator-function@1.1.2: dependencies: call-bound: 1.0.4 @@ -13623,7 +13012,7 @@ snapshots: jiti@1.21.7: {} - jiti@2.5.1: {} + jiti@2.6.1: {} js-tokens@4.0.0: {} @@ -13631,9 +13020,11 @@ snapshots: dependencies: argparse: 2.0.1 - jsep@1.4.0: {} + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 - jsesc@3.0.2: {} + jsep@1.4.0: {} jsesc@3.1.0: {} @@ -13641,16 +13032,6 @@ snapshots: json-parse-even-better-errors@2.3.1: {} - json-schema-compare@0.2.2: - dependencies: - lodash: 4.17.21 - - json-schema-merge-allof@0.8.1: - dependencies: - compute-lcm: 1.1.2 - json-schema-compare: 0.2.2 - lodash: 4.17.21 - json-schema-traverse@0.4.1: {} json-schema-traverse@1.0.0: {} @@ -13742,7 +13123,7 @@ snapshots: dependencies: uc.micro: 2.1.0 - loader-runner@4.3.0: {} + loader-runner@4.3.1: {} loader-utils@2.0.4: dependencies: @@ -13764,7 +13145,7 @@ snapshots: dependencies: p-locate: 6.0.0 - lodash-es@4.17.21: {} + lodash-es@4.17.22: {} lodash.camelcase@4.3.0: {} @@ -13822,7 +13203,7 @@ snapshots: lz-string@1.5.0: {} - magic-string@0.30.19: + magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -13845,8 +13226,8 @@ snapshots: markdown-table@3.0.4: {} - markdown-to-jsx@7.7.13(react@18.3.1): - dependencies: + markdown-to-jsx@8.0.0(react@18.3.1): + optionalDependencies: react: 18.3.1 math-intrinsics@1.1.0: {} @@ -13861,8 +13242,8 @@ snapshots: dependencies: '@types/mdast': 4.0.4 escape-string-regexp: 5.0.0 - unist-util-is: 6.0.0 - unist-util-visit-parents: 6.0.1 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 mdast-util-from-markdown@2.0.2: dependencies: @@ -13992,9 +13373,9 @@ snapshots: mdast-util-phrasing@4.1.0: dependencies: '@types/mdast': 4.0.4 - unist-util-is: 6.0.0 + unist-util-is: 6.0.1 - mdast-util-to-hast@13.2.0: + mdast-util-to-hast@13.2.1: dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 @@ -14267,29 +13648,23 @@ snapshots: dependencies: brace-expansion: 2.0.2 - minimatch@8.0.4: - dependencies: - brace-expansion: 2.0.2 - minimatch@9.0.5: dependencies: brace-expansion: 2.0.2 minimist@1.2.8: {} - minipass@4.2.8: {} - minipass@7.1.2: {} module-details-from-path@1.0.4: {} moment@2.30.1: {} - motion-dom@12.23.23: + motion-dom@12.24.8: dependencies: - motion-utils: 12.23.6 + motion-utils: 12.23.28 - motion-utils@12.23.6: {} + motion-utils@12.23.28: {} ms@2.1.3: {} @@ -14300,12 +13675,12 @@ snapshots: msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3): dependencies: - '@inquirer/confirm': 5.1.19(@types/node@24.10.0) + '@inquirer/confirm': 5.1.21(@types/node@24.10.0) '@mswjs/interceptors': 0.40.0 '@open-draft/deferred-promise': 2.2.0 '@types/statuses': 2.0.6 cookie: 1.0.2 - graphql: 16.11.0 + graphql: 16.12.0 headers-polyfill: 4.0.3 is-node-process: 1.2.0 outvariant: 1.4.3 @@ -14346,15 +13721,15 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - next@15.4.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + next@15.4.10(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@next/env': 15.4.10 '@swc/helpers': 0.5.15 - caniuse-lite: 1.0.30001741 + caniuse-lite: 1.0.30001762 postcss: 8.4.31 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - styled-jsx: 5.1.6(@babel/core@7.28.4)(react@18.3.1) + styled-jsx: 5.1.6(@babel/core@7.28.5)(react@18.3.1) optionalDependencies: '@next/swc-darwin-arm64': 15.4.8 '@next/swc-darwin-x64': 15.4.8 @@ -14366,7 +13741,7 @@ snapshots: '@next/swc-win32-x64-msvc': 15.4.8 '@opentelemetry/api': 1.9.0 '@playwright/test': 1.56.1 - sharp: 0.34.3 + sharp: 0.34.5 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros @@ -14396,7 +13771,7 @@ snapshots: dependencies: whatwg-url: 5.0.0 - node-polyfill-webpack-plugin@2.0.1(webpack@5.101.3(esbuild@0.25.9)): + node-polyfill-webpack-plugin@2.0.1(webpack@5.104.1(esbuild@0.25.12)): dependencies: assert: 2.1.0 browserify-zlib: 0.2.0 @@ -14423,13 +13798,13 @@ snapshots: url: 0.11.4 util: 0.12.5 vm-browserify: 1.1.2 - webpack: 5.101.3(esbuild@0.25.9) + webpack: 5.104.1(esbuild@0.25.12) node-readfiles@0.2.0: dependencies: es6-promise: 3.3.1 - node-releases@2.0.20: {} + node-releases@2.0.27: {} normalize-path@3.0.0: {} @@ -14441,12 +13816,12 @@ snapshots: dependencies: boolbase: 1.0.0 - nuqs@2.7.2(next@15.4.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1): + nuqs@2.7.2(next@15.4.10(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1): dependencies: '@standard-schema/spec': 1.0.0 react: 18.3.1 optionalDependencies: - next: 15.4.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 15.4.10(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) oas-kit-common@1.0.8: dependencies: @@ -14512,14 +13887,14 @@ snapshots: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.1 es-object-atoms: 1.1.1 object.groupby@1.0.3: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.1 object.values@1.2.1: dependencies: @@ -14548,7 +13923,7 @@ snapshots: openapi3-ts@4.5.0: dependencies: - yaml: 2.8.1 + yaml: 2.8.2 optionator@0.9.4: dependencies: @@ -14579,15 +13954,15 @@ snapshots: enquirer: 2.4.1 execa: 5.1.1 find-up: 5.0.0 - fs-extra: 11.3.2 + fs-extra: 11.3.3 js-yaml: 4.1.0 lodash.uniq: 4.5.0 openapi3-ts: 4.5.0 string-argv: 0.3.2 tsconfck: 2.1.2(typescript@5.9.3) - typedoc: 0.28.14(typescript@5.9.3) - typedoc-plugin-coverage: 4.0.2(typedoc@0.28.14(typescript@5.9.3)) - typedoc-plugin-markdown: 4.9.0(typedoc@0.28.14(typescript@5.9.3)) + typedoc: 0.28.15(typescript@5.9.3) + typedoc-plugin-coverage: 4.0.2(typedoc@0.28.15(typescript@5.9.3)) + typedoc-plugin-markdown: 4.9.0(typedoc@0.28.15(typescript@5.9.3)) transitivePeerDependencies: - encoding - openapi-types @@ -14614,7 +13989,7 @@ snapshots: p-limit@4.0.0: dependencies: - yocto-queue: 1.2.1 + yocto-queue: 1.2.2 p-locate@4.1.0: dependencies: @@ -14643,12 +14018,11 @@ snapshots: dependencies: callsites: 3.1.0 - parse-asn1@5.1.7: + parse-asn1@5.1.9: dependencies: asn1.js: 4.10.1 browserify-aes: 1.2.0 evp_bytestokey: 1.0.3 - hash-base: 3.0.5 pbkdf2: 3.1.5 safe-buffer: 5.2.1 @@ -14665,7 +14039,7 @@ snapshots: parse-json@5.2.0: dependencies: '@babel/code-frame': 7.27.1 - error-ex: 1.3.2 + error-ex: 1.3.4 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -14720,7 +14094,7 @@ snapshots: dependencies: pg-int8: 1.0.1 postgres-array: 2.0.0 - postgres-bytea: 1.0.0 + postgres-bytea: 1.0.1 postgres-date: 1.0.7 postgres-interval: 1.2.0 @@ -14759,9 +14133,9 @@ snapshots: postcss: 8.5.6 postcss-value-parser: 4.2.0 read-cache: 1.0.0 - resolve: 1.22.10 + resolve: 1.22.11 - postcss-js@4.0.1(postcss@8.5.6): + postcss-js@4.1.0(postcss@8.5.6): dependencies: camelcase-css: 2.0.1 postcss: 8.5.6 @@ -14769,18 +14143,18 @@ snapshots: postcss-load-config@4.0.2(postcss@8.5.6): dependencies: lilconfig: 3.1.3 - yaml: 2.8.1 + yaml: 2.8.2 optionalDependencies: postcss: 8.5.6 - postcss-loader@8.2.0(postcss@8.5.6)(typescript@5.9.3)(webpack@5.101.3(esbuild@0.25.9)): + postcss-loader@8.2.0(postcss@8.5.6)(typescript@5.9.3)(webpack@5.104.1(esbuild@0.25.12)): dependencies: cosmiconfig: 9.0.0(typescript@5.9.3) - jiti: 2.5.1 + jiti: 2.6.1 postcss: 8.5.6 - semver: 7.7.2 + semver: 7.7.3 optionalDependencies: - webpack: 5.101.3(esbuild@0.25.9) + webpack: 5.104.1(esbuild@0.25.12) transitivePeerDependencies: - typescript @@ -14792,13 +14166,13 @@ snapshots: dependencies: icss-utils: 5.1.0(postcss@8.5.6) postcss: 8.5.6 - postcss-selector-parser: 7.1.0 + postcss-selector-parser: 7.1.1 postcss-value-parser: 4.2.0 postcss-modules-scope@3.2.1(postcss@8.5.6): dependencies: postcss: 8.5.6 - postcss-selector-parser: 7.1.0 + postcss-selector-parser: 7.1.1 postcss-modules-values@4.0.0(postcss@8.5.6): dependencies: @@ -14815,7 +14189,7 @@ snapshots: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss-selector-parser@7.1.0: + postcss-selector-parser@7.1.1: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 @@ -14828,12 +14202,6 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - postcss@8.4.49: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - postcss@8.5.6: dependencies: nanoid: 3.3.11 @@ -14842,7 +14210,7 @@ snapshots: postgres-array@2.0.0: {} - postgres-bytea@1.0.0: {} + postgres-bytea@1.0.1: {} postgres-date@1.0.7: {} @@ -14890,7 +14258,7 @@ snapshots: bn.js: 4.12.2 browserify-rsa: 4.1.1 create-hash: 1.2.0 - parse-asn1: 5.1.7 + parse-asn1: 5.1.9 randombytes: 2.1.0 safe-buffer: 5.2.1 @@ -14900,7 +14268,7 @@ snapshots: punycode@2.3.1: {} - qs@6.14.0: + qs@6.14.1: dependencies: side-channel: 1.1.0 @@ -14936,16 +14304,16 @@ snapshots: react-docgen@7.1.1: dependencies: - '@babel/core': 7.28.4 - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/core': 7.28.5 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.28.0 '@types/doctrine': 0.0.9 '@types/resolve': 1.20.6 doctrine: 3.0.0 - resolve: 1.22.10 - strip-indent: 4.0.0 + resolve: 1.22.11 + strip-indent: 4.1.1 transitivePeerDependencies: - supports-color @@ -14955,13 +14323,6 @@ snapshots: react: 18.3.1 scheduler: 0.23.2 - react-drag-drop-files@2.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - styled-components: 6.1.19(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-hook-form@7.66.0(react@18.3.1): dependencies: react: 18.3.1 @@ -14985,7 +14346,7 @@ snapshots: devlop: 1.1.0 hast-util-to-jsx-runtime: 2.3.6 html-url-attributes: 3.0.1 - mdast-util-to-hast: 13.2.0 + mdast-util-to-hast: 13.2.1 react: 18.3.1 remark-parse: 11.0.0 remark-rehype: 11.1.2 @@ -15008,7 +14369,7 @@ snapshots: dependencies: '@types/use-sync-external-store': 0.0.6 react: 18.3.1 - use-sync-external-store: 1.5.0(react@18.3.1) + use-sync-external-store: 1.6.0(react@18.3.1) optionalDependencies: '@types/react': 18.3.17 redux: 5.0.1 @@ -15023,7 +14384,7 @@ snapshots: optionalDependencies: '@types/react': 18.3.17 - react-remove-scroll@2.7.1(@types/react@18.3.17)(react@18.3.1): + react-remove-scroll@2.7.2(@types/react@18.3.17)(react@18.3.1): dependencies: react: 18.3.1 react-remove-scroll-bar: 2.3.8(@types/react@18.3.17)(react@18.3.1) @@ -15104,19 +14465,19 @@ snapshots: recharts@3.3.0(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react-is@18.3.1)(react@18.3.1)(redux@5.0.1): dependencies: - '@reduxjs/toolkit': 2.9.0(react-redux@9.2.0(@types/react@18.3.17)(react@18.3.1)(redux@5.0.1))(react@18.3.1) + '@reduxjs/toolkit': 2.11.2(react-redux@9.2.0(@types/react@18.3.17)(react@18.3.1)(redux@5.0.1))(react@18.3.1) clsx: 2.1.1 decimal.js-light: 2.5.1 - es-toolkit: 1.39.10 + es-toolkit: 1.43.0 eventemitter3: 5.0.1 - immer: 10.1.3 + immer: 10.2.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) react-is: 18.3.1 react-redux: 9.2.0(@types/react@18.3.17)(react@18.3.1)(redux@5.0.1) reselect: 5.1.1 tiny-invariant: 1.3.3 - use-sync-external-store: 1.5.0(react@18.3.1) + use-sync-external-store: 1.6.0(react@18.3.1) victory-vendor: 37.3.6 transitivePeerDependencies: - '@types/react' @@ -15137,7 +14498,7 @@ snapshots: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.1 es-errors: 1.3.0 es-object-atoms: 1.1.1 get-intrinsic: 1.3.0 @@ -15146,7 +14507,7 @@ snapshots: reftools@1.1.9: {} - regenerate-unicode-properties@10.2.0: + regenerate-unicode-properties@10.2.2: dependencies: regenerate: 1.4.2 @@ -15163,20 +14524,20 @@ snapshots: gopd: 1.2.0 set-function-name: 2.0.2 - regexpu-core@6.2.0: + regexpu-core@6.4.0: dependencies: regenerate: 1.4.2 - regenerate-unicode-properties: 10.2.0 + regenerate-unicode-properties: 10.2.2 regjsgen: 0.8.0 - regjsparser: 0.12.0 + regjsparser: 0.13.0 unicode-match-property-ecmascript: 2.0.0 - unicode-match-property-value-ecmascript: 2.2.0 + unicode-match-property-value-ecmascript: 2.2.1 regjsgen@0.8.0: {} - regjsparser@0.12.0: + regjsparser@0.13.0: dependencies: - jsesc: 3.0.2 + jsesc: 3.1.0 rehype-autolink-headings@7.1.0: dependencies: @@ -15202,7 +14563,7 @@ snapshots: hast-util-from-html-isomorphic: 2.0.0 hast-util-to-text: 4.0.2 katex: 0.16.25 - unist-util-visit-parents: 6.0.1 + unist-util-visit-parents: 6.0.2 vfile: 6.0.3 rehype-slug@6.0.0: @@ -15248,7 +14609,7 @@ snapshots: dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 - mdast-util-to-hast: 13.2.0 + mdast-util-to-hast: 13.2.1 unified: 11.0.5 vfile: 6.0.3 @@ -15274,7 +14635,7 @@ snapshots: dependencies: debug: 4.4.3 module-details-from-path: 1.0.4 - resolve: 1.22.10 + resolve: 1.22.11 transitivePeerDependencies: - supports-color @@ -15299,12 +14660,6 @@ snapshots: postcss: 8.5.6 source-map: 0.6.1 - resolve@1.22.10: - dependencies: - is-core-module: 2.16.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - resolve@1.22.11: dependencies: is-core-module: 2.16.1 @@ -15336,32 +14691,35 @@ snapshots: hash-base: 3.1.2 inherits: 2.0.4 - rollup@4.52.2: + rollup@4.55.1: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.52.2 - '@rollup/rollup-android-arm64': 4.52.2 - '@rollup/rollup-darwin-arm64': 4.52.2 - '@rollup/rollup-darwin-x64': 4.52.2 - '@rollup/rollup-freebsd-arm64': 4.52.2 - '@rollup/rollup-freebsd-x64': 4.52.2 - '@rollup/rollup-linux-arm-gnueabihf': 4.52.2 - '@rollup/rollup-linux-arm-musleabihf': 4.52.2 - '@rollup/rollup-linux-arm64-gnu': 4.52.2 - '@rollup/rollup-linux-arm64-musl': 4.52.2 - '@rollup/rollup-linux-loong64-gnu': 4.52.2 - '@rollup/rollup-linux-ppc64-gnu': 4.52.2 - '@rollup/rollup-linux-riscv64-gnu': 4.52.2 - '@rollup/rollup-linux-riscv64-musl': 4.52.2 - '@rollup/rollup-linux-s390x-gnu': 4.52.2 - '@rollup/rollup-linux-x64-gnu': 4.52.2 - '@rollup/rollup-linux-x64-musl': 4.52.2 - '@rollup/rollup-openharmony-arm64': 4.52.2 - '@rollup/rollup-win32-arm64-msvc': 4.52.2 - '@rollup/rollup-win32-ia32-msvc': 4.52.2 - '@rollup/rollup-win32-x64-gnu': 4.52.2 - '@rollup/rollup-win32-x64-msvc': 4.52.2 + '@rollup/rollup-android-arm-eabi': 4.55.1 + '@rollup/rollup-android-arm64': 4.55.1 + '@rollup/rollup-darwin-arm64': 4.55.1 + '@rollup/rollup-darwin-x64': 4.55.1 + '@rollup/rollup-freebsd-arm64': 4.55.1 + '@rollup/rollup-freebsd-x64': 4.55.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.55.1 + '@rollup/rollup-linux-arm-musleabihf': 4.55.1 + '@rollup/rollup-linux-arm64-gnu': 4.55.1 + '@rollup/rollup-linux-arm64-musl': 4.55.1 + '@rollup/rollup-linux-loong64-gnu': 4.55.1 + '@rollup/rollup-linux-loong64-musl': 4.55.1 + '@rollup/rollup-linux-ppc64-gnu': 4.55.1 + '@rollup/rollup-linux-ppc64-musl': 4.55.1 + '@rollup/rollup-linux-riscv64-gnu': 4.55.1 + '@rollup/rollup-linux-riscv64-musl': 4.55.1 + '@rollup/rollup-linux-s390x-gnu': 4.55.1 + '@rollup/rollup-linux-x64-gnu': 4.55.1 + '@rollup/rollup-linux-x64-musl': 4.55.1 + '@rollup/rollup-openbsd-x64': 4.55.1 + '@rollup/rollup-openharmony-arm64': 4.55.1 + '@rollup/rollup-win32-arm64-msvc': 4.55.1 + '@rollup/rollup-win32-ia32-msvc': 4.55.1 + '@rollup/rollup-win32-x64-gnu': 4.55.1 + '@rollup/rollup-win32-x64-msvc': 4.55.1 fsevents: 2.3.3 run-parallel@1.2.0: @@ -15397,11 +14755,11 @@ snapshots: safe-stable-stringify@1.1.1: {} - sass-loader@16.0.5(webpack@5.101.3(esbuild@0.25.9)): + sass-loader@16.0.6(webpack@5.104.1(esbuild@0.25.12)): dependencies: neo-async: 2.6.2 optionalDependencies: - webpack: 5.101.3(esbuild@0.25.9) + webpack: 5.104.1(esbuild@0.25.12) scheduler@0.23.2: dependencies: @@ -15413,7 +14771,7 @@ snapshots: ajv: 6.12.6 ajv-keywords: 3.5.2(ajv@6.12.6) - schema-utils@4.3.2: + schema-utils@4.3.3: dependencies: '@types/json-schema': 7.0.15 ajv: 8.17.1 @@ -15422,8 +14780,6 @@ snapshots: semver@6.3.1: {} - semver@7.7.2: {} - semver@7.7.3: {} serialize-javascript@6.0.2: @@ -15460,36 +14816,36 @@ snapshots: safe-buffer: 5.2.1 to-buffer: 1.2.2 - shallowequal@1.1.0: {} - - sharp@0.34.3: + sharp@0.34.5: dependencies: - color: 4.2.3 - detect-libc: 2.0.4 + '@img/colour': 1.0.0 + detect-libc: 2.1.2 semver: 7.7.3 optionalDependencies: - '@img/sharp-darwin-arm64': 0.34.3 - '@img/sharp-darwin-x64': 0.34.3 - '@img/sharp-libvips-darwin-arm64': 1.2.0 - '@img/sharp-libvips-darwin-x64': 1.2.0 - '@img/sharp-libvips-linux-arm': 1.2.0 - '@img/sharp-libvips-linux-arm64': 1.2.0 - '@img/sharp-libvips-linux-ppc64': 1.2.0 - '@img/sharp-libvips-linux-s390x': 1.2.0 - '@img/sharp-libvips-linux-x64': 1.2.0 - '@img/sharp-libvips-linuxmusl-arm64': 1.2.0 - '@img/sharp-libvips-linuxmusl-x64': 1.2.0 - '@img/sharp-linux-arm': 0.34.3 - '@img/sharp-linux-arm64': 0.34.3 - '@img/sharp-linux-ppc64': 0.34.3 - '@img/sharp-linux-s390x': 0.34.3 - '@img/sharp-linux-x64': 0.34.3 - '@img/sharp-linuxmusl-arm64': 0.34.3 - '@img/sharp-linuxmusl-x64': 0.34.3 - '@img/sharp-wasm32': 0.34.3 - '@img/sharp-win32-arm64': 0.34.3 - '@img/sharp-win32-ia32': 0.34.3 - '@img/sharp-win32-x64': 0.34.3 + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 optional: true shebang-command@2.0.0: @@ -15502,7 +14858,7 @@ snapshots: shepherd.js@14.5.1: dependencies: - '@floating-ui/dom': 1.7.3 + '@floating-ui/dom': 1.7.4 '@scarf/scarf': 1.4.0 deepmerge-ts: 7.1.5 @@ -15568,11 +14924,6 @@ snapshots: dependencies: jsep: 1.4.0 - simple-swizzle@0.2.2: - dependencies: - is-arrayish: 0.3.2 - optional: true - slash@3.0.0: {} sonner@2.0.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1): @@ -15611,17 +14962,17 @@ snapshots: storybook@9.1.5(@testing-library/dom@10.4.1)(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3))(prettier@3.6.2): dependencies: '@storybook/global': 5.0.0 - '@testing-library/jest-dom': 6.8.0 + '@testing-library/jest-dom': 6.9.1 '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.1) '@vitest/expect': 3.2.4 '@vitest/mocker': 3.2.4(msw@2.11.6(@types/node@24.10.0)(typescript@5.9.3)) '@vitest/spy': 3.2.4 better-opn: 3.0.2 - esbuild: 0.25.9 - esbuild-register: 3.6.0(esbuild@0.25.9) + esbuild: 0.25.12 + esbuild-register: 3.6.0(esbuild@0.25.12) recast: 0.23.11 - semver: 7.7.2 - ws: 8.18.3 + semver: 7.7.3 + ws: 8.19.0 optionalDependencies: prettier: 3.6.2 transitivePeerDependencies: @@ -15664,14 +15015,14 @@ snapshots: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.1 string.prototype.matchall@4.0.12: dependencies: call-bind: 1.0.8 call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.1 es-errors: 1.3.0 es-object-atoms: 1.1.1 get-intrinsic: 1.3.0 @@ -15685,7 +15036,7 @@ snapshots: string.prototype.repeat@1.0.0: dependencies: define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.1 string.prototype.trim@1.2.10: dependencies: @@ -15693,7 +15044,7 @@ snapshots: call-bound: 1.0.4 define-data-property: 1.1.4 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.1 es-object-atoms: 1.1.1 has-property-descriptors: 1.0.2 @@ -15739,62 +15090,44 @@ snapshots: dependencies: min-indent: 1.0.1 - strip-indent@4.0.0: - dependencies: - min-indent: 1.0.1 + strip-indent@4.1.1: {} strip-json-comments@3.1.1: {} - style-loader@3.3.4(webpack@5.101.3(esbuild@0.25.9)): + style-loader@3.3.4(webpack@5.104.1(esbuild@0.25.12)): dependencies: - webpack: 5.101.3(esbuild@0.25.9) + webpack: 5.104.1(esbuild@0.25.12) - style-to-js@1.1.17: + style-to-js@1.1.21: dependencies: - style-to-object: 1.0.9 + style-to-object: 1.0.14 - style-to-object@1.0.9: + style-to-object@1.0.14: dependencies: - inline-style-parser: 0.2.4 + inline-style-parser: 0.2.7 - styled-components@6.1.19(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - '@emotion/is-prop-valid': 1.2.2 - '@emotion/unitless': 0.8.1 - '@types/stylis': 4.2.5 - css-to-react-native: 3.2.0 - csstype: 3.1.3 - postcss: 8.4.49 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - shallowequal: 1.1.0 - stylis: 4.3.2 - tslib: 2.6.2 - - styled-jsx@5.1.6(@babel/core@7.28.4)(react@18.3.1): + styled-jsx@5.1.6(@babel/core@7.28.5)(react@18.3.1): dependencies: client-only: 0.0.1 react: 18.3.1 optionalDependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 - styled-jsx@5.1.7(@babel/core@7.28.4)(react@18.3.1): + styled-jsx@5.1.7(@babel/core@7.28.5)(react@18.3.1): dependencies: client-only: 0.0.1 react: 18.3.1 optionalDependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 - stylis@4.3.2: {} - - sucrase@3.35.0: + sucrase@3.35.1: dependencies: '@jridgewell/gen-mapping': 0.3.13 commander: 4.1.1 - glob: 10.4.5 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: @@ -15851,29 +15184,29 @@ snapshots: picocolors: 1.1.1 postcss: 8.5.6 postcss-import: 15.1.0(postcss@8.5.6) - postcss-js: 4.0.1(postcss@8.5.6) + postcss-js: 4.1.0(postcss@8.5.6) postcss-load-config: 4.0.2(postcss@8.5.6) postcss-nested: 6.2.0(postcss@8.5.6) postcss-selector-parser: 6.1.2 - resolve: 1.22.10 - sucrase: 3.35.0 + resolve: 1.22.11 + sucrase: 3.35.1 transitivePeerDependencies: - ts-node - tapable@2.2.3: {} + tapable@2.3.0: {} - terser-webpack-plugin@5.3.14(esbuild@0.25.9)(webpack@5.101.3(esbuild@0.25.9)): + terser-webpack-plugin@5.3.16(esbuild@0.25.12)(webpack@5.104.1(esbuild@0.25.12)): dependencies: - '@jridgewell/trace-mapping': 0.3.30 + '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 - schema-utils: 4.3.2 + schema-utils: 4.3.3 serialize-javascript: 6.0.2 - terser: 5.44.0 - webpack: 5.101.3(esbuild@0.25.9) + terser: 5.44.1 + webpack: 5.104.1(esbuild@0.25.12) optionalDependencies: - esbuild: 0.25.9 + esbuild: 0.25.12 - terser@5.44.0: + terser@5.44.1: dependencies: '@jridgewell/source-map': 0.3.11 acorn: 8.15.0 @@ -15905,13 +15238,13 @@ snapshots: tinyrainbow@2.0.0: {} - tinyspy@4.0.3: {} + tinyspy@4.0.4: {} - tldts-core@7.0.17: {} + tldts-core@7.0.19: {} - tldts@7.0.17: + tldts@7.0.19: dependencies: - tldts-core: 7.0.17 + tldts-core: 7.0.19 to-buffer@1.2.2: dependencies: @@ -15925,7 +15258,7 @@ snapshots: tough-cookie@6.0.0: dependencies: - tldts: 7.0.17 + tldts: 7.0.19 tr46@0.0.3: {} @@ -15935,7 +15268,7 @@ snapshots: trough@2.2.0: {} - ts-api-utils@2.1.0(typescript@5.9.3): + ts-api-utils@2.4.0(typescript@5.9.3): dependencies: typescript: 5.9.3 @@ -15950,8 +15283,8 @@ snapshots: tsconfig-paths-webpack-plugin@4.2.0: dependencies: chalk: 4.1.2 - enhanced-resolve: 5.18.3 - tapable: 2.2.3 + enhanced-resolve: 5.18.4 + tapable: 2.3.0 tsconfig-paths: 4.2.0 tsconfig-paths@3.15.0: @@ -15969,8 +15302,6 @@ snapshots: tslib@1.14.1: {} - tslib@2.6.2: {} - tslib@2.8.1: {} tty-browserify@0.0.1: {} @@ -16020,22 +15351,22 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 - typedoc-plugin-coverage@4.0.2(typedoc@0.28.14(typescript@5.9.3)): + typedoc-plugin-coverage@4.0.2(typedoc@0.28.15(typescript@5.9.3)): dependencies: - typedoc: 0.28.14(typescript@5.9.3) + typedoc: 0.28.15(typescript@5.9.3) - typedoc-plugin-markdown@4.9.0(typedoc@0.28.14(typescript@5.9.3)): + typedoc-plugin-markdown@4.9.0(typedoc@0.28.15(typescript@5.9.3)): dependencies: - typedoc: 0.28.14(typescript@5.9.3) + typedoc: 0.28.15(typescript@5.9.3) - typedoc@0.28.14(typescript@5.9.3): + typedoc@0.28.15(typescript@5.9.3): dependencies: - '@gerrit0/mini-shiki': 3.14.0 + '@gerrit0/mini-shiki': 3.20.0 lunr: 2.3.9 markdown-it: 14.1.0 minimatch: 9.0.5 typescript: 5.9.3 - yaml: 2.8.1 + yaml: 2.8.2 typescript@5.9.3: {} @@ -16055,11 +15386,11 @@ snapshots: unicode-match-property-ecmascript@2.0.0: dependencies: unicode-canonical-property-names-ecmascript: 2.0.1 - unicode-property-aliases-ecmascript: 2.1.0 + unicode-property-aliases-ecmascript: 2.2.0 - unicode-match-property-value-ecmascript@2.2.0: {} + unicode-match-property-value-ecmascript@2.2.1: {} - unicode-property-aliases-ecmascript@2.1.0: {} + unicode-property-aliases-ecmascript@2.2.0: {} unicorn-magic@0.1.0: {} @@ -16076,9 +15407,9 @@ snapshots: unist-util-find-after@5.0.0: dependencies: '@types/unist': 3.0.3 - unist-util-is: 6.0.0 + unist-util-is: 6.0.1 - unist-util-is@6.0.0: + unist-util-is@6.0.1: dependencies: '@types/unist': 3.0.3 @@ -16095,16 +15426,16 @@ snapshots: dependencies: '@types/unist': 3.0.3 - unist-util-visit-parents@6.0.1: + unist-util-visit-parents@6.0.2: dependencies: '@types/unist': 3.0.3 - unist-util-is: 6.0.0 + unist-util-is: 6.0.1 unist-util-visit@5.0.0: dependencies: '@types/unist': 3.0.3 - unist-util-is: 6.0.0 - unist-util-visit-parents: 6.0.1 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 universalify@2.0.1: {} @@ -16146,9 +15477,9 @@ snapshots: until-async@3.0.2: {} - update-browserslist-db@1.1.3(browserslist@4.25.4): + update-browserslist-db@1.2.3(browserslist@4.28.1): dependencies: - browserslist: 4.25.4 + browserslist: 4.28.1 escalade: 3.2.0 picocolors: 1.1.1 @@ -16161,7 +15492,7 @@ snapshots: url@0.11.4: dependencies: punycode: 1.4.1 - qs: 6.14.0 + qs: 6.14.1 use-callback-ref@1.3.3(@types/react@18.3.17)(react@18.3.1): dependencies: @@ -16178,7 +15509,7 @@ snapshots: optionalDependencies: '@types/react': 18.3.17 - use-sync-external-store@1.5.0(react@18.3.1): + use-sync-external-store@1.6.0(react@18.3.1): dependencies: react: 18.3.1 @@ -16188,7 +15519,7 @@ snapshots: dependencies: inherits: 2.0.4 is-arguments: 1.2.0 - is-generator-function: 1.1.0 + is-generator-function: 1.1.2 is-typed-array: 1.1.15 which-typed-array: 1.1.19 @@ -16202,22 +15533,7 @@ snapshots: uuid@9.0.1: {} - validate.io-array@1.0.6: {} - - validate.io-function@1.0.2: {} - - validate.io-integer-array@1.0.0: - dependencies: - validate.io-array: 1.0.6 - validate.io-integer: 1.0.5 - - validate.io-integer@1.0.5: - dependencies: - validate.io-number: 1.0.3 - - validate.io-number@1.0.3: {} - - validator@13.15.20: {} + validator@13.15.26: {} vaul@1.1.2(@types/react-dom@18.3.5(@types/react@18.3.17))(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: @@ -16245,7 +15561,7 @@ snapshots: victory-vendor@37.3.6: dependencies: - '@types/d3-array': 3.2.1 + '@types/d3-array': 3.2.2 '@types/d3-ease': 3.0.2 '@types/d3-interpolate': 3.0.4 '@types/d3-scale': 4.0.9 @@ -16266,7 +15582,7 @@ snapshots: dependencies: loose-envify: 1.4.0 - watchpack@2.4.4: + watchpack@2.5.0: dependencies: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 @@ -16275,15 +15591,15 @@ snapshots: webidl-conversions@3.0.1: {} - webpack-dev-middleware@6.1.3(webpack@5.101.3(esbuild@0.25.9)): + webpack-dev-middleware@6.1.3(webpack@5.104.1(esbuild@0.25.12)): dependencies: colorette: 2.0.20 memfs: 3.5.3 mime-types: 2.1.35 range-parser: 1.2.1 - schema-utils: 4.3.2 + schema-utils: 4.3.3 optionalDependencies: - webpack: 5.101.3(esbuild@0.25.9) + webpack: 5.104.1(esbuild@0.25.12) webpack-hot-middleware@2.26.1: dependencies: @@ -16297,7 +15613,7 @@ snapshots: webpack-virtual-modules@0.6.2: {} - webpack@5.101.3(esbuild@0.25.9): + webpack@5.104.1(esbuild@0.25.12): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.8 @@ -16307,22 +15623,22 @@ snapshots: '@webassemblyjs/wasm-parser': 1.14.1 acorn: 8.15.0 acorn-import-phases: 1.0.4(acorn@8.15.0) - browserslist: 4.25.4 + browserslist: 4.28.1 chrome-trace-event: 1.0.4 - enhanced-resolve: 5.18.3 - es-module-lexer: 1.7.0 + enhanced-resolve: 5.18.4 + es-module-lexer: 2.0.0 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.0 + loader-runner: 4.3.1 mime-types: 2.1.35 neo-async: 2.6.2 - schema-utils: 4.3.2 - tapable: 2.2.3 - terser-webpack-plugin: 5.3.14(esbuild@0.25.9)(webpack@5.101.3(esbuild@0.25.9)) - watchpack: 2.4.4 + schema-utils: 4.3.3 + tapable: 2.3.0 + terser-webpack-plugin: 5.3.16(esbuild@0.25.12)(webpack@5.104.1(esbuild@0.25.12)) + watchpack: 2.5.0 webpack-sources: 3.3.3 transitivePeerDependencies: - '@swc/core' @@ -16401,7 +15717,7 @@ snapshots: wrappy@1.0.2: {} - ws@8.18.3: {} + ws@8.19.0: {} xmlbuilder@15.1.1: {} @@ -16413,7 +15729,7 @@ snapshots: yaml@1.10.2: {} - yaml@2.8.1: {} + yaml@2.8.2: {} yargs-parser@21.1.1: {} @@ -16429,25 +15745,25 @@ snapshots: yocto-queue@0.1.0: {} - yocto-queue@1.2.1: {} + yocto-queue@1.2.2: {} yoctocolors-cjs@2.1.3: {} zod@3.25.76: {} - zustand@4.5.7(@types/react@18.3.17)(immer@10.1.3)(react@18.3.1): + zustand@4.5.7(@types/react@18.3.17)(immer@11.1.3)(react@18.3.1): dependencies: - use-sync-external-store: 1.5.0(react@18.3.1) + use-sync-external-store: 1.6.0(react@18.3.1) optionalDependencies: '@types/react': 18.3.17 - immer: 10.1.3 + immer: 11.1.3 react: 18.3.1 - zustand@5.0.8(@types/react@18.3.17)(immer@10.1.3)(react@18.3.1)(use-sync-external-store@1.5.0(react@18.3.1)): + zustand@5.0.8(@types/react@18.3.17)(immer@11.1.3)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)): optionalDependencies: '@types/react': 18.3.17 - immer: 10.1.3 + immer: 11.1.3 react: 18.3.1 - use-sync-external-store: 1.5.0(react@18.3.1) + use-sync-external-store: 1.6.0(react@18.3.1) zwitch@2.0.4: {} diff --git a/autogpt_platform/frontend/public/integrations/webshare_proxy.png b/autogpt_platform/frontend/public/integrations/webshare_proxy.png new file mode 100644 index 0000000000..2b07ef8415 Binary files /dev/null and b/autogpt_platform/frontend/public/integrations/webshare_proxy.png differ diff --git a/autogpt_platform/frontend/public/integrations/wordpress.png b/autogpt_platform/frontend/public/integrations/wordpress.png new file mode 100644 index 0000000000..b8ba8bd3ff Binary files /dev/null and b/autogpt_platform/frontend/public/integrations/wordpress.png differ diff --git a/autogpt_platform/frontend/src/app/(platform)/auth/integrations/oauth_callback/route.ts b/autogpt_platform/frontend/src/app/(platform)/auth/integrations/oauth_callback/route.ts index df1de26300..41d05a9afb 100644 --- a/autogpt_platform/frontend/src/app/(platform)/auth/integrations/oauth_callback/route.ts +++ b/autogpt_platform/frontend/src/app/(platform)/auth/integrations/oauth_callback/route.ts @@ -1,4 +1,4 @@ -import { OAuthPopupResultMessage } from "@/components/renderers/input-renderer/fields/CredentialField/models/OAuthCredentialModal/useOAuthCredentialModal"; +import { OAuthPopupResultMessage } from "./types"; import { NextResponse } from "next/server"; // This route is intended to be used as the callback for integration OAuth flows, diff --git a/autogpt_platform/frontend/src/app/(platform)/auth/integrations/oauth_callback/types.ts b/autogpt_platform/frontend/src/app/(platform)/auth/integrations/oauth_callback/types.ts new file mode 100644 index 0000000000..9000adf392 --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/auth/integrations/oauth_callback/types.ts @@ -0,0 +1,11 @@ +export type OAuthPopupResultMessage = { message_type: "oauth_popup_result" } & ( + | { + success: true; + code: string; + state: string; + } + | { + success: false; + message: string; + } +); diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/BuilderActions/components/RunInputDialog/RunInputDialog.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/BuilderActions/components/RunInputDialog/RunInputDialog.tsx index 2d9f51c8bf..bd08aa8ee0 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/BuilderActions/components/RunInputDialog/RunInputDialog.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/BuilderActions/components/RunInputDialog/RunInputDialog.tsx @@ -5,7 +5,7 @@ import { useGraphStore } from "@/app/(platform)/build/stores/graphStore"; import { Button } from "@/components/atoms/Button/Button"; import { ClockIcon, PlayIcon } from "@phosphor-icons/react"; import { Text } from "@/components/atoms/Text/Text"; -import { FormRenderer } from "@/components/renderers/input-renderer/FormRenderer"; +import { FormRenderer } from "@/components/renderers/InputRenderer/FormRenderer"; import { useRunInputDialog } from "./useRunInputDialog"; import { CronSchedulerDialog } from "../CronSchedulerDialog/CronSchedulerDialog"; @@ -66,6 +66,7 @@ export const RunInputDialog = ({ formContext={{ showHandles: false, size: "large", + showOptionalToggle: false, }} /> diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/BuilderActions/components/RunInputDialog/useRunInputDialog.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/BuilderActions/components/RunInputDialog/useRunInputDialog.ts index f0bb3b1c98..ddd77bae48 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/BuilderActions/components/RunInputDialog/useRunInputDialog.ts +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/BuilderActions/components/RunInputDialog/useRunInputDialog.ts @@ -8,7 +8,7 @@ import { import { parseAsInteger, parseAsString, useQueryStates } from "nuqs"; import { useMemo, useState } from "react"; import { uiSchema } from "../../../FlowEditor/nodes/uiSchema"; -import { isCredentialFieldSchema } from "@/components/renderers/input-renderer/fields/CredentialField/helpers"; +import { isCredentialFieldSchema } from "@/components/renderers/InputRenderer/custom/CredentialField/helpers"; export const useRunInputDialog = ({ setIsOpen, @@ -66,7 +66,7 @@ export const useRunInputDialog = ({ if (isCredentialFieldSchema(fieldSchema)) { dynamicUiSchema[fieldName] = { ...dynamicUiSchema[fieldName], - "ui:field": "credentials", + "ui:field": "custom/credential_field", }; } }); @@ -76,12 +76,18 @@ export const useRunInputDialog = ({ }, [credentialsSchema]); const handleManualRun = async () => { + // Filter out incomplete credentials (those without a valid id) + // RJSF auto-populates const values (provider, type) but not id field + const validCredentials = Object.fromEntries( + Object.entries(credentialValues).filter(([_, cred]) => cred && cred.id), + ); + await executeGraph({ graphId: flowID ?? "", graphVersion: flowVersion || null, data: { inputs: inputValues, - credentials_inputs: credentialValues, + credentials_inputs: validCredentials, source: "builder", }, }); diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/DraftRecoveryDialog/DraftRecoveryPopup.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/DraftRecoveryDialog/DraftRecoveryPopup.tsx index 520addd50f..905d1d4680 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/DraftRecoveryDialog/DraftRecoveryPopup.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/DraftRecoveryDialog/DraftRecoveryPopup.tsx @@ -12,16 +12,59 @@ import { import { useDraftRecoveryPopup } from "./useDraftRecoveryPopup"; import { Text } from "@/components/atoms/Text/Text"; import { AnimatePresence, motion } from "framer-motion"; +import { DraftDiff } from "@/lib/dexie/draft-utils"; interface DraftRecoveryPopupProps { isInitialLoadComplete: boolean; } +function formatDiffSummary(diff: DraftDiff | null): string { + if (!diff) return ""; + + const parts: string[] = []; + + // Node changes + const nodeChanges: string[] = []; + if (diff.nodes.added > 0) nodeChanges.push(`+${diff.nodes.added}`); + if (diff.nodes.removed > 0) nodeChanges.push(`-${diff.nodes.removed}`); + if (diff.nodes.modified > 0) nodeChanges.push(`~${diff.nodes.modified}`); + + if (nodeChanges.length > 0) { + parts.push( + `${nodeChanges.join("/")} block${diff.nodes.added + diff.nodes.removed + diff.nodes.modified !== 1 ? "s" : ""}`, + ); + } + + // Edge changes + const edgeChanges: string[] = []; + if (diff.edges.added > 0) edgeChanges.push(`+${diff.edges.added}`); + if (diff.edges.removed > 0) edgeChanges.push(`-${diff.edges.removed}`); + if (diff.edges.modified > 0) edgeChanges.push(`~${diff.edges.modified}`); + + if (edgeChanges.length > 0) { + parts.push( + `${edgeChanges.join("/")} connection${diff.edges.added + diff.edges.removed + diff.edges.modified !== 1 ? "s" : ""}`, + ); + } + + return parts.join(", "); +} + export function DraftRecoveryPopup({ isInitialLoadComplete, }: DraftRecoveryPopupProps) { - const { isOpen, popupRef, nodeCount, edgeCount, savedAt, onLoad, onDiscard } = - useDraftRecoveryPopup(isInitialLoadComplete); + const { + isOpen, + popupRef, + nodeCount, + edgeCount, + diff, + savedAt, + onLoad, + onDiscard, + } = useDraftRecoveryPopup(isInitialLoadComplete); + + const diffSummary = formatDiffSummary(diff); return ( @@ -72,10 +115,9 @@ export function DraftRecoveryPopup({ variant="small" className="text-amber-700 dark:text-amber-400" > - {nodeCount} block{nodeCount !== 1 ? "s" : ""}, {edgeCount}{" "} - connection - {edgeCount !== 1 ? "s" : ""} •{" "} - {formatTimeAgo(new Date(savedAt).toISOString())} + {diffSummary || + `${nodeCount} block${nodeCount !== 1 ? "s" : ""}, ${edgeCount} connection${edgeCount !== 1 ? "s" : ""}`}{" "} + • {formatTimeAgo(new Date(savedAt).toISOString())} diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/DraftRecoveryDialog/useDraftRecoveryPopup.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/DraftRecoveryDialog/useDraftRecoveryPopup.tsx index 0914b04952..7a77f7b4cc 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/DraftRecoveryDialog/useDraftRecoveryPopup.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/DraftRecoveryDialog/useDraftRecoveryPopup.tsx @@ -9,6 +9,7 @@ export const useDraftRecoveryPopup = (isInitialLoadComplete: boolean) => { savedAt, nodeCount, edgeCount, + diff, loadDraft: onLoad, discardDraft: onDiscard, } = useDraftManager(isInitialLoadComplete); @@ -54,6 +55,7 @@ export const useDraftRecoveryPopup = (isInitialLoadComplete: boolean) => { isOpen, nodeCount, edgeCount, + diff, savedAt, onLoad, onDiscard, diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/Flow.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/Flow.tsx index faaebb6b35..29fd984b1d 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/Flow.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/Flow.tsx @@ -97,6 +97,9 @@ export const Flow = () => { onConnect={onConnect} onEdgesChange={onEdgesChange} onNodeDragStop={onNodeDragStop} + onNodeContextMenu={(event) => { + event.preventDefault(); + }} maxZoom={2} minZoom={0.1} onDragOver={onDragOver} diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/helpers/resolve-collision.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/helpers/resolve-collision.ts index c05f00b5fb..890d1982c8 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/helpers/resolve-collision.ts +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/helpers/resolve-collision.ts @@ -48,8 +48,6 @@ export const resolveCollisions: CollisionAlgorithm = ( const width = (node.width ?? node.measured?.width ?? 0) + margin * 2; const height = (node.height ?? node.measured?.height ?? 0) + margin * 2; - console.log("width", width); - console.log("height", height); const x = node.position.x - margin; const y = node.position.y - margin; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/useDraftManager.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/useDraftManager.ts index f6d03923bd..a38def74f6 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/useDraftManager.ts +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/useDraftManager.ts @@ -7,7 +7,12 @@ import { DraftData, } from "@/services/builder-draft/draft-service"; import { BuilderDraft } from "@/lib/dexie/db"; -import { cleanNodes, cleanEdges } from "@/lib/dexie/draft-utils"; +import { + cleanNodes, + cleanEdges, + calculateDraftDiff, + DraftDiff, +} from "@/lib/dexie/draft-utils"; import { useNodeStore } from "../../../stores/nodeStore"; import { useEdgeStore } from "../../../stores/edgeStore"; import { useGraphStore } from "../../../stores/graphStore"; @@ -19,6 +24,7 @@ const AUTO_SAVE_INTERVAL_MS = 15000; // 15 seconds interface DraftRecoveryState { isOpen: boolean; draft: BuilderDraft | null; + diff: DraftDiff | null; } /** @@ -31,6 +37,7 @@ export function useDraftManager(isInitialLoadComplete: boolean) { const [state, setState] = useState({ isOpen: false, draft: null, + diff: null, }); const [{ flowID, flowVersion }] = useQueryStates({ @@ -207,9 +214,16 @@ export function useDraftManager(isInitialLoadComplete: boolean) { ); if (isDifferent && (draft.nodes.length > 0 || draft.edges.length > 0)) { + const diff = calculateDraftDiff( + draft.nodes, + draft.edges, + currentNodes, + currentEdges, + ); setState({ isOpen: true, draft, + diff, }); } else { await draftService.deleteDraft(effectiveFlowId); @@ -231,6 +245,7 @@ export function useDraftManager(isInitialLoadComplete: boolean) { setState({ isOpen: false, draft: null, + diff: null, }); }, [flowID]); @@ -242,8 +257,10 @@ export function useDraftManager(isInitialLoadComplete: boolean) { try { useNodeStore.getState().setNodes(draft.nodes); useEdgeStore.getState().setEdges(draft.edges); + draft.nodes.forEach((node) => { + useNodeStore.getState().syncHardcodedValuesWithHandleIds(node.id); + }); - // Restore nodeCounter to prevent ID conflicts when adding new nodes if (draft.nodeCounter !== undefined) { useNodeStore.setState({ nodeCounter: draft.nodeCounter }); } @@ -267,6 +284,7 @@ export function useDraftManager(isInitialLoadComplete: boolean) { setState({ isOpen: false, draft: null, + diff: null, }); } catch (error) { console.error("[DraftRecovery] Failed to load draft:", error); @@ -275,7 +293,7 @@ export function useDraftManager(isInitialLoadComplete: boolean) { const discardDraft = useCallback(async () => { if (!state.draft) { - setState({ isOpen: false, draft: null }); + setState({ isOpen: false, draft: null, diff: null }); return; } @@ -285,7 +303,7 @@ export function useDraftManager(isInitialLoadComplete: boolean) { console.error("[DraftRecovery] Failed to discard draft:", error); } - setState({ isOpen: false, draft: null }); + setState({ isOpen: false, draft: null, diff: null }); }, [state.draft]); return { @@ -294,6 +312,7 @@ export function useDraftManager(isInitialLoadComplete: boolean) { savedAt: state.draft?.savedAt ?? 0, nodeCount: state.draft?.nodes.length ?? 0, edgeCount: state.draft?.edges.length ?? 0, + diff: state.diff, loadDraft, discardDraft, }; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/useFlow.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/useFlow.ts index 7514611f08..407482073f 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/useFlow.ts +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/useFlow.ts @@ -121,6 +121,14 @@ export const useFlow = () => { if (customNodes.length > 0) { useNodeStore.getState().setNodes([]); addNodes(customNodes); + + // Sync hardcoded values with handle IDs. + // If a key–value field has a key without a value, the backend omits it from hardcoded values. + // But if a handleId exists for that key, it causes inconsistency. + // This ensures hardcoded values stay in sync with handle IDs. + customNodes.forEach((node) => { + useNodeStore.getState().syncHardcodedValuesWithHandleIds(node.id); + }); } }, [customNodes, addNodes]); diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/edges/useCustomEdge.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/edges/useCustomEdge.ts index 8d27f346ef..bf4ba3a418 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/edges/useCustomEdge.ts +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/edges/useCustomEdge.ts @@ -1,12 +1,17 @@ -import { Connection as RFConnection, EdgeChange } from "@xyflow/react"; +import { + Connection as RFConnection, + EdgeChange, + applyEdgeChanges, +} from "@xyflow/react"; import { useEdgeStore } from "@/app/(platform)/build/stores/edgeStore"; import { useCallback } from "react"; import { useNodeStore } from "../../../stores/nodeStore"; +import { CustomEdge } from "./CustomEdge"; export const useCustomEdge = () => { const edges = useEdgeStore((s) => s.edges); const addEdge = useEdgeStore((s) => s.addEdge); - const removeEdge = useEdgeStore((s) => s.removeEdge); + const setEdges = useEdgeStore((s) => s.setEdges); const onConnect = useCallback( (conn: RFConnection) => { @@ -45,14 +50,10 @@ export const useCustomEdge = () => { ); const onEdgesChange = useCallback( - (changes: EdgeChange[]) => { - changes.forEach((change) => { - if (change.type === "remove") { - removeEdge(change.id); - } - }); + (changes: EdgeChange[]) => { + setEdges(applyEdgeChanges(changes, edges)); }, - [removeEdge], + [edges, setEdges], ); return { edges, onConnect, onEdgesChange }; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/handlers/NodeHandle.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/handlers/NodeHandle.tsx index 4eb2437b65..99edb00c45 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/handlers/NodeHandle.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/handlers/NodeHandle.tsx @@ -1,26 +1,32 @@ import { CircleIcon } from "@phosphor-icons/react"; import { Handle, Position } from "@xyflow/react"; +import { useEdgeStore } from "../../../stores/edgeStore"; +import { cleanUpHandleId } from "@/components/renderers/InputRenderer/helpers"; +import { cn } from "@/lib/utils"; -const NodeHandle = ({ +const InputNodeHandle = ({ handleId, - isConnected, - side, + nodeId, }: { handleId: string; - isConnected: boolean; - side: "left" | "right"; + nodeId: string; }) => { + const cleanedHandleId = cleanUpHandleId(handleId); + const isInputConnected = useEdgeStore((state) => + state.isInputConnected(nodeId ?? "", cleanedHandleId), + ); + return (
@@ -28,4 +34,35 @@ const NodeHandle = ({ ); }; -export default NodeHandle; +const OutputNodeHandle = ({ + field_name, + nodeId, + hexColor, +}: { + field_name: string; + nodeId: string; + hexColor: string; +}) => { + const isOutputConnected = useEdgeStore((state) => + state.isOutputConnected(nodeId, field_name), + ); + return ( + +
+ +
+
+ ); +}; + +export { InputNodeHandle, OutputNodeHandle }; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/handlers/helpers.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/handlers/helpers.ts index ecacc83146..afaa85a38a 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/handlers/helpers.ts +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/handlers/helpers.ts @@ -1,31 +1,4 @@ -/** - * Handle ID Types for different input structures - * - * Examples: - * SIMPLE: "message" - * NESTED: "config.api_key" - * ARRAY: "items_$_0", "items_$_1" - * KEY_VALUE: "headers_#_Authorization", "params_#_limit" - * - * Note: All handle IDs are sanitized to remove spaces and special characters. - * Spaces become underscores, and special characters are removed. - * Example: "user name" becomes "user_name", "email@domain.com" becomes "emaildomaincom" - */ -export enum HandleIdType { - SIMPLE = "SIMPLE", - NESTED = "NESTED", - ARRAY = "ARRAY", - KEY_VALUE = "KEY_VALUE", -} - -const fromRjsfId = (id: string): string => { - if (!id) return ""; - const parts = id.split("_"); - const filtered = parts.filter( - (p) => p !== "root" && p !== "properties" && p.length > 0, - ); - return filtered.join("_") || ""; -}; +// Here we are handling single level of nesting, if need more in future then i will update it const sanitizeForHandleId = (str: string): string => { if (!str) return ""; @@ -38,51 +11,53 @@ const sanitizeForHandleId = (str: string): string => { .replace(/^_|_$/g, ""); // Remove leading/trailing underscores }; -export const generateHandleId = ( +const cleanTitleId = (id: string): string => { + if (!id) return ""; + + if (id.endsWith("_title")) { + id = id.slice(0, -6); + } + const parts = id.split("_"); + const filtered = parts.filter( + (p) => p !== "root" && p !== "properties" && p.length > 0, + ); + const filtered_id = filtered.join("_") || ""; + return filtered_id; +}; + +export const generateHandleIdFromTitleId = ( fieldKey: string, - nestedValues: string[] = [], - type: HandleIdType = HandleIdType.SIMPLE, + { + isObjectProperty, + isAdditionalProperty, + isArrayItem, + }: { + isArrayItem?: boolean; + isObjectProperty?: boolean; + isAdditionalProperty?: boolean; + } = { + isArrayItem: false, + isObjectProperty: false, + isAdditionalProperty: false, + }, ): string => { if (!fieldKey) return ""; - fieldKey = fromRjsfId(fieldKey); - fieldKey = sanitizeForHandleId(fieldKey); + const filteredKey = cleanTitleId(fieldKey); + if (isAdditionalProperty || isArrayItem) { + return filteredKey; + } + const cleanedKey = sanitizeForHandleId(filteredKey); - if (type === HandleIdType.SIMPLE || nestedValues.length === 0) { - return fieldKey; + if (isObjectProperty) { + // "config_api_key" -> "config.api_key" + const parts = cleanedKey.split("_"); + if (parts.length >= 2) { + const baseName = parts[0]; + const propertyName = parts.slice(1).join("_"); + return `${baseName}.${propertyName}`; + } } - const sanitizedNestedValues = nestedValues.map((value) => - sanitizeForHandleId(value), - ); - - switch (type) { - case HandleIdType.NESTED: - return [fieldKey, ...sanitizedNestedValues].join("."); - - case HandleIdType.ARRAY: - return [fieldKey, ...sanitizedNestedValues].join("_$_"); - - case HandleIdType.KEY_VALUE: - return [fieldKey, ...sanitizedNestedValues].join("_#_"); - - default: - return fieldKey; - } -}; - -export const parseKeyValueHandleId = ( - handleId: string, - type: HandleIdType, -): string => { - if (type === HandleIdType.KEY_VALUE) { - return handleId.split("_#_")[1]; - } else if (type === HandleIdType.ARRAY) { - return handleId.split("_$_")[1]; - } else if (type === HandleIdType.NESTED) { - return handleId.split(".")[1]; - } else if (type === HandleIdType.SIMPLE) { - return handleId.split("_")[1]; - } - return ""; + return cleanedKey; }; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/CustomNode.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/CustomNode.tsx index 52068f3acb..99a5b9f0e5 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/CustomNode.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/CustomNode.tsx @@ -1,24 +1,25 @@ -import React from "react"; -import { Node as XYNode, NodeProps } from "@xyflow/react"; -import { RJSFSchema } from "@rjsf/utils"; -import { BlockUIType } from "../../../types"; -import { StickyNoteBlock } from "./components/StickyNoteBlock"; -import { BlockInfoCategoriesItem } from "@/app/api/__generated__/models/blockInfoCategoriesItem"; -import { BlockCost } from "@/app/api/__generated__/models/blockCost"; import { AgentExecutionStatus } from "@/app/api/__generated__/models/agentExecutionStatus"; +import { BlockCost } from "@/app/api/__generated__/models/blockCost"; +import { BlockInfoCategoriesItem } from "@/app/api/__generated__/models/blockInfoCategoriesItem"; import { NodeExecutionResult } from "@/app/api/__generated__/models/nodeExecutionResult"; -import { NodeContainer } from "./components/NodeContainer"; -import { NodeHeader } from "./components/NodeHeader"; -import { FormCreator } from "../FormCreator"; -import { preprocessInputSchema } from "@/components/renderers/input-renderer/utils/input-schema-pre-processor"; -import { OutputHandler } from "../OutputHandler"; -import { NodeAdvancedToggle } from "./components/NodeAdvancedToggle"; -import { NodeDataRenderer } from "./components/NodeOutput/NodeOutput"; -import { NodeExecutionBadge } from "./components/NodeExecutionBadge"; -import { cn } from "@/lib/utils"; -import { WebhookDisclaimer } from "./components/WebhookDisclaimer"; -import { AyrshareConnectButton } from "./components/AyrshareConnectButton"; import { NodeModelMetadata } from "@/app/api/__generated__/models/nodeModelMetadata"; +import { preprocessInputSchema } from "@/components/renderers/InputRenderer/utils/input-schema-pre-processor"; +import { cn } from "@/lib/utils"; +import { RJSFSchema } from "@rjsf/utils"; +import { NodeProps, Node as XYNode } from "@xyflow/react"; +import React from "react"; +import { BlockUIType } from "../../../types"; +import { FormCreator } from "../FormCreator"; +import { OutputHandler } from "../OutputHandler"; +import { AyrshareConnectButton } from "./components/AyrshareConnectButton"; +import { NodeAdvancedToggle } from "./components/NodeAdvancedToggle"; +import { NodeContainer } from "./components/NodeContainer"; +import { NodeExecutionBadge } from "./components/NodeExecutionBadge"; +import { NodeHeader } from "./components/NodeHeader"; +import { NodeDataRenderer } from "./components/NodeOutput/NodeOutput"; +import { NodeRightClickMenu } from "./components/NodeRightClickMenu"; +import { StickyNoteBlock } from "./components/StickyNoteBlock"; +import { WebhookDisclaimer } from "./components/WebhookDisclaimer"; export type CustomNodeData = { hardcodedValues: { @@ -88,7 +89,7 @@ export const CustomNode: React.FC> = React.memo( // Currently all blockTypes design are similar - that's why i am using the same component for all of them // If in future - if we need some drastic change in some blockTypes design - we can create separate components for them - return ( + const node = (
@@ -99,7 +100,7 @@ export const CustomNode: React.FC> = React.memo( nodeId={nodeId} uiType={data.uiType} className={cn( - "bg-white pr-6", + "bg-white px-4", isWebhook && "pointer-events-none opacity-50", )} showHandles={showHandles} @@ -117,6 +118,15 @@ export const CustomNode: React.FC> = React.memo( ); + + return ( + + {node} + + ); }, ); diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeAdvancedToggle.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeAdvancedToggle.tsx index 4903f2e020..950db1657f 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeAdvancedToggle.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeAdvancedToggle.tsx @@ -8,7 +8,7 @@ export const NodeAdvancedToggle = ({ nodeId }: { nodeId: string }) => { ); const setShowAdvanced = useNodeStore((state) => state.setShowAdvanced); return ( -
+
Advanced diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeContainer.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeContainer.tsx index f8d5b2e089..da9c13335f 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeContainer.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeContainer.tsx @@ -22,7 +22,7 @@ export const NodeContainer = ({ return (
{ +}; + +export const NodeContextMenu = ({ nodeId, subGraphID }: Props) => { const { deleteElements } = useReactFlow(); - const handleCopy = () => { + function handleCopy() { useNodeStore.setState((state) => ({ nodes: state.nodes.map((node) => ({ ...node, @@ -30,47 +35,47 @@ export const NodeContextMenu = ({ useCopyPasteStore.getState().copySelectedNodes(); useCopyPasteStore.getState().pasteNodes(); - }; + } - const handleDelete = () => { + function handleDelete() { deleteElements({ nodes: [{ id: nodeId }] }); - }; + } return ( - - - - Copy Node - + + + + Copy + + {subGraphID && ( - window.open(`/build?flowID=${subGraphID}`)} - className="hover:rounded-xlarge" - > - - Open Agent - + <> + window.open(`/build?flowID=${subGraphID}`)} + > + + Open agent + + + )} - - - - - Delete - - + + + Delete + + ); }; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeHeader.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeHeader.tsx index 42d14a81a0..e13aa37a31 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeHeader.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeHeader.tsx @@ -1,29 +1,30 @@ -import { Text } from "@/components/atoms/Text/Text"; -import { beautifyString, cn } from "@/lib/utils"; -import { NodeCost } from "./NodeCost"; -import { NodeBadges } from "./NodeBadges"; -import { NodeContextMenu } from "./NodeContextMenu"; -import { CustomNodeData } from "../CustomNode"; import { useNodeStore } from "@/app/(platform)/build/stores/nodeStore"; -import { useState } from "react"; +import { Text } from "@/components/atoms/Text/Text"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@/components/atoms/Tooltip/BaseTooltip"; +import { beautifyString, cn } from "@/lib/utils"; +import { useState } from "react"; +import { CustomNodeData } from "../CustomNode"; +import { NodeBadges } from "./NodeBadges"; +import { NodeContextMenu } from "./NodeContextMenu"; +import { NodeCost } from "./NodeCost"; -export const NodeHeader = ({ - data, - nodeId, -}: { +type Props = { data: CustomNodeData; nodeId: string; -}) => { +}; + +export const NodeHeader = ({ data, nodeId }: Props) => { const updateNodeData = useNodeStore((state) => state.updateNodeData); const title = (data.metadata?.customized_name as string) || data.title; const [isEditingTitle, setIsEditingTitle] = useState(false); - const [editedTitle, setEditedTitle] = useState(title); + const [editedTitle, setEditedTitle] = useState( + beautifyString(title).replace("Block", "").trim(), + ); const handleTitleEdit = () => { updateNodeData(nodeId, { @@ -41,7 +42,7 @@ export const NodeHeader = ({ }; return ( -
+
{/* Title row with context menu */}
@@ -67,13 +68,16 @@ export const NodeHeader = ({
- - {beautifyString(title)} + + {beautifyString(title).replace("Block", "").trim()}
-

{beautifyString(title)}

+

{beautifyString(title).replace("Block", "").trim()}

diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeOutput/NodeOutput.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeOutput/NodeOutput.tsx index a4b53e3ac3..3f0ae6e350 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeOutput/NodeOutput.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeOutput/NodeOutput.tsx @@ -23,7 +23,7 @@ export const NodeDataRenderer = ({ nodeId }: { nodeId: string }) => { } return ( -
+
Node Output diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeOutput/components/NodeDataViewer/NodeDataViewer.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeOutput/components/NodeDataViewer/NodeDataViewer.tsx index c505282e7b..31b89315d6 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeOutput/components/NodeDataViewer/NodeDataViewer.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeOutput/components/NodeDataViewer/NodeDataViewer.tsx @@ -151,7 +151,7 @@ export const NodeDataViewer: FC = ({
- {outputItems.length > 0 && ( + {outputItems.length > 1 && ( ({ value: item.value, diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeRightClickMenu.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeRightClickMenu.tsx new file mode 100644 index 0000000000..a56e42544f --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeRightClickMenu.tsx @@ -0,0 +1,104 @@ +import { useCopyPasteStore } from "@/app/(platform)/build/stores/copyPasteStore"; +import { useNodeStore } from "@/app/(platform)/build/stores/nodeStore"; +import { + SecondaryMenuContent, + SecondaryMenuItem, + SecondaryMenuSeparator, +} from "@/components/molecules/SecondaryMenu/SecondaryMenu"; +import { ArrowSquareOutIcon, CopyIcon, TrashIcon } from "@phosphor-icons/react"; +import * as ContextMenu from "@radix-ui/react-context-menu"; +import { useReactFlow } from "@xyflow/react"; +import { useEffect, useRef } from "react"; +import { CustomNode } from "../CustomNode"; + +type Props = { + nodeId: string; + subGraphID?: string; + children: React.ReactNode; +}; + +const DOUBLE_CLICK_TIMEOUT = 300; + +export function NodeRightClickMenu({ nodeId, subGraphID, children }: Props) { + const { deleteElements } = useReactFlow(); + const lastRightClickTime = useRef(0); + const containerRef = useRef(null); + + function copyNode() { + useNodeStore.setState((state) => ({ + nodes: state.nodes.map((node) => ({ + ...node, + selected: node.id === nodeId, + })), + })); + + useCopyPasteStore.getState().copySelectedNodes(); + useCopyPasteStore.getState().pasteNodes(); + } + + function deleteNode() { + deleteElements({ nodes: [{ id: nodeId }] }); + } + + useEffect(() => { + const container = containerRef.current; + if (!container) return; + + function handleContextMenu(e: MouseEvent) { + const now = Date.now(); + const timeSinceLastClick = now - lastRightClickTime.current; + + if (timeSinceLastClick < DOUBLE_CLICK_TIMEOUT) { + e.stopImmediatePropagation(); + lastRightClickTime.current = 0; + return; + } + + lastRightClickTime.current = now; + } + + container.addEventListener("contextmenu", handleContextMenu, true); + + return () => { + container.removeEventListener("contextmenu", handleContextMenu, true); + }; + }, []); + + return ( + + +
{children}
+
+ + + + Copy + + + + {subGraphID && ( + <> + window.open(`/build?flowID=${subGraphID}`)} + > + + Open agent + + + + )} + + + + Delete + + +
+ ); +} diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/StickyNoteBlock.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/StickyNoteBlock.tsx index 5d57c6c5b6..f900b1633f 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/StickyNoteBlock.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/StickyNoteBlock.tsx @@ -1,6 +1,6 @@ import { useMemo } from "react"; import { FormCreator } from "../../FormCreator"; -import { preprocessInputSchema } from "@/components/renderers/input-renderer/utils/input-schema-pre-processor"; +import { preprocessInputSchema } from "@/components/renderers/InputRenderer/utils/input-schema-pre-processor"; import { CustomNodeData } from "../CustomNode"; import { Text } from "@/components/atoms/Text/Text"; import { cn } from "@/lib/utils"; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/FormCreator.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/FormCreator.tsx index cfee0bf89f..28d1bcc0ab 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/FormCreator.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/FormCreator.tsx @@ -3,7 +3,7 @@ import React from "react"; import { uiSchema } from "./uiSchema"; import { useNodeStore } from "../../../stores/nodeStore"; import { BlockUIType } from "../../types"; -import { FormRenderer } from "@/components/renderers/input-renderer/FormRenderer"; +import { FormRenderer } from "@/components/renderers/InputRenderer/FormRenderer"; export const FormCreator = React.memo( ({ diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/OutputHandler.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/OutputHandler.tsx index ab3b648ba9..b70a8e239b 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/OutputHandler.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/OutputHandler.tsx @@ -4,7 +4,7 @@ import { CaretDownIcon, InfoIcon } from "@phosphor-icons/react"; import { RJSFSchema } from "@rjsf/utils"; import { useState } from "react"; -import NodeHandle from "../handlers/NodeHandle"; +import { OutputNodeHandle } from "../handlers/NodeHandle"; import { Tooltip, TooltipContent, @@ -13,7 +13,6 @@ import { } from "@/components/atoms/Tooltip/BaseTooltip"; import { useEdgeStore } from "@/app/(platform)/build/stores/edgeStore"; import { getTypeDisplayInfo } from "./helpers"; -import { generateHandleId } from "../handlers/helpers"; import { BlockUIType } from "../../types"; export const OutputHandler = ({ @@ -29,8 +28,73 @@ export const OutputHandler = ({ const properties = outputSchema?.properties || {}; const [isOutputVisible, setIsOutputVisible] = useState(true); + const showHandles = uiType !== BlockUIType.OUTPUT; + + const renderOutputHandles = ( + schema: RJSFSchema, + keyPrefix: string = "", + titlePrefix: string = "", + ): React.ReactNode[] => { + return Object.entries(schema).map( + ([key, fieldSchema]: [string, RJSFSchema]) => { + const fullKey = keyPrefix ? `${keyPrefix}_#_${key}` : key; + const fieldTitle = titlePrefix + (fieldSchema?.title || key); + + const isConnected = isOutputConnected(nodeId, fullKey); + const shouldShow = isConnected || isOutputVisible; + const { displayType, colorClass, hexColor } = + getTypeDisplayInfo(fieldSchema); + + return shouldShow ? ( +
+
+ {fieldSchema?.description && ( + + + + + + + + {fieldSchema?.description} + + + )} + + {fieldTitle} + + + ({displayType}) + + + {showHandles && ( + + )} +
+ + {/* Recursively render nested properties */} + {fieldSchema?.properties && + renderOutputHandles( + fieldSchema.properties, + fullKey, + `${fieldTitle}.`, + )} +
+ ) : null; + }, + ); + }; + return ( -
+
- { -
- {Object.entries(properties).map(([key, property]: [string, any]) => { - const isConnected = isOutputConnected(nodeId, key); - const shouldShow = isConnected || isOutputVisible; - const { displayType, colorClass } = getTypeDisplayInfo(property); - - return shouldShow ? ( -
- {property?.description && ( - - - - - - - - {property?.description} - - - )} - - {property?.title || key}{" "} - - - ({displayType}) - - - -
- ) : null; - })} -
- } +
+ {renderOutputHandles(properties)} +
); }; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/helpers.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/helpers.ts index 5572426dc7..46032a67ea 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/helpers.ts +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/helpers.ts @@ -89,17 +89,53 @@ export function extractOptions( // get display type and color for schema types [need for type display next to field name] export const getTypeDisplayInfo = (schema: any) => { + if ( + schema?.type === "array" && + "format" in schema && + schema.format === "table" + ) { + return { + displayType: "table", + colorClass: "!text-indigo-500", + hexColor: "#6366f1", + }; + } + if (schema?.type === "string" && schema?.format) { const formatMap: Record< string, - { displayType: string; colorClass: string } + { displayType: string; colorClass: string; hexColor: string } > = { - file: { displayType: "file", colorClass: "!text-green-500" }, - date: { displayType: "date", colorClass: "!text-blue-500" }, - time: { displayType: "time", colorClass: "!text-blue-500" }, - "date-time": { displayType: "datetime", colorClass: "!text-blue-500" }, - "long-text": { displayType: "text", colorClass: "!text-green-500" }, - "short-text": { displayType: "text", colorClass: "!text-green-500" }, + file: { + displayType: "file", + colorClass: "!text-green-500", + hexColor: "#22c55e", + }, + date: { + displayType: "date", + colorClass: "!text-blue-500", + hexColor: "#3b82f6", + }, + time: { + displayType: "time", + colorClass: "!text-blue-500", + hexColor: "#3b82f6", + }, + "date-time": { + displayType: "datetime", + colorClass: "!text-blue-500", + hexColor: "#3b82f6", + }, + "long-text": { + displayType: "text", + colorClass: "!text-green-500", + hexColor: "#22c55e", + }, + "short-text": { + displayType: "text", + colorClass: "!text-green-500", + hexColor: "#22c55e", + }, }; const formatInfo = formatMap[schema.format]; @@ -131,10 +167,23 @@ export const getTypeDisplayInfo = (schema: any) => { any: "!text-gray-500", }; + const hexColorMap: Record = { + string: "#22c55e", + number: "#3b82f6", + integer: "#3b82f6", + boolean: "#eab308", + object: "#a855f7", + array: "#6366f1", + null: "#6b7280", + any: "#6b7280", + }; + const colorClass = colorMap[schema?.type] || "!text-gray-500"; + const hexColor = hexColorMap[schema?.type] || "#6b7280"; return { displayType, colorClass, + hexColor, }; }; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/uiSchema.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/uiSchema.ts index ad1fab7c95..065e697828 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/uiSchema.ts +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/uiSchema.ts @@ -1,6 +1,6 @@ export const uiSchema = { credentials: { - "ui:field": "credentials", + "ui:field": "custom/credential_field", provider: { "ui:widget": "hidden" }, type: { "ui:widget": "hidden" }, id: { "ui:autofocus": true }, diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuFilters/BlockMenuFilters.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuFilters/BlockMenuFilters.tsx new file mode 100644 index 0000000000..ebcea9eee6 --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuFilters/BlockMenuFilters.tsx @@ -0,0 +1,57 @@ +import { useBlockMenuStore } from "@/app/(platform)/build/stores/blockMenuStore"; +import { FilterChip } from "../FilterChip"; +import { categories } from "./constants"; +import { FilterSheet } from "../FilterSheet/FilterSheet"; +import { GetV2BuilderSearchFilterAnyOfItem } from "@/app/api/__generated__/models/getV2BuilderSearchFilterAnyOfItem"; + +export const BlockMenuFilters = () => { + const { + filters, + addFilter, + removeFilter, + categoryCounts, + creators, + addCreator, + removeCreator, + } = useBlockMenuStore(); + + const handleFilterClick = (filter: GetV2BuilderSearchFilterAnyOfItem) => { + if (filters.includes(filter)) { + removeFilter(filter); + } else { + addFilter(filter); + } + }; + + const handleCreatorClick = (creator: string) => { + if (creators.includes(creator)) { + removeCreator(creator); + } else { + addCreator(creator); + } + }; + + return ( +
+ + {creators.length > 0 && + creators.map((creator) => ( + handleCreatorClick(creator)} + /> + ))} + {categories.map((category) => ( + handleFilterClick(category.key)} + number={categoryCounts[category.key] ?? 0} + /> + ))} +
+ ); +}; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuFilters/constants.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuFilters/constants.ts new file mode 100644 index 0000000000..b438aae91b --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuFilters/constants.ts @@ -0,0 +1,15 @@ +import { GetV2BuilderSearchFilterAnyOfItem } from "@/app/api/__generated__/models/getV2BuilderSearchFilterAnyOfItem"; +import { CategoryKey } from "./types"; + +export const categories: Array<{ key: CategoryKey; name: string }> = [ + { key: GetV2BuilderSearchFilterAnyOfItem.blocks, name: "Blocks" }, + { + key: GetV2BuilderSearchFilterAnyOfItem.integrations, + name: "Integrations", + }, + { + key: GetV2BuilderSearchFilterAnyOfItem.marketplace_agents, + name: "Marketplace agents", + }, + { key: GetV2BuilderSearchFilterAnyOfItem.my_agents, name: "My agents" }, +]; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuFilters/types.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuFilters/types.ts new file mode 100644 index 0000000000..8fec9ef64d --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuFilters/types.ts @@ -0,0 +1,26 @@ +import { GetV2BuilderSearchFilterAnyOfItem } from "@/app/api/__generated__/models/getV2BuilderSearchFilterAnyOfItem"; + +export type DefaultStateType = + | "suggestion" + | "all_blocks" + | "input_blocks" + | "action_blocks" + | "output_blocks" + | "integrations" + | "marketplace_agents" + | "my_agents"; + +export type CategoryKey = GetV2BuilderSearchFilterAnyOfItem; + +export interface Filters { + categories: { + blocks: boolean; + integrations: boolean; + marketplace_agents: boolean; + my_agents: boolean; + providers: boolean; + }; + createdBy: string[]; +} + +export type CategoryCounts = Record; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuSearch/BlockMenuSearch.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuSearch/BlockMenuSearch.tsx index de339431e8..26723eebcc 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuSearch/BlockMenuSearch.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuSearch/BlockMenuSearch.tsx @@ -1,111 +1,14 @@ import { Text } from "@/components/atoms/Text/Text"; -import { useBlockMenuSearch } from "./useBlockMenuSearch"; -import { InfiniteScroll } from "@/components/contextual/InfiniteScroll/InfiniteScroll"; -import { LoadingSpinner } from "@/components/__legacy__/ui/loading"; -import { SearchResponseItemsItem } from "@/app/api/__generated__/models/searchResponseItemsItem"; -import { MarketplaceAgentBlock } from "../MarketplaceAgentBlock"; -import { Block } from "../Block"; -import { UGCAgentBlock } from "../UGCAgentBlock"; -import { getSearchItemType } from "./helper"; -import { useBlockMenuStore } from "../../../../stores/blockMenuStore"; import { blockMenuContainerStyle } from "../style"; -import { cn } from "@/lib/utils"; -import { NoSearchResult } from "../NoSearchResult"; +import { BlockMenuFilters } from "../BlockMenuFilters/BlockMenuFilters"; +import { BlockMenuSearchContent } from "../BlockMenuSearchContent/BlockMenuSearchContent"; export const BlockMenuSearch = () => { - const { - searchResults, - isFetchingNextPage, - fetchNextPage, - hasNextPage, - searchLoading, - handleAddLibraryAgent, - handleAddMarketplaceAgent, - addingLibraryAgentId, - addingMarketplaceAgentSlug, - } = useBlockMenuSearch(); - const { searchQuery } = useBlockMenuStore(); - - if (searchLoading) { - return ( -
- -
- ); - } - - if (searchResults.length === 0) { - return ; - } - return (
+ Search results - } - className="space-y-2.5" - > - {searchResults.map((item: SearchResponseItemsItem, index: number) => { - const { type, data } = getSearchItemType(item); - // backend give support to these 3 types only [right now] - we need to give support to integration and ai agent types in follow up PRs - switch (type) { - case "store_agent": - return ( - - handleAddMarketplaceAgent({ - creator_name: data.creator, - slug: data.slug, - }) - } - /> - ); - case "block": - return ( - - ); - - case "library_agent": - return ( - handleAddLibraryAgent(data)} - /> - ); - - default: - return null; - } - })} - +
); }; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuSearchContent/BlockMenuSearchContent.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuSearchContent/BlockMenuSearchContent.tsx new file mode 100644 index 0000000000..7229c44ed7 --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuSearchContent/BlockMenuSearchContent.tsx @@ -0,0 +1,108 @@ +import { SearchResponseItemsItem } from "@/app/api/__generated__/models/searchResponseItemsItem"; +import { LoadingSpinner } from "@/components/atoms/LoadingSpinner/LoadingSpinner"; +import { InfiniteScroll } from "@/components/contextual/InfiniteScroll/InfiniteScroll"; +import { getSearchItemType } from "./helper"; +import { MarketplaceAgentBlock } from "../MarketplaceAgentBlock"; +import { Block } from "../Block"; +import { UGCAgentBlock } from "../UGCAgentBlock"; +import { useBlockMenuSearchContent } from "./useBlockMenuSearchContent"; +import { useBlockMenuStore } from "@/app/(platform)/build/stores/blockMenuStore"; +import { cn } from "@/lib/utils"; +import { blockMenuContainerStyle } from "../style"; +import { NoSearchResult } from "../NoSearchResult"; + +export const BlockMenuSearchContent = () => { + const { + searchResults, + isFetchingNextPage, + fetchNextPage, + hasNextPage, + searchLoading, + handleAddLibraryAgent, + handleAddMarketplaceAgent, + addingLibraryAgentId, + addingMarketplaceAgentSlug, + } = useBlockMenuSearchContent(); + + const { searchQuery } = useBlockMenuStore(); + + if (searchLoading) { + return ( +
+ +
+ ); + } + + if (searchResults.length === 0) { + return ; + } + + return ( + } + className="space-y-2.5" + > + {searchResults.map((item: SearchResponseItemsItem, index: number) => { + const { type, data } = getSearchItemType(item); + // backend give support to these 3 types only [right now] - we need to give support to integration and ai agent types in follow up PRs + switch (type) { + case "store_agent": + return ( + + handleAddMarketplaceAgent({ + creator_name: data.creator, + slug: data.slug, + }) + } + /> + ); + case "block": + return ( + + ); + + case "library_agent": + return ( + handleAddLibraryAgent(data)} + /> + ); + + default: + return null; + } + })} + + ); +}; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuSearch/helper.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuSearchContent/helper.ts similarity index 100% rename from autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuSearch/helper.ts rename to autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuSearchContent/helper.ts diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuSearch/useBlockMenuSearch.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuSearchContent/useBlockMenuSearchContent.tsx similarity index 83% rename from autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuSearch/useBlockMenuSearch.ts rename to autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuSearchContent/useBlockMenuSearchContent.tsx index beff80a984..9da9cb4cbc 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuSearch/useBlockMenuSearch.ts +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuSearchContent/useBlockMenuSearchContent.tsx @@ -23,9 +23,19 @@ import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent"; import { getQueryClient } from "@/lib/react-query/queryClient"; import { useToast } from "@/components/molecules/Toast/use-toast"; import * as Sentry from "@sentry/nextjs"; +import { GetV2BuilderSearchFilterAnyOfItem } from "@/app/api/__generated__/models/getV2BuilderSearchFilterAnyOfItem"; + +export const useBlockMenuSearchContent = () => { + const { + searchQuery, + searchId, + setSearchId, + filters, + setCreatorsList, + creators, + setCategoryCounts, + } = useBlockMenuStore(); -export const useBlockMenuSearch = () => { - const { searchQuery, searchId, setSearchId } = useBlockMenuStore(); const { toast } = useToast(); const { addAgentToBuilder, addLibraryAgentToBuilder } = useAddAgentToBuilder(); @@ -57,6 +67,8 @@ export const useBlockMenuSearch = () => { page_size: 8, search_query: searchQuery, search_id: searchId, + filter: filters.length > 0 ? filters : undefined, + by_creator: creators.length > 0 ? creators : undefined, }, { query: { getNextPageParam: getPaginationNextPageNumber }, @@ -98,6 +110,26 @@ export const useBlockMenuSearch = () => { } }, [searchQueryData, searchId, setSearchId]); + // from all the results, we need to get all the unique creators + useEffect(() => { + if (!searchQueryData?.pages?.length) { + return; + } + const latestData = okData(searchQueryData.pages.at(-1)); + setCategoryCounts( + (latestData?.total_items as Record< + GetV2BuilderSearchFilterAnyOfItem, + number + >) || { + blocks: 0, + integrations: 0, + marketplace_agents: 0, + my_agents: 0, + }, + ); + setCreatorsList(latestData?.items || []); + }, [searchQueryData]); + useEffect(() => { if (searchId && !searchQuery) { resetSearchSession(); diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/FilterChip.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/FilterChip.tsx index 69931958b3..23197ab612 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/FilterChip.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/FilterChip.tsx @@ -1,7 +1,9 @@ import { Button } from "@/components/__legacy__/ui/button"; import { cn } from "@/lib/utils"; -import { X } from "lucide-react"; -import React, { ButtonHTMLAttributes } from "react"; +import { XIcon } from "@phosphor-icons/react"; +import { AnimatePresence, motion } from "framer-motion"; + +import React, { ButtonHTMLAttributes, useState } from "react"; interface Props extends ButtonHTMLAttributes { selected?: boolean; @@ -16,39 +18,51 @@ export const FilterChip: React.FC = ({ className, ...rest }) => { + const [isHovered, setIsHovered] = useState(false); return ( - + > + {name} + + {selected && !isHovered && ( + + + + )} + {number !== undefined && isHovered && ( + + {number > 100 ? "100+" : number} + + )} + + ); }; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/FilterSheet/FilterSheet.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/FilterSheet/FilterSheet.tsx new file mode 100644 index 0000000000..dc7c428245 --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/FilterSheet/FilterSheet.tsx @@ -0,0 +1,156 @@ +import { FilterChip } from "../FilterChip"; +import { cn } from "@/lib/utils"; +import { CategoryKey } from "../BlockMenuFilters/types"; +import { AnimatePresence, motion } from "framer-motion"; +import { XIcon } from "@phosphor-icons/react"; +import { Button } from "@/components/atoms/Button/Button"; +import { Text } from "@/components/atoms/Text/Text"; +import { Separator } from "@/components/__legacy__/ui/separator"; +import { Checkbox } from "@/components/__legacy__/ui/checkbox"; +import { useFilterSheet } from "./useFilterSheet"; +import { INITIAL_CREATORS_TO_SHOW } from "./constant"; + +export function FilterSheet({ + categories, +}: { + categories: Array<{ key: CategoryKey; name: string }>; +}) { + const { + isOpen, + localCategories, + localCreators, + displayedCreatorsCount, + handleLocalCategoryChange, + handleToggleShowMoreCreators, + handleLocalCreatorChange, + handleClearFilters, + handleCloseButton, + handleApplyFilters, + hasLocalActiveFilters, + visibleCreators, + creators, + handleOpenFilters, + hasActiveFilters, + } = useFilterSheet(); + + return ( +
+ + + + {isOpen && ( + + {/* Top section */} +
+ Filters + +
+ + + + {/* Category section */} +
+ Categories +
+ {categories.map((category) => ( +
+ + handleLocalCategoryChange(category.key) + } + className="border border-[#D4D4D4] shadow-none data-[state=checked]:border-none data-[state=checked]:bg-violet-700 data-[state=checked]:text-white" + /> + +
+ ))} +
+
+ + {/* Created by section */} +
+

+ Created by +

+
+ {visibleCreators.map((creator, i) => ( +
+ handleLocalCreatorChange(creator)} + className="border border-[#D4D4D4] shadow-none data-[state=checked]:border-none data-[state=checked]:bg-violet-700 data-[state=checked]:text-white" + /> + +
+ ))} +
+ {creators.length > INITIAL_CREATORS_TO_SHOW && ( + + )} +
+ + {/* Footer section */} +
+ + + +
+
+ )} +
+
+ ); +} diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/FilterSheet/constant.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/FilterSheet/constant.ts new file mode 100644 index 0000000000..8e05dc1037 --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/FilterSheet/constant.ts @@ -0,0 +1 @@ +export const INITIAL_CREATORS_TO_SHOW = 5; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/FilterSheet/useFilterSheet.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/FilterSheet/useFilterSheet.ts new file mode 100644 index 0000000000..200671f4e7 --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/FilterSheet/useFilterSheet.ts @@ -0,0 +1,100 @@ +import { useBlockMenuStore } from "@/app/(platform)/build/stores/blockMenuStore"; +import { useState } from "react"; +import { INITIAL_CREATORS_TO_SHOW } from "./constant"; +import { GetV2BuilderSearchFilterAnyOfItem } from "@/app/api/__generated__/models/getV2BuilderSearchFilterAnyOfItem"; + +export const useFilterSheet = () => { + const { filters, creators_list, creators, setFilters, setCreators } = + useBlockMenuStore(); + + const [isOpen, setIsOpen] = useState(false); + const [localCategories, setLocalCategories] = + useState(filters); + const [localCreators, setLocalCreators] = useState(creators); + const [displayedCreatorsCount, setDisplayedCreatorsCount] = useState( + INITIAL_CREATORS_TO_SHOW, + ); + + const handleLocalCategoryChange = ( + category: GetV2BuilderSearchFilterAnyOfItem, + ) => { + setLocalCategories((prev) => { + if (prev.includes(category)) { + return prev.filter((c) => c !== category); + } + return [...prev, category]; + }); + }; + + const hasActiveFilters = () => { + return filters.length > 0 || creators.length > 0; + }; + + const handleToggleShowMoreCreators = () => { + if (displayedCreatorsCount < creators.length) { + setDisplayedCreatorsCount(creators.length); + } else { + setDisplayedCreatorsCount(INITIAL_CREATORS_TO_SHOW); + } + }; + + const handleLocalCreatorChange = (creator: string) => { + setLocalCreators((prev) => { + if (prev.includes(creator)) { + return prev.filter((c) => c !== creator); + } + return [...prev, creator]; + }); + }; + + const handleClearFilters = () => { + setLocalCategories([]); + setLocalCreators([]); + setDisplayedCreatorsCount(INITIAL_CREATORS_TO_SHOW); + }; + + const handleCloseButton = () => { + setIsOpen(false); + setLocalCategories(filters); + setLocalCreators(creators); + setDisplayedCreatorsCount(INITIAL_CREATORS_TO_SHOW); + }; + + const handleApplyFilters = () => { + setFilters(localCategories); + setCreators(localCreators); + setIsOpen(false); + }; + + const handleOpenFilters = () => { + setIsOpen(true); + setLocalCategories(filters); + setLocalCreators(creators); + }; + + const hasLocalActiveFilters = () => { + return localCategories.length > 0 || localCreators.length > 0; + }; + + const visibleCreators = creators_list.slice(0, displayedCreatorsCount); + + return { + creators, + isOpen, + setIsOpen, + localCategories, + localCreators, + displayedCreatorsCount, + setDisplayedCreatorsCount, + handleLocalCategoryChange, + handleToggleShowMoreCreators, + handleLocalCreatorChange, + handleClearFilters, + handleCloseButton, + handleOpenFilters, + handleApplyFilters, + hasLocalActiveFilters, + visibleCreators, + hasActiveFilters, + }; +}; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/stores/blockMenuStore.ts b/autogpt_platform/frontend/src/app/(platform)/build/stores/blockMenuStore.ts index ea50a03979..31b9eda338 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/stores/blockMenuStore.ts +++ b/autogpt_platform/frontend/src/app/(platform)/build/stores/blockMenuStore.ts @@ -1,12 +1,30 @@ import { create } from "zustand"; import { DefaultStateType } from "../components/NewControlPanel/NewBlockMenu/types"; +import { SearchResponseItemsItem } from "@/app/api/__generated__/models/searchResponseItemsItem"; +import { getSearchItemType } from "../components/NewControlPanel/NewBlockMenu/BlockMenuSearchContent/helper"; +import { StoreAgent } from "@/app/api/__generated__/models/storeAgent"; +import { GetV2BuilderSearchFilterAnyOfItem } from "@/app/api/__generated__/models/getV2BuilderSearchFilterAnyOfItem"; type BlockMenuStore = { searchQuery: string; searchId: string | undefined; defaultState: DefaultStateType; integration: string | undefined; + filters: GetV2BuilderSearchFilterAnyOfItem[]; + creators: string[]; + creators_list: string[]; + categoryCounts: Record; + setCategoryCounts: ( + counts: Record, + ) => void; + setCreatorsList: (searchData: SearchResponseItemsItem[]) => void; + addCreator: (creator: string) => void; + setCreators: (creators: string[]) => void; + removeCreator: (creator: string) => void; + addFilter: (filter: GetV2BuilderSearchFilterAnyOfItem) => void; + setFilters: (filters: GetV2BuilderSearchFilterAnyOfItem[]) => void; + removeFilter: (filter: GetV2BuilderSearchFilterAnyOfItem) => void; setSearchQuery: (query: string) => void; setSearchId: (id: string | undefined) => void; setDefaultState: (state: DefaultStateType) => void; @@ -19,11 +37,44 @@ export const useBlockMenuStore = create((set) => ({ searchId: undefined, defaultState: DefaultStateType.SUGGESTION, integration: undefined, + filters: [], + creators: [], // creator filters that are applied to the search results + creators_list: [], // all creators that are available to filter by + categoryCounts: { + blocks: 0, + integrations: 0, + marketplace_agents: 0, + my_agents: 0, + }, + setCategoryCounts: (counts) => set({ categoryCounts: counts }), + setCreatorsList: (searchData) => { + const marketplaceAgents = searchData.filter((item) => { + return getSearchItemType(item).type === "store_agent"; + }) as StoreAgent[]; + + const newCreators = marketplaceAgents.map((agent) => agent.creator); + + set((state) => ({ + creators_list: Array.from( + new Set([...state.creators_list, ...newCreators]), + ), + })); + }, + setCreators: (creators) => set({ creators }), + setFilters: (filters) => set({ filters }), setSearchQuery: (query) => set({ searchQuery: query }), setSearchId: (id) => set({ searchId: id }), setDefaultState: (state) => set({ defaultState: state }), setIntegration: (integration) => set({ integration }), + addFilter: (filter) => + set((state) => ({ filters: [...state.filters, filter] })), + removeFilter: (filter) => + set((state) => ({ filters: state.filters.filter((f) => f !== filter) })), + addCreator: (creator) => + set((state) => ({ creators: [...state.creators, creator] })), + removeCreator: (creator) => + set((state) => ({ creators: state.creators.filter((c) => c !== creator) })), reset: () => set({ searchQuery: "", diff --git a/autogpt_platform/frontend/src/app/(platform)/build/stores/edgeStore.ts b/autogpt_platform/frontend/src/app/(platform)/build/stores/edgeStore.ts index cae1d995da..7b17eecfb3 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/stores/edgeStore.ts +++ b/autogpt_platform/frontend/src/app/(platform)/build/stores/edgeStore.ts @@ -4,6 +4,7 @@ import { CustomEdge } from "../components/FlowEditor/edges/CustomEdge"; import { customEdgeToLink, linkToCustomEdge } from "../components/helper"; import { MarkerType } from "@xyflow/react"; import { NodeExecutionResult } from "@/app/api/__generated__/models/nodeExecutionResult"; +import { cleanUpHandleId } from "@/components/renderers/InputRenderer/helpers"; type EdgeStore = { edges: CustomEdge[]; @@ -13,6 +14,8 @@ type EdgeStore = { removeEdge: (edgeId: string) => void; upsertMany: (edges: CustomEdge[]) => void; + removeEdgesByHandlePrefix: (nodeId: string, handlePrefix: string) => void; + getNodeEdges: (nodeId: string) => CustomEdge[]; isInputConnected: (nodeId: string, handle: string) => boolean; isOutputConnected: (nodeId: string, handle: string) => boolean; @@ -79,11 +82,27 @@ export const useEdgeStore = create((set, get) => ({ return { edges: Array.from(byKey.values()) }; }), + removeEdgesByHandlePrefix: (nodeId, handlePrefix) => + set((state) => ({ + edges: state.edges.filter( + (e) => + !( + e.target === nodeId && + e.targetHandle && + e.targetHandle.startsWith(handlePrefix) + ), + ), + })), + getNodeEdges: (nodeId) => get().edges.filter((e) => e.source === nodeId || e.target === nodeId), - isInputConnected: (nodeId, handle) => - get().edges.some((e) => e.target === nodeId && e.targetHandle === handle), + isInputConnected: (nodeId, handle) => { + const cleanedHandle = cleanUpHandleId(handle); + return get().edges.some( + (e) => e.target === nodeId && e.targetHandle === cleanedHandle, + ); + }, isOutputConnected: (nodeId, handle) => get().edges.some((e) => e.source === nodeId && e.sourceHandle === handle), @@ -105,15 +124,15 @@ export const useEdgeStore = create((set, get) => ({ targetNodeId: string, executionResult: NodeExecutionResult, ) => { - set((state) => ({ - edges: state.edges.map((edge) => { + set((state) => { + let hasChanges = false; + + const newEdges = state.edges.map((edge) => { if (edge.target !== targetNodeId) { return edge; } - const beadData = - edge.data?.beadData ?? - new Map(); + const beadData = new Map(edge.data?.beadData ?? new Map()); const inputValue = edge.targetHandle ? executionResult.input_data[edge.targetHandle] @@ -137,6 +156,11 @@ export const useEdgeStore = create((set, get) => ({ beadUp = beadDown + 1; } + if (edge.data?.beadUp === beadUp && edge.data?.beadDown === beadDown) { + return edge; + } + + hasChanges = true; return { ...edge, data: { @@ -146,8 +170,10 @@ export const useEdgeStore = create((set, get) => ({ beadData, }, }; - }), - })); + }); + + return hasChanges ? { edges: newEdges } : state; + }); }, resetEdgeBeads: () => { diff --git a/autogpt_platform/frontend/src/app/(platform)/build/stores/nodeStore.ts b/autogpt_platform/frontend/src/app/(platform)/build/stores/nodeStore.ts index 2f41c3bb46..c151f90faa 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/stores/nodeStore.ts +++ b/autogpt_platform/frontend/src/app/(platform)/build/stores/nodeStore.ts @@ -13,6 +13,10 @@ import { useHistoryStore } from "./historyStore"; import { useEdgeStore } from "./edgeStore"; import { BlockUIType } from "../components/types"; import { pruneEmptyValues } from "@/lib/utils"; +import { + ensurePathExists, + parseHandleIdToPath, +} from "@/components/renderers/InputRenderer/helpers"; // Minimum movement (in pixels) required before logging position change to history // Prevents spamming history with small movements when clicking on inputs inside blocks @@ -62,6 +66,11 @@ type NodeStore = { errors: { [key: string]: string }, ) => void; clearAllNodeErrors: () => void; // Add this + + syncHardcodedValuesWithHandleIds: (nodeId: string) => void; + + // Credentials optional helpers + setCredentialsOptional: (nodeId: string, optional: boolean) => void; }; export const useNodeStore = create((set, get) => ({ @@ -220,6 +229,9 @@ export const useNodeStore = create((set, get) => ({ ...(node.data.metadata?.customized_name !== undefined && { customized_name: node.data.metadata.customized_name, }), + ...(node.data.metadata?.credentials_optional !== undefined && { + credentials_optional: node.data.metadata.credentials_optional, + }), }, }; }, @@ -305,4 +317,61 @@ export const useNodeStore = create((set, get) => ({ })), })); }, + + syncHardcodedValuesWithHandleIds: (nodeId: string) => { + const node = get().nodes.find((n) => n.id === nodeId); + if (!node) return; + + const handleIds = useEdgeStore.getState().getAllHandleIdsOfANode(nodeId); + const additionalHandles = handleIds.filter((h) => h.includes("_#_")); + + if (additionalHandles.length === 0) return; + + const hardcodedValues = JSON.parse( + JSON.stringify(node.data.hardcodedValues || {}), + ); + + let modified = false; + + additionalHandles.forEach((handleId) => { + const segments = parseHandleIdToPath(handleId); + if (ensurePathExists(hardcodedValues, segments)) { + modified = true; + } + }); + + if (modified) { + set((state) => ({ + nodes: state.nodes.map((n) => + n.id === nodeId ? { ...n, data: { ...n.data, hardcodedValues } } : n, + ), + })); + } + }, + + setCredentialsOptional: (nodeId: string, optional: boolean) => { + set((state) => ({ + nodes: state.nodes.map((n) => + n.id === nodeId + ? { + ...n, + data: { + ...n.data, + metadata: { + ...n.data.metadata, + credentials_optional: optional, + }, + }, + } + : n, + ), + })); + + const newState = { + nodes: get().nodes, + edges: useEdgeStore.getState().edges, + }; + + useHistoryStore.getState().pushState(newState); + }, })); diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/CredentialsInputs.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/CredentialsInputs.tsx index 07350fb610..a0f9376aa2 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/CredentialsInputs.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/CredentialsInputs.tsx @@ -34,7 +34,9 @@ type Props = { onSelectCredentials: (newValue?: CredentialsMetaInput) => void; onLoaded?: (loaded: boolean) => void; readOnly?: boolean; + isOptional?: boolean; showTitle?: boolean; + variant?: "default" | "node"; }; export function CredentialsInput({ @@ -45,7 +47,9 @@ export function CredentialsInput({ siblingInputs, onLoaded, readOnly = false, + isOptional = false, showTitle = true, + variant = "default", }: Props) { const hookData = useCredentialsInput({ schema, @@ -54,6 +58,7 @@ export function CredentialsInput({ siblingInputs, onLoaded, readOnly, + isOptional, }); if (!isLoaded(hookData)) { @@ -94,7 +99,14 @@ export function CredentialsInput({
{showTitle && (
- {displayName} credentials + + {displayName} credentials + {isOptional && ( + + (optional) + + )} + {schema.description && ( )} @@ -103,14 +115,17 @@ export function CredentialsInput({ {hasCredentialsToShow ? ( <> - {credentialsToShow.length > 1 && !readOnly ? ( + {(credentialsToShow.length > 1 || isOptional) && !readOnly ? ( onSelectCredential(undefined)} readOnly={readOnly} + allowNone={isOptional} + variant={variant} /> ) : (
@@ -143,6 +158,7 @@ export function CredentialsInput({ size="small" onClick={handleActionButtonClick} className="w-fit" + type="button" > {actionButtonText} @@ -155,6 +171,7 @@ export function CredentialsInput({ size="small" onClick={handleActionButtonClick} className="w-fit" + type="button" > {actionButtonText} diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/components/CredentialRow/CredentialRow.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/components/CredentialRow/CredentialRow.tsx index 21ec1200e4..2d0358aacb 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/components/CredentialRow/CredentialRow.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/components/CredentialRow/CredentialRow.tsx @@ -30,6 +30,8 @@ type CredentialRowProps = { readOnly?: boolean; showCaret?: boolean; asSelectTrigger?: boolean; + /** When "node", applies compact styling for node context */ + variant?: "default" | "node"; }; export function CredentialRow({ @@ -41,14 +43,22 @@ export function CredentialRow({ readOnly = false, showCaret = false, asSelectTrigger = false, + variant = "default", }: CredentialRowProps) { const ProviderIcon = providerIcons[provider] || fallbackIcon; + const isNodeVariant = variant === "node"; return (
-
+
{getCredentialDisplayName(credential, displayName)} - - {"*".repeat(MASKED_KEY_LENGTH)} - + {!(asSelectTrigger && isNodeVariant) && ( + + {"*".repeat(MASKED_KEY_LENGTH)} + + )}
{showCaret && !asSelectTrigger && ( diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/components/CredentialsSelect/CredentialsSelect.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/components/CredentialsSelect/CredentialsSelect.tsx index 7adfa5772b..6e1ec2afb1 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/components/CredentialsSelect/CredentialsSelect.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/CredentialsInputs/components/CredentialsSelect/CredentialsSelect.tsx @@ -7,6 +7,7 @@ import { } from "@/components/__legacy__/ui/select"; import { Text } from "@/components/atoms/Text/Text"; import { CredentialsMetaInput } from "@/lib/autogpt-server-api/types"; +import { cn } from "@/lib/utils"; import { useEffect } from "react"; import { getCredentialDisplayName } from "../../helpers"; import { CredentialRow } from "../CredentialRow/CredentialRow"; @@ -23,7 +24,11 @@ interface Props { displayName: string; selectedCredentials?: CredentialsMetaInput; onSelectCredential: (credentialId: string) => void; + onClearCredential?: () => void; readOnly?: boolean; + allowNone?: boolean; + /** When "node", applies compact styling for node context */ + variant?: "default" | "node"; } export function CredentialsSelect({ @@ -32,22 +37,38 @@ export function CredentialsSelect({ displayName, selectedCredentials, onSelectCredential, + onClearCredential, readOnly = false, + allowNone = true, + variant = "default", }: Props) { - // Auto-select first credential if none is selected + // Auto-select first credential if none is selected (only if allowNone is false) useEffect(() => { - if (!selectedCredentials && credentials.length > 0) { + if (!allowNone && !selectedCredentials && credentials.length > 0) { onSelectCredential(credentials[0].id); } - }, [selectedCredentials, credentials, onSelectCredential]); + }, [allowNone, selectedCredentials, credentials, onSelectCredential]); + + const handleValueChange = (value: string) => { + if (value === "__none__") { + onClearCredential?.(); + } else { + onSelectCredential(value); + } + }; return (
setIsFocused(true)} - onBlur={() => !inputRef.current?.value && setIsFocused(false)} + label="Search agents" + id="library-search-bar" + hideLabel onChange={handleSearchInput} - className="flex-1 border-none font-sans text-[16px] font-normal leading-7 shadow-none focus:shadow-none focus:ring-0" + className="min-w-[18rem] pl-12 lg:min-w-[30rem]" type="text" data-testid="library-textbox" placeholder="Search agents" /> - - {isFocused && inputRef.current?.value && ( - - )}
); } diff --git a/autogpt_platform/frontend/src/app/(platform)/library/components/LibrarySearchBar/useLibrarySearchbar.tsx b/autogpt_platform/frontend/src/app/(platform)/library/components/LibrarySearchBar/useLibrarySearchbar.tsx index f6428c6c4e..74b8e9874c 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/components/LibrarySearchBar/useLibrarySearchbar.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/components/LibrarySearchBar/useLibrarySearchbar.tsx @@ -1,36 +1,30 @@ -import { useRef, useState } from "react"; -import { useLibraryPageContext } from "../state-provider"; import { debounce } from "lodash"; +import { useCallback, useEffect } from "react"; -export const useLibrarySearchbar = () => { - const inputRef = useRef(null); - const [isFocused, setIsFocused] = useState(false); - const { setSearchTerm } = useLibraryPageContext(); +interface Props { + setSearchTerm: (value: string) => void; +} - const debouncedSearch = debounce((value: string) => { - setSearchTerm(value); - }, 300); +export function useLibrarySearchbar({ setSearchTerm }: Props) { + const debouncedSearch = useCallback( + debounce((value: string) => { + setSearchTerm(value); + }, 300), + [setSearchTerm], + ); - const handleSearchInput = (e: React.ChangeEvent) => { + useEffect(() => { + return () => { + debouncedSearch.cancel(); + }; + }, [debouncedSearch]); + + function handleSearchInput(e: React.ChangeEvent) { const searchTerm = e.target.value; debouncedSearch(searchTerm); - }; - - const handleClear = (e: React.MouseEvent) => { - if (inputRef.current) { - inputRef.current.value = ""; - inputRef.current.blur(); - setSearchTerm(""); - e.preventDefault(); - } - setIsFocused(false); - }; + } return { - handleClear, handleSearchInput, - isFocused, - inputRef, - setIsFocused, }; -}; +} diff --git a/autogpt_platform/frontend/src/app/(platform)/library/components/LibrarySortMenu/LibrarySortMenu.tsx b/autogpt_platform/frontend/src/app/(platform)/library/components/LibrarySortMenu/LibrarySortMenu.tsx index ac4ed060f2..de37af5fad 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/components/LibrarySortMenu/LibrarySortMenu.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/components/LibrarySortMenu/LibrarySortMenu.tsx @@ -1,5 +1,5 @@ "use client"; -import { ArrowDownNarrowWideIcon } from "lucide-react"; +import { LibraryAgentSort } from "@/app/api/__generated__/models/libraryAgentSort"; import { Select, SelectContent, @@ -8,11 +8,15 @@ import { SelectTrigger, SelectValue, } from "@/components/__legacy__/ui/select"; -import { LibraryAgentSort } from "@/app/api/__generated__/models/libraryAgentSort"; +import { ArrowDownNarrowWideIcon } from "lucide-react"; import { useLibrarySortMenu } from "./useLibrarySortMenu"; -export default function LibrarySortMenu(): React.ReactNode { - const { handleSortChange } = useLibrarySortMenu(); +interface Props { + setLibrarySort: (value: LibraryAgentSort) => void; +} + +export function LibrarySortMenu({ setLibrarySort }: Props) { + const { handleSortChange } = useLibrarySortMenu({ setLibrarySort }); return (
sort by diff --git a/autogpt_platform/frontend/src/app/(platform)/library/components/LibrarySortMenu/useLibrarySortMenu.ts b/autogpt_platform/frontend/src/app/(platform)/library/components/LibrarySortMenu/useLibrarySortMenu.ts index d2575c8936..e6d6f2d127 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/components/LibrarySortMenu/useLibrarySortMenu.ts +++ b/autogpt_platform/frontend/src/app/(platform)/library/components/LibrarySortMenu/useLibrarySortMenu.ts @@ -1,11 +1,11 @@ import { LibraryAgentSort } from "@/app/api/__generated__/models/libraryAgentSort"; -import { useLibraryPageContext } from "../state-provider"; -export const useLibrarySortMenu = () => { - const { setLibrarySort } = useLibraryPageContext(); +interface Props { + setLibrarySort: (value: LibraryAgentSort) => void; +} +export function useLibrarySortMenu({ setLibrarySort }: Props) { const handleSortChange = (value: LibraryAgentSort) => { - // Simply updating the sort state - React Query will handle the rest setLibrarySort(value); }; @@ -24,4 +24,4 @@ export const useLibrarySortMenu = () => { handleSortChange, getSortLabel, }; -}; +} diff --git a/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryUploadAgentDialog/LibraryUploadAgentDialog.tsx b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryUploadAgentDialog/LibraryUploadAgentDialog.tsx index d92bbe86fe..1a6999721e 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryUploadAgentDialog/LibraryUploadAgentDialog.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryUploadAgentDialog/LibraryUploadAgentDialog.tsx @@ -1,192 +1,134 @@ "use client"; -import { Upload, X } from "lucide-react"; -import { Button } from "@/components/__legacy__/Button"; -import { - Dialog, - DialogContent, - DialogDescription, - DialogHeader, - DialogTitle, - DialogTrigger, -} from "@/components/__legacy__/ui/dialog"; -import { z } from "zod"; -import { FileUploader } from "react-drag-drop-files"; +import { Button } from "@/components/atoms/Button/Button"; +import { FileInput } from "@/components/atoms/FileInput/FileInput"; +import { Input } from "@/components/atoms/Input/Input"; +import { Dialog } from "@/components/molecules/Dialog/Dialog"; import { Form, FormControl, FormField, FormItem, - FormLabel, FormMessage, -} from "@/components/__legacy__/ui/form"; -import { Input } from "@/components/__legacy__/ui/input"; -import { Textarea } from "@/components/__legacy__/ui/textarea"; +} from "@/components/molecules/Form/Form"; +import { UploadSimpleIcon } from "@phosphor-icons/react"; +import { z } from "zod"; import { useLibraryUploadAgentDialog } from "./useLibraryUploadAgentDialog"; -const fileTypes = ["JSON"]; - -const fileSchema = z.custom((val) => val instanceof File, { - message: "Must be a File object", -}); - export const uploadAgentFormSchema = z.object({ - agentFile: fileSchema, + agentFile: z.string().min(1, "Agent file is required"), agentName: z.string().min(1, "Agent name is required"), agentDescription: z.string(), }); -export default function LibraryUploadAgentDialog(): React.ReactNode { - const { - onSubmit, - isUploading, - isOpen, - setIsOpen, - isDroped, - handleChange, - form, - setisDroped, - agentObject, - clearAgentFile, - } = useLibraryUploadAgentDialog(); +export default function LibraryUploadAgentDialog() { + const { onSubmit, isUploading, isOpen, setIsOpen, form, agentObject } = + useLibraryUploadAgentDialog(); + return ( - - + { + setIsOpen(false); + }} + > + - - - - Upload Agent - - Upload your agent by providing a name, description, and JSON file. - - + + +
+ ( + + + + + + + )} + /> - - - ( - - Agent name - - - - - - )} - /> + ( + + + + + + + )} + /> - ( - - Description - -