diff --git a/.github/workflows/platform-frontend-ci.yml b/.github/workflows/platform-frontend-ci.yml
index 97b4d38e06..486a7d07f5 100644
--- a/.github/workflows/platform-frontend-ci.yml
+++ b/.github/workflows/platform-frontend-ci.yml
@@ -55,6 +55,9 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile
+ - name: Generate API client
+ run: pnpm generate:api-client
+
- name: Run tsc check
run: pnpm type-check
diff --git a/.gitignore b/.gitignore
index d00ab276ce..b6c2fdc035 100644
--- a/.gitignore
+++ b/.gitignore
@@ -165,7 +165,7 @@ package-lock.json
# Allow for locally private items
# private
-pri*
+pri*
# ignore
ig*
.github_access_token
@@ -176,3 +176,7 @@ autogpt_platform/backend/settings.py
*.ign.*
.test-contents
+.claude/settings.local.json
+
+# Auto generated client
+autogpt_platform/frontend/src/api/__generated__
diff --git a/autogpt_platform/CLAUDE.md b/autogpt_platform/CLAUDE.md
index 30bb2496bd..93f64e1eb3 100644
--- a/autogpt_platform/CLAUDE.md
+++ b/autogpt_platform/CLAUDE.md
@@ -32,6 +32,7 @@ poetry run test
poetry run pytest path/to/test_file.py::test_function_name
# Lint and format
+# prefer format if you want to just "fix" it and only get the errors that can't be autofixed
poetry run format # Black + isort
poetry run lint # ruff
```
@@ -77,6 +78,7 @@ npm run type-check
- **Queue System**: RabbitMQ for async task processing
- **Execution Engine**: Separate executor service processes agent workflows
- **Authentication**: JWT-based with Supabase integration
+- **Security**: Cache protection middleware prevents sensitive data caching in browsers/proxies
### Frontend Architecture
- **Framework**: Next.js App Router with React Server Components
@@ -129,4 +131,15 @@ Key models (defined in `/backend/schema.prisma`):
1. Components go in `/frontend/src/components/`
2. Use existing UI components from `/frontend/src/components/ui/`
3. Add Storybook stories for new components
-4. Test with Playwright if user-facing
\ No newline at end of file
+4. Test with Playwright if user-facing
+
+### Security Implementation
+
+**Cache Protection Middleware:**
+- Located in `/backend/backend/server/middleware/security.py`
+- Default behavior: Disables caching for ALL endpoints with `Cache-Control: no-store, no-cache, must-revalidate, private`
+- Uses an allow list approach - only explicitly permitted paths can be cached
+- Cacheable paths include: static assets (`/static/*`, `/_next/static/*`), health checks, public store pages, documentation
+- Prevents sensitive data (auth tokens, API keys, user data) from being cached by browsers/proxies
+- To allow caching for a new endpoint, add it to `CACHEABLE_PATHS` in the middleware
+- Applied to both main API server and external API applications
\ No newline at end of file
diff --git a/autogpt_platform/README.md b/autogpt_platform/README.md
index 6d535d5543..8422a29f0e 100644
--- a/autogpt_platform/README.md
+++ b/autogpt_platform/README.md
@@ -62,6 +62,12 @@ To run the AutoGPT Platform, follow these steps:
pnpm i
```
+ Generate the API client (this step is required before running the frontend):
+
+ ```
+ pnpm generate:api-client
+ ```
+
Then start the frontend application in development mode:
```
@@ -164,3 +170,27 @@ To persist data for PostgreSQL and Redis, you can modify the `docker-compose.yml
3. Save the file and run `docker compose up -d` to apply the changes.
This configuration will create named volumes for PostgreSQL and Redis, ensuring that your data persists across container restarts.
+
+### API Client Generation
+
+The platform includes scripts for generating and managing the API client:
+
+- `pnpm fetch:openapi`: Fetches the OpenAPI specification from the backend service (requires backend to be running on port 8006)
+- `pnpm generate:api-client`: Generates the TypeScript API client from the OpenAPI specification using Orval
+- `pnpm generate:api-all`: Runs both fetch and generate commands in sequence
+
+#### Manual API Client Updates
+
+If you need to update the API client after making changes to the backend API:
+
+1. Ensure the backend services are running:
+ ```
+ docker compose up -d
+ ```
+
+2. Generate the updated API client:
+ ```
+ pnpm generate:api-all
+ ```
+
+This will fetch the latest OpenAPI specification and regenerate the TypeScript client code.
diff --git a/autogpt_platform/autogpt_libs/autogpt_libs/api_key/key_manager.py b/autogpt_platform/autogpt_libs/autogpt_libs/api_key/key_manager.py
index 257250a753..0ac5f8793c 100644
--- a/autogpt_platform/autogpt_libs/autogpt_libs/api_key/key_manager.py
+++ b/autogpt_platform/autogpt_libs/autogpt_libs/api_key/key_manager.py
@@ -31,4 +31,5 @@ class APIKeyManager:
"""Verify if a provided API key matches the stored hash."""
if not provided_key.startswith(self.PREFIX):
return False
- return hashlib.sha256(provided_key.encode()).hexdigest() == stored_hash
+ provided_hash = hashlib.sha256(provided_key.encode()).hexdigest()
+ return secrets.compare_digest(provided_hash, stored_hash)
diff --git a/autogpt_platform/autogpt_libs/autogpt_libs/auth/middleware.py b/autogpt_platform/autogpt_libs/autogpt_libs/auth/middleware.py
index d00fe1a05d..eb583ac1fc 100644
--- a/autogpt_platform/autogpt_libs/autogpt_libs/auth/middleware.py
+++ b/autogpt_platform/autogpt_libs/autogpt_libs/auth/middleware.py
@@ -1,5 +1,6 @@
import inspect
import logging
+import secrets
from typing import Any, Callable, Optional
from fastapi import HTTPException, Request, Security
@@ -93,7 +94,11 @@ class APIKeyValidator:
self.error_message = error_message
async def default_validator(self, api_key: str) -> bool:
- return api_key == self.expected_token
+ if not self.expected_token:
+ raise ValueError(
+ "Expected Token Required to be set when uisng API Key Validator default validation"
+ )
+ return secrets.compare_digest(api_key, self.expected_token)
async def __call__(
self, request: Request, api_key: str = Security(APIKeyHeader)
diff --git a/autogpt_platform/autogpt_libs/autogpt_libs/utils/synchronize.py b/autogpt_platform/autogpt_libs/autogpt_libs/utils/synchronize.py
index d8221eea0f..348ae4d78d 100644
--- a/autogpt_platform/autogpt_libs/autogpt_libs/utils/synchronize.py
+++ b/autogpt_platform/autogpt_libs/autogpt_libs/utils/synchronize.py
@@ -1,15 +1,15 @@
-from contextlib import contextmanager
-from threading import Lock
+import asyncio
+from contextlib import asynccontextmanager
from typing import TYPE_CHECKING, Any
from expiringdict import ExpiringDict
if TYPE_CHECKING:
- from redis import Redis
- from redis.lock import Lock as RedisLock
+ from redis.asyncio import Redis as AsyncRedis
+ from redis.asyncio.lock import Lock as AsyncRedisLock
-class RedisKeyedMutex:
+class AsyncRedisKeyedMutex:
"""
This class provides a mutex that can be locked and unlocked by a specific key,
using Redis as a distributed locking provider.
@@ -17,41 +17,45 @@ class RedisKeyedMutex:
in case the key is not unlocked for a specified duration, to prevent memory leaks.
"""
- def __init__(self, redis: "Redis", timeout: int | None = 60):
+ def __init__(self, redis: "AsyncRedis", timeout: int | None = 60):
self.redis = redis
self.timeout = timeout
- self.locks: dict[Any, "RedisLock"] = ExpiringDict(
+ self.locks: dict[Any, "AsyncRedisLock"] = ExpiringDict(
max_len=6000, max_age_seconds=self.timeout
)
- self.locks_lock = Lock()
+ self.locks_lock = asyncio.Lock()
- @contextmanager
- def locked(self, key: Any):
- lock = self.acquire(key)
+ @asynccontextmanager
+ async def locked(self, key: Any):
+ lock = await self.acquire(key)
try:
yield
finally:
- if lock.locked() and lock.owned():
- lock.release()
+ if (await lock.locked()) and (await lock.owned()):
+ await lock.release()
- def acquire(self, key: Any) -> "RedisLock":
+ async def acquire(self, key: Any) -> "AsyncRedisLock":
"""Acquires and returns a lock with the given key"""
- with self.locks_lock:
+ async with self.locks_lock:
if key not in self.locks:
self.locks[key] = self.redis.lock(
str(key), self.timeout, thread_local=False
)
lock = self.locks[key]
- lock.acquire()
+ await lock.acquire()
return lock
- def release(self, key: Any):
- if (lock := self.locks.get(key)) and lock.locked() and lock.owned():
- lock.release()
+ async def release(self, key: Any):
+ if (
+ (lock := self.locks.get(key))
+ and (await lock.locked())
+ and (await lock.owned())
+ ):
+ await lock.release()
- def release_all_locks(self):
+ async def release_all_locks(self):
"""Call this on process termination to ensure all locks are released"""
- self.locks_lock.acquire(blocking=False)
- for lock in self.locks.values():
- if lock.locked() and lock.owned():
- lock.release()
+ async with self.locks_lock:
+ for lock in self.locks.values():
+ if (await lock.locked()) and (await lock.owned()):
+ await lock.release()
diff --git a/autogpt_platform/autogpt_libs/poetry.lock b/autogpt_platform/autogpt_libs/poetry.lock
index 12a4970d50..155098d059 100644
--- a/autogpt_platform/autogpt_libs/poetry.lock
+++ b/autogpt_platform/autogpt_libs/poetry.lock
@@ -1,4 +1,4 @@
-# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand.
+# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand.
[[package]]
name = "aiohappyeyeballs"
@@ -177,7 +177,7 @@ files = [
{file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"},
{file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"},
]
-markers = {main = "python_version < \"3.11\"", dev = "python_full_version < \"3.11.3\""}
+markers = {main = "python_version == \"3.10\"", dev = "python_full_version < \"3.11.3\""}
[[package]]
name = "attrs"
@@ -323,6 +323,21 @@ files = [
{file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"},
]
+[[package]]
+name = "click"
+version = "8.2.1"
+description = "Composable command line interface toolkit"
+optional = false
+python-versions = ">=3.10"
+groups = ["main"]
+files = [
+ {file = "click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b"},
+ {file = "click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202"},
+]
+
+[package.dependencies]
+colorama = {version = "*", markers = "platform_system == \"Windows\""}
+
[[package]]
name = "colorama"
version = "0.4.6"
@@ -375,7 +390,7 @@ description = "Backport of PEP 654 (exception groups)"
optional = false
python-versions = ">=3.7"
groups = ["main"]
-markers = "python_version < \"3.11\""
+markers = "python_version == \"3.10\""
files = [
{file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"},
{file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"},
@@ -399,6 +414,27 @@ files = [
[package.extras]
tests = ["coverage", "coveralls", "dill", "mock", "nose"]
+[[package]]
+name = "fastapi"
+version = "0.115.12"
+description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "fastapi-0.115.12-py3-none-any.whl", hash = "sha256:e94613d6c05e27be7ffebdd6ea5f388112e5e430c8f7d6494a9d1d88d43e814d"},
+ {file = "fastapi-0.115.12.tar.gz", hash = "sha256:1e2c2a2646905f9e83d32f04a3f86aff4a286669c6c950ca95b5fd68c2602681"},
+]
+
+[package.dependencies]
+pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0"
+starlette = ">=0.40.0,<0.47.0"
+typing-extensions = ">=4.8.0"
+
+[package.extras]
+all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=3.1.5)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"]
+standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "jinja2 (>=3.1.5)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"]
+
[[package]]
name = "frozenlist"
version = "1.4.1"
@@ -895,6 +931,47 @@ files = [
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
]
+[[package]]
+name = "launchdarkly-eventsource"
+version = "1.2.4"
+description = "LaunchDarkly SSE Client"
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "launchdarkly_eventsource-1.2.4-py3-none-any.whl", hash = "sha256:048ef8c4440d0d8219778661ee4d4b5e12aa6ed2c29a3004417ede44c2386e8c"},
+ {file = "launchdarkly_eventsource-1.2.4.tar.gz", hash = "sha256:b8b9342681f55e1d35c56243431cbbaca4eb9812d6785f8de204af322104e066"},
+]
+
+[package.dependencies]
+urllib3 = ">=1.26.0,<3"
+
+[[package]]
+name = "launchdarkly-server-sdk"
+version = "9.11.1"
+description = "LaunchDarkly SDK for Python"
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "launchdarkly_server_sdk-9.11.1-py3-none-any.whl", hash = "sha256:128569cebf666dd115cc0ba03c48ff75f6acc9788301a7e2c3a54d06107e445a"},
+ {file = "launchdarkly_server_sdk-9.11.1.tar.gz", hash = "sha256:150e29656cb8c506d1967f3c59e62b69310d345ec27217640a6146dd1db5d250"},
+]
+
+[package.dependencies]
+certifi = ">=2018.4.16"
+expiringdict = ">=1.1.4"
+launchdarkly-eventsource = ">=1.2.4,<2.0.0"
+pyRFC3339 = ">=1.0"
+semver = ">=2.10.2"
+urllib3 = ">=1.26.0,<3"
+
+[package.extras]
+consul = ["python-consul (>=1.0.1)"]
+dynamodb = ["boto3 (>=1.9.71)"]
+redis = ["redis (>=2.10.5)"]
+test-filesource = ["pyyaml (>=5.3.1)", "watchdog (>=3.0.0)"]
+
[[package]]
name = "multidict"
version = "6.1.0"
@@ -1412,6 +1489,18 @@ dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pyte
docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"]
tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"]
+[[package]]
+name = "pyrfc3339"
+version = "2.0.1"
+description = "Generate and parse RFC 3339 timestamps"
+optional = false
+python-versions = "*"
+groups = ["main"]
+files = [
+ {file = "pyRFC3339-2.0.1-py3-none-any.whl", hash = "sha256:30b70a366acac3df7386b558c21af871522560ed7f3f73cf344b8c2cbb8b0c9d"},
+ {file = "pyrfc3339-2.0.1.tar.gz", hash = "sha256:e47843379ea35c1296c3b6c67a948a1a490ae0584edfcbdea0eaffb5dd29960b"},
+]
+
[[package]]
name = "pytest"
version = "8.3.3"
@@ -1604,6 +1693,18 @@ files = [
{file = "ruff-0.11.10.tar.gz", hash = "sha256:d522fb204b4959909ecac47da02830daec102eeb100fb50ea9554818d47a5fa6"},
]
+[[package]]
+name = "semver"
+version = "3.0.4"
+description = "Python helper for Semantic Versioning (https://semver.org)"
+optional = false
+python-versions = ">=3.7"
+groups = ["main"]
+files = [
+ {file = "semver-3.0.4-py3-none-any.whl", hash = "sha256:9c824d87ba7f7ab4a1890799cec8596f15c1241cb473404ea1cb0c55e4b04746"},
+ {file = "semver-3.0.4.tar.gz", hash = "sha256:afc7d8c584a5ed0a11033af086e8af226a9c0b206f313e0301f8dd7b6b589602"},
+]
+
[[package]]
name = "six"
version = "1.16.0"
@@ -1628,6 +1729,24 @@ files = [
{file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
]
+[[package]]
+name = "starlette"
+version = "0.46.2"
+description = "The little ASGI library that shines."
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "starlette-0.46.2-py3-none-any.whl", hash = "sha256:595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35"},
+ {file = "starlette-0.46.2.tar.gz", hash = "sha256:7f7361f34eed179294600af672f565727419830b54b7b084efe44bb82d2fccd5"},
+]
+
+[package.dependencies]
+anyio = ">=3.6.2,<5"
+
+[package.extras]
+full = ["httpx (>=0.27.0,<0.29.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.18)", "pyyaml"]
+
[[package]]
name = "storage3"
version = "0.11.0"
@@ -1704,7 +1823,7 @@ description = "A lil' TOML parser"
optional = false
python-versions = ">=3.8"
groups = ["main"]
-markers = "python_version < \"3.11\""
+markers = "python_version == \"3.10\""
files = [
{file = "tomli-2.1.0-py3-none-any.whl", hash = "sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391"},
{file = "tomli-2.1.0.tar.gz", hash = "sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8"},
@@ -1755,6 +1874,26 @@ h2 = ["h2 (>=4,<5)"]
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
zstd = ["zstandard (>=0.18.0)"]
+[[package]]
+name = "uvicorn"
+version = "0.34.3"
+description = "The lightning-fast ASGI server."
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "uvicorn-0.34.3-py3-none-any.whl", hash = "sha256:16246631db62bdfbf069b0645177d6e8a77ba950cfedbfd093acef9444e4d885"},
+ {file = "uvicorn-0.34.3.tar.gz", hash = "sha256:35919a9a979d7a59334b6b10e05d77c1d0d574c50e0fc98b8b1a0f165708b55a"},
+]
+
+[package.dependencies]
+click = ">=7.0"
+h11 = ">=0.8"
+typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""}
+
+[package.extras]
+standard = ["colorama (>=0.4) ; sys_platform == \"win32\"", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.15.1) ; sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"", "watchfiles (>=0.13)", "websockets (>=10.4)"]
+
[[package]]
name = "websockets"
version = "12.0"
@@ -2037,4 +2176,4 @@ type = ["pytest-mypy"]
[metadata]
lock-version = "2.1"
python-versions = ">=3.10,<4.0"
-content-hash = "78ebf65cdef769cfbe92fe204f01e32d219cca9ee5a6ca9e657aa0630be63802"
+content-hash = "d92143928a88ca3a56ac200c335910eafac938940022fed8bd0d17c95040b54f"
diff --git a/autogpt_platform/autogpt_libs/pyproject.toml b/autogpt_platform/autogpt_libs/pyproject.toml
index 2f2d05ac7a..71d6eeb1f6 100644
--- a/autogpt_platform/autogpt_libs/pyproject.toml
+++ b/autogpt_platform/autogpt_libs/pyproject.toml
@@ -17,6 +17,9 @@ pyjwt = "^2.10.1"
pytest-asyncio = "^0.26.0"
pytest-mock = "^3.14.0"
supabase = "^2.15.1"
+launchdarkly-server-sdk = "^9.11.1"
+fastapi = "^0.115.12"
+uvicorn = "^0.34.3"
[tool.poetry.group.dev.dependencies]
redis = "^5.2.1"
diff --git a/autogpt_platform/backend/.env.example b/autogpt_platform/backend/.env.example
index 4c5830d704..18343d7725 100644
--- a/autogpt_platform/backend/.env.example
+++ b/autogpt_platform/backend/.env.example
@@ -13,7 +13,6 @@ PRISMA_SCHEMA="postgres/schema.prisma"
# EXECUTOR
NUM_GRAPH_WORKERS=10
-NUM_NODE_WORKERS=3
BACKEND_CORS_ALLOW_ORIGINS=["http://localhost:3000"]
diff --git a/autogpt_platform/backend/backend/blocks/agent.py b/autogpt_platform/backend/backend/blocks/agent.py
index a68cb05204..c25d99458d 100644
--- a/autogpt_platform/backend/backend/blocks/agent.py
+++ b/autogpt_platform/backend/backend/blocks/agent.py
@@ -1,3 +1,4 @@
+import asyncio
import logging
from typing import Any, Optional
@@ -61,37 +62,78 @@ class AgentExecutorBlock(Block):
categories={BlockCategory.AGENT},
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
- from backend.data.execution import ExecutionEventType
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
+
from backend.executor import utils as execution_utils
- event_bus = execution_utils.get_execution_event_bus()
-
- graph_exec = execution_utils.add_graph_execution(
+ graph_exec = await execution_utils.add_graph_execution(
graph_id=input_data.graph_id,
graph_version=input_data.graph_version,
user_id=input_data.user_id,
inputs=input_data.inputs,
node_credentials_input_map=input_data.node_credentials_input_map,
+ use_db_query=False,
)
- log_id = f"Graph #{input_data.graph_id}-V{input_data.graph_version}, exec-id: {graph_exec.id}"
+
+ try:
+ async for name, data in self._run(
+ graph_id=input_data.graph_id,
+ graph_version=input_data.graph_version,
+ graph_exec_id=graph_exec.id,
+ user_id=input_data.user_id,
+ ):
+ yield name, data
+ except asyncio.CancelledError:
+ logger.warning(
+ f"Execution of graph {input_data.graph_id} version {input_data.graph_version} was cancelled."
+ )
+ await execution_utils.stop_graph_execution(
+ graph_exec.id, use_db_query=False
+ )
+ except Exception as e:
+ logger.error(
+ f"Execution of graph {input_data.graph_id} version {input_data.graph_version} failed: {e}, stopping execution."
+ )
+ await execution_utils.stop_graph_execution(
+ graph_exec.id, use_db_query=False
+ )
+ raise
+
+ async def _run(
+ self,
+ graph_id: str,
+ graph_version: int,
+ graph_exec_id: str,
+ user_id: str,
+ ) -> BlockOutput:
+
+ from backend.data.execution import ExecutionEventType
+ from backend.executor import utils as execution_utils
+
+ event_bus = execution_utils.get_async_execution_event_bus()
+
+ log_id = f"Graph #{graph_id}-V{graph_version}, exec-id: {graph_exec_id}"
logger.info(f"Starting execution of {log_id}")
- for event in event_bus.listen(
- user_id=graph_exec.user_id,
- graph_id=graph_exec.graph_id,
- graph_exec_id=graph_exec.id,
+ async for event in event_bus.listen(
+ user_id=user_id,
+ graph_id=graph_id,
+ graph_exec_id=graph_exec_id,
):
+ if event.status not in [
+ ExecutionStatus.COMPLETED,
+ ExecutionStatus.TERMINATED,
+ ExecutionStatus.FAILED,
+ ]:
+ logger.debug(
+ f"Execution {log_id} received event {event.event_type} with status {event.status}"
+ )
+ continue
+
if event.event_type == ExecutionEventType.GRAPH_EXEC_UPDATE:
- if event.status in [
- ExecutionStatus.COMPLETED,
- ExecutionStatus.TERMINATED,
- ExecutionStatus.FAILED,
- ]:
- logger.info(f"Execution {log_id} ended with status {event.status}")
- break
- else:
- continue
+ # If the graph execution is COMPLETED, TERMINATED, or FAILED,
+ # we can stop listening for further events.
+ break
logger.debug(
f"Execution {log_id} produced input {event.input_data} output {event.output_data}"
diff --git a/autogpt_platform/backend/backend/blocks/ai_image_generator_block.py b/autogpt_platform/backend/backend/blocks/ai_image_generator_block.py
index 230f3acd88..39c0d4ac54 100644
--- a/autogpt_platform/backend/backend/blocks/ai_image_generator_block.py
+++ b/autogpt_platform/backend/backend/blocks/ai_image_generator_block.py
@@ -165,7 +165,7 @@ class AIImageGeneratorBlock(Block):
},
)
- def _run_client(
+ async def _run_client(
self, credentials: APIKeyCredentials, model_name: str, input_params: dict
):
try:
@@ -173,7 +173,7 @@ class AIImageGeneratorBlock(Block):
client = ReplicateClient(api_token=credentials.api_key.get_secret_value())
# Run the model with input parameters
- output = client.run(model_name, input=input_params, wait=False)
+ output = await client.async_run(model_name, input=input_params, wait=False)
# Process output
if isinstance(output, list) and len(output) > 0:
@@ -195,7 +195,7 @@ class AIImageGeneratorBlock(Block):
except Exception as e:
raise RuntimeError(f"Unexpected error during model execution: {e}")
- def generate_image(self, input_data: Input, credentials: APIKeyCredentials):
+ async def generate_image(self, input_data: Input, credentials: APIKeyCredentials):
try:
# Handle style-based prompt modification for models without native style support
modified_prompt = input_data.prompt
@@ -213,7 +213,7 @@ class AIImageGeneratorBlock(Block):
"steps": 40,
"cfg_scale": 7.0,
}
- output = self._run_client(
+ output = await self._run_client(
credentials,
"stability-ai/stable-diffusion-3.5-medium",
input_params,
@@ -231,7 +231,7 @@ class AIImageGeneratorBlock(Block):
"output_format": "jpg", # Set to jpg for Flux models
"output_quality": 90,
}
- output = self._run_client(
+ output = await self._run_client(
credentials, "black-forest-labs/flux-1.1-pro", input_params
)
return output
@@ -246,7 +246,7 @@ class AIImageGeneratorBlock(Block):
"output_format": "jpg",
"output_quality": 90,
}
- output = self._run_client(
+ output = await self._run_client(
credentials, "black-forest-labs/flux-1.1-pro-ultra", input_params
)
return output
@@ -257,7 +257,7 @@ class AIImageGeneratorBlock(Block):
"size": SIZE_TO_RECRAFT_DIMENSIONS[input_data.size],
"style": input_data.style.value,
}
- output = self._run_client(
+ output = await self._run_client(
credentials, "recraft-ai/recraft-v3", input_params
)
return output
@@ -296,9 +296,9 @@ class AIImageGeneratorBlock(Block):
style_text = style_map.get(style, "")
return f"{style_text} of" if style_text else ""
- def run(self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs):
+ async def run(self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs):
try:
- url = self.generate_image(input_data, credentials)
+ url = await self.generate_image(input_data, credentials)
if url:
yield "image_url", url
else:
diff --git a/autogpt_platform/backend/backend/blocks/ai_music_generator.py b/autogpt_platform/backend/backend/blocks/ai_music_generator.py
index ce9cf45498..b4561bd513 100644
--- a/autogpt_platform/backend/backend/blocks/ai_music_generator.py
+++ b/autogpt_platform/backend/backend/blocks/ai_music_generator.py
@@ -1,5 +1,5 @@
+import asyncio
import logging
-import time
from enum import Enum
from typing import Literal
@@ -142,7 +142,7 @@ class AIMusicGeneratorBlock(Block):
test_credentials=TEST_CREDENTIALS,
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
max_retries = 3
@@ -154,7 +154,7 @@ class AIMusicGeneratorBlock(Block):
logger.debug(
f"[AIMusicGeneratorBlock] - Running model (attempt {attempt + 1})"
)
- result = self.run_model(
+ result = await self.run_model(
api_key=credentials.api_key,
music_gen_model_version=input_data.music_gen_model_version,
prompt=input_data.prompt,
@@ -176,13 +176,13 @@ class AIMusicGeneratorBlock(Block):
last_error = f"Unexpected error: {str(e)}"
logger.error(f"[AIMusicGeneratorBlock] - Error: {last_error}")
if attempt < max_retries - 1:
- time.sleep(retry_delay)
+ await asyncio.sleep(retry_delay)
continue
# If we've exhausted all retries, yield the error
yield "error", f"Failed after {max_retries} attempts. Last error: {last_error}"
- def run_model(
+ async def run_model(
self,
api_key: SecretStr,
music_gen_model_version: MusicGenModelVersion,
@@ -199,7 +199,7 @@ class AIMusicGeneratorBlock(Block):
client = ReplicateClient(api_token=api_key.get_secret_value())
# Run the model with parameters
- output = client.run(
+ output = await client.async_run(
"meta/musicgen:671ac645ce5e552cc63a54a2bbff63fcf798043055d2dac5fc9e36a837eedcfb",
input={
"prompt": prompt,
diff --git a/autogpt_platform/backend/backend/blocks/ai_shortform_video_block.py b/autogpt_platform/backend/backend/blocks/ai_shortform_video_block.py
index df2b3a2726..c3c4e36472 100644
--- a/autogpt_platform/backend/backend/blocks/ai_shortform_video_block.py
+++ b/autogpt_platform/backend/backend/blocks/ai_shortform_video_block.py
@@ -1,3 +1,4 @@
+import asyncio
import logging
import time
from enum import Enum
@@ -13,7 +14,7 @@ from backend.data.model import (
SchemaField,
)
from backend.integrations.providers import ProviderName
-from backend.util.request import requests
+from backend.util.request import Requests
TEST_CREDENTIALS = APIKeyCredentials(
id="01234567-89ab-cdef-0123-456789abcdef",
@@ -216,29 +217,29 @@ class AIShortformVideoCreatorBlock(Block):
test_credentials=TEST_CREDENTIALS,
)
- def create_webhook(self):
+ async def create_webhook(self):
url = "https://webhook.site/token"
headers = {"Accept": "application/json", "Content-Type": "application/json"}
- response = requests.post(url, headers=headers)
+ response = await Requests().post(url, headers=headers)
webhook_data = response.json()
return webhook_data["uuid"], f"https://webhook.site/{webhook_data['uuid']}"
- def create_video(self, api_key: SecretStr, payload: dict) -> dict:
+ async def create_video(self, api_key: SecretStr, payload: dict) -> dict:
url = "https://www.revid.ai/api/public/v2/render"
headers = {"key": api_key.get_secret_value()}
- response = requests.post(url, json=payload, headers=headers)
+ response = await Requests().post(url, json=payload, headers=headers)
logger.debug(
- f"API Response Status Code: {response.status_code}, Content: {response.text}"
+ f"API Response Status Code: {response.status}, Content: {response.text}"
)
return response.json()
- def check_video_status(self, api_key: SecretStr, pid: str) -> dict:
+ async def check_video_status(self, api_key: SecretStr, pid: str) -> dict:
url = f"https://www.revid.ai/api/public/v2/status?pid={pid}"
headers = {"key": api_key.get_secret_value()}
- response = requests.get(url, headers=headers)
+ response = await Requests().get(url, headers=headers)
return response.json()
- def wait_for_video(
+ async def wait_for_video(
self,
api_key: SecretStr,
pid: str,
@@ -247,7 +248,7 @@ class AIShortformVideoCreatorBlock(Block):
) -> str:
start_time = time.time()
while time.time() - start_time < max_wait_time:
- status = self.check_video_status(api_key, pid)
+ status = await self.check_video_status(api_key, pid)
logger.debug(f"Video status: {status}")
if status.get("status") == "ready" and "videoUrl" in status:
@@ -260,16 +261,16 @@ class AIShortformVideoCreatorBlock(Block):
logger.error(f"Video creation failed: {status.get('message')}")
raise ValueError(f"Video creation failed: {status.get('message')}")
- time.sleep(10)
+ await asyncio.sleep(10)
logger.error("Video creation timed out")
raise TimeoutError("Video creation timed out")
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
# Create a new Webhook.site URL
- webhook_token, webhook_url = self.create_webhook()
+ webhook_token, webhook_url = await self.create_webhook()
logger.debug(f"Webhook URL: {webhook_url}")
audio_url = input_data.background_music.audio_url
@@ -306,7 +307,7 @@ class AIShortformVideoCreatorBlock(Block):
}
logger.debug("Creating video...")
- response = self.create_video(credentials.api_key, payload)
+ response = await self.create_video(credentials.api_key, payload)
pid = response.get("pid")
if not pid:
@@ -318,6 +319,8 @@ class AIShortformVideoCreatorBlock(Block):
logger.debug(
f"Video created with project ID: {pid}. Waiting for completion..."
)
- video_url = self.wait_for_video(credentials.api_key, pid, webhook_token)
+ video_url = await self.wait_for_video(
+ credentials.api_key, pid, webhook_token
+ )
logger.debug(f"Video ready: {video_url}")
yield "video_url", video_url
diff --git a/autogpt_platform/backend/backend/blocks/apollo/_api.py b/autogpt_platform/backend/backend/blocks/apollo/_api.py
index 157235ff0f..dd4e6aa741 100644
--- a/autogpt_platform/backend/backend/blocks/apollo/_api.py
+++ b/autogpt_platform/backend/backend/blocks/apollo/_api.py
@@ -27,14 +27,15 @@ class ApolloClient:
def _get_headers(self) -> dict[str, str]:
return {"x-api-key": self.credentials.api_key.get_secret_value()}
- def search_people(self, query: SearchPeopleRequest) -> List[Contact]:
+ async def search_people(self, query: SearchPeopleRequest) -> List[Contact]:
"""Search for people in Apollo"""
- response = self.requests.get(
+ response = await self.requests.post(
f"{self.API_URL}/mixed_people/search",
headers=self._get_headers(),
- params=query.model_dump(exclude={"credentials", "max_results"}),
+ json=query.model_dump(exclude={"max_results"}),
)
- parsed_response = SearchPeopleResponse(**response.json())
+ data = response.json()
+ parsed_response = SearchPeopleResponse(**data)
if parsed_response.pagination.total_entries == 0:
return []
@@ -52,27 +53,29 @@ class ApolloClient:
and len(parsed_response.people) > 0
):
query.page += 1
- response = self.requests.get(
+ response = await self.requests.post(
f"{self.API_URL}/mixed_people/search",
headers=self._get_headers(),
- params=query.model_dump(exclude={"credentials", "max_results"}),
+ json=query.model_dump(exclude={"max_results"}),
)
- parsed_response = SearchPeopleResponse(**response.json())
+ data = response.json()
+ parsed_response = SearchPeopleResponse(**data)
people.extend(parsed_response.people[: query.max_results - len(people)])
logger.info(f"Found {len(people)} people")
return people[: query.max_results] if query.max_results else people
- def search_organizations(
+ async def search_organizations(
self, query: SearchOrganizationsRequest
) -> List[Organization]:
"""Search for organizations in Apollo"""
- response = self.requests.get(
+ response = await self.requests.post(
f"{self.API_URL}/mixed_companies/search",
headers=self._get_headers(),
- params=query.model_dump(exclude={"credentials", "max_results"}),
+ json=query.model_dump(exclude={"max_results"}),
)
- parsed_response = SearchOrganizationsResponse(**response.json())
+ data = response.json()
+ parsed_response = SearchOrganizationsResponse(**data)
if parsed_response.pagination.total_entries == 0:
return []
@@ -90,12 +93,13 @@ class ApolloClient:
and len(parsed_response.organizations) > 0
):
query.page += 1
- response = self.requests.get(
+ response = await self.requests.post(
f"{self.API_URL}/mixed_companies/search",
headers=self._get_headers(),
- params=query.model_dump(exclude={"credentials", "max_results"}),
+ json=query.model_dump(exclude={"max_results"}),
)
- parsed_response = SearchOrganizationsResponse(**response.json())
+ data = response.json()
+ parsed_response = SearchOrganizationsResponse(**data)
organizations.extend(
parsed_response.organizations[
: query.max_results - len(organizations)
diff --git a/autogpt_platform/backend/backend/blocks/apollo/models.py b/autogpt_platform/backend/backend/blocks/apollo/models.py
index 25fbb4d669..f97da43eaf 100644
--- a/autogpt_platform/backend/backend/blocks/apollo/models.py
+++ b/autogpt_platform/backend/backend/blocks/apollo/models.py
@@ -1,17 +1,31 @@
from enum import Enum
from typing import Any, Optional
-from pydantic import BaseModel, ConfigDict
+from pydantic import BaseModel as OriginalBaseModel
+from pydantic import ConfigDict
from backend.data.model import SchemaField
+class BaseModel(OriginalBaseModel):
+ def model_dump(self, *args, exclude: set[str] | None = None, **kwargs):
+ if exclude is None:
+ exclude = set("credentials")
+ else:
+ exclude.add("credentials")
+
+ kwargs.setdefault("exclude_none", True)
+ kwargs.setdefault("exclude_unset", True)
+ kwargs.setdefault("exclude_defaults", True)
+ return super().model_dump(*args, exclude=exclude, **kwargs)
+
+
class PrimaryPhone(BaseModel):
"""A primary phone in Apollo"""
- number: str
- source: str
- sanitized_number: str
+ number: str = ""
+ source: str = ""
+ sanitized_number: str = ""
class SenorityLevels(str, Enum):
@@ -42,88 +56,88 @@ class ContactEmailStatuses(str, Enum):
class RuleConfigStatus(BaseModel):
"""A rule config status in Apollo"""
- _id: str
- created_at: str
- rule_action_config_id: str
- rule_config_id: str
- status_cd: str
- updated_at: str
- id: str
- key: str
+ _id: str = ""
+ created_at: str = ""
+ rule_action_config_id: str = ""
+ rule_config_id: str = ""
+ status_cd: str = ""
+ updated_at: str = ""
+ id: str = ""
+ key: str = ""
class ContactCampaignStatus(BaseModel):
"""A contact campaign status in Apollo"""
- id: str
- emailer_campaign_id: str
- send_email_from_user_id: str
- inactive_reason: str
- status: str
- added_at: str
- added_by_user_id: str
- finished_at: str
- paused_at: str
- auto_unpause_at: str
- send_email_from_email_address: str
- send_email_from_email_account_id: str
- manually_set_unpause: str
- failure_reason: str
- current_step_id: str
- in_response_to_emailer_message_id: str
- cc_emails: str
- bcc_emails: str
- to_emails: str
+ id: str = ""
+ emailer_campaign_id: str = ""
+ send_email_from_user_id: str = ""
+ inactive_reason: str = ""
+ status: str = ""
+ added_at: str = ""
+ added_by_user_id: str = ""
+ finished_at: str = ""
+ paused_at: str = ""
+ auto_unpause_at: str = ""
+ send_email_from_email_address: str = ""
+ send_email_from_email_account_id: str = ""
+ manually_set_unpause: str = ""
+ failure_reason: str = ""
+ current_step_id: str = ""
+ in_response_to_emailer_message_id: str = ""
+ cc_emails: str = ""
+ bcc_emails: str = ""
+ to_emails: str = ""
class Account(BaseModel):
"""An account in Apollo"""
- id: str
- name: str
- website_url: str
- blog_url: str
- angellist_url: str
- linkedin_url: str
- twitter_url: str
- facebook_url: str
- primary_phone: PrimaryPhone
+ id: str = ""
+ name: str = ""
+ website_url: str = ""
+ blog_url: str = ""
+ angellist_url: str = ""
+ linkedin_url: str = ""
+ twitter_url: str = ""
+ facebook_url: str = ""
+ primary_phone: PrimaryPhone = PrimaryPhone()
languages: list[str]
- alexa_ranking: int
- phone: str
- linkedin_uid: str
- founded_year: int
- publicly_traded_symbol: str
- publicly_traded_exchange: str
- logo_url: str
- chrunchbase_url: str
- primary_domain: str
- domain: str
- team_id: str
- organization_id: str
- account_stage_id: str
- source: str
- original_source: str
- creator_id: str
- owner_id: str
- created_at: str
- phone_status: str
- hubspot_id: str
- salesforce_id: str
- crm_owner_id: str
- parent_account_id: str
- sanitized_phone: str
+ alexa_ranking: int = 0
+ phone: str = ""
+ linkedin_uid: str = ""
+ founded_year: int = 0
+ publicly_traded_symbol: str = ""
+ publicly_traded_exchange: str = ""
+ logo_url: str = ""
+ chrunchbase_url: str = ""
+ primary_domain: str = ""
+ domain: str = ""
+ team_id: str = ""
+ organization_id: str = ""
+ account_stage_id: str = ""
+ source: str = ""
+ original_source: str = ""
+ creator_id: str = ""
+ owner_id: str = ""
+ created_at: str = ""
+ phone_status: str = ""
+ hubspot_id: str = ""
+ salesforce_id: str = ""
+ crm_owner_id: str = ""
+ parent_account_id: str = ""
+ sanitized_phone: str = ""
# no listed type on the API docs
- account_playbook_statues: list[Any]
- account_rule_config_statuses: list[RuleConfigStatus]
- existence_level: str
- label_ids: list[str]
+ account_playbook_statues: list[Any] = []
+ account_rule_config_statuses: list[RuleConfigStatus] = []
+ existence_level: str = ""
+ label_ids: list[str] = []
typed_custom_fields: Any
custom_field_errors: Any
- modality: str
- source_display_name: str
- salesforce_record_id: str
- crm_record_url: str
+ modality: str = ""
+ source_display_name: str = ""
+ salesforce_record_id: str = ""
+ crm_record_url: str = ""
class ContactEmail(BaseModel):
@@ -205,7 +219,7 @@ class Pagination(BaseModel):
class DialerFlags(BaseModel):
"""A dialer flags in Apollo"""
- country_name: str
+ country_name: str = ""
country_enabled: bool
high_risk_calling_enabled: bool
potential_high_risk_number: bool
diff --git a/autogpt_platform/backend/backend/blocks/apollo/organization.py b/autogpt_platform/backend/backend/blocks/apollo/organization.py
index 37537a6461..e21b0ab5d9 100644
--- a/autogpt_platform/backend/backend/blocks/apollo/organization.py
+++ b/autogpt_platform/backend/backend/blocks/apollo/organization.py
@@ -201,19 +201,17 @@ To find IDs, identify the values for organization_id when you call this endpoint
)
@staticmethod
- def search_organizations(
+ async def search_organizations(
query: SearchOrganizationsRequest, credentials: ApolloCredentials
) -> list[Organization]:
client = ApolloClient(credentials)
- return client.search_organizations(query)
+ return await client.search_organizations(query)
- def run(
+ async def run(
self, input_data: Input, *, credentials: ApolloCredentials, **kwargs
) -> BlockOutput:
- query = SearchOrganizationsRequest(
- **input_data.model_dump(exclude={"credentials"})
- )
- organizations = self.search_organizations(query, credentials)
+ query = SearchOrganizationsRequest(**input_data.model_dump())
+ organizations = await self.search_organizations(query, credentials)
for organization in organizations:
yield "organization", organization
yield "organizations", organizations
diff --git a/autogpt_platform/backend/backend/blocks/apollo/people.py b/autogpt_platform/backend/backend/blocks/apollo/people.py
index 628bb5dc7c..c6d8620b7d 100644
--- a/autogpt_platform/backend/backend/blocks/apollo/people.py
+++ b/autogpt_platform/backend/backend/blocks/apollo/people.py
@@ -107,6 +107,7 @@ class SearchPeopleBlock(Block):
default_factory=list,
)
person: Contact = SchemaField(
+ title="Person",
description="Each found person, one at a time",
)
error: str = SchemaField(
@@ -373,13 +374,13 @@ class SearchPeopleBlock(Block):
)
@staticmethod
- def search_people(
+ async def search_people(
query: SearchPeopleRequest, credentials: ApolloCredentials
) -> list[Contact]:
client = ApolloClient(credentials)
- return client.search_people(query)
+ return await client.search_people(query)
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -387,8 +388,8 @@ class SearchPeopleBlock(Block):
**kwargs,
) -> BlockOutput:
- query = SearchPeopleRequest(**input_data.model_dump(exclude={"credentials"}))
- people = self.search_people(query, credentials)
+ query = SearchPeopleRequest(**input_data.model_dump())
+ people = await self.search_people(query, credentials)
for person in people:
yield "person", person
yield "people", people
diff --git a/autogpt_platform/backend/backend/blocks/basic.py b/autogpt_platform/backend/backend/blocks/basic.py
index 2c7edeb0ad..7e52e70f12 100644
--- a/autogpt_platform/backend/backend/blocks/basic.py
+++ b/autogpt_platform/backend/backend/blocks/basic.py
@@ -30,14 +30,14 @@ class FileStoreBlock(Block):
static_output=True,
)
- def run(
+ async def run(
self,
input_data: Input,
*,
graph_exec_id: str,
**kwargs,
) -> BlockOutput:
- file_path = store_media_file(
+ file_path = await store_media_file(
graph_exec_id=graph_exec_id,
file=input_data.file_in,
return_content=False,
@@ -84,7 +84,7 @@ class StoreValueBlock(Block):
static_output=True,
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
yield "output", input_data.data or input_data.input
@@ -110,7 +110,7 @@ class PrintToConsoleBlock(Block):
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
yield "output", input_data.text
yield "status", "printed"
@@ -151,7 +151,7 @@ class FindInDictionaryBlock(Block):
categories={BlockCategory.BASIC},
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
obj = input_data.input
key = input_data.key
@@ -241,7 +241,7 @@ class AddToDictionaryBlock(Block):
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
updated_dict = input_data.dictionary.copy()
if input_data.value is not None and input_data.key:
@@ -319,7 +319,7 @@ class AddToListBlock(Block):
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
entries_added = input_data.entries.copy()
if input_data.entry:
entries_added.append(input_data.entry)
@@ -366,7 +366,7 @@ class FindInListBlock(Block):
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
try:
yield "index", input_data.list.index(input_data.value)
yield "found", True
@@ -396,7 +396,7 @@ class NoteBlock(Block):
block_type=BlockType.NOTE,
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
yield "output", input_data.text
@@ -442,7 +442,7 @@ class CreateDictionaryBlock(Block):
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
try:
# The values are already validated by Pydantic schema
yield "dictionary", input_data.values
@@ -456,6 +456,11 @@ class CreateListBlock(Block):
description="A list of values to be combined into a new list.",
placeholder="e.g., ['Alice', 25, True]",
)
+ max_size: int | None = SchemaField(
+ default=None,
+ description="Maximum size of the list. If provided, the list will be yielded in chunks of this size.",
+ advanced=True,
+ )
class Output(BlockSchema):
list: List[Any] = SchemaField(
@@ -490,10 +495,11 @@ class CreateListBlock(Block):
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
try:
- # The values are already validated by Pydantic schema
- yield "list", input_data.values
+ max_size = input_data.max_size or len(input_data.values)
+ for i in range(0, len(input_data.values), max_size):
+ yield "list", input_data.values[i : i + max_size]
except Exception as e:
yield "error", f"Failed to create list: {str(e)}"
@@ -525,7 +531,7 @@ class UniversalTypeConverterBlock(Block):
output_schema=UniversalTypeConverterBlock.Output,
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
try:
converted_value = convert(
input_data.value,
diff --git a/autogpt_platform/backend/backend/blocks/block.py b/autogpt_platform/backend/backend/blocks/block.py
index 01e8af7238..e1745d3055 100644
--- a/autogpt_platform/backend/backend/blocks/block.py
+++ b/autogpt_platform/backend/backend/blocks/block.py
@@ -38,7 +38,7 @@ class BlockInstallationBlock(Block):
disabled=True,
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
code = input_data.code
if search := re.search(r"class (\w+)\(Block\):", code):
@@ -64,7 +64,7 @@ class BlockInstallationBlock(Block):
from backend.util.test import execute_block_test
- execute_block_test(block)
+ await execute_block_test(block)
yield "success", "Block installed successfully."
except Exception as e:
os.remove(file_path)
diff --git a/autogpt_platform/backend/backend/blocks/branching.py b/autogpt_platform/backend/backend/blocks/branching.py
index a3424d3374..17cfd6d5c1 100644
--- a/autogpt_platform/backend/backend/blocks/branching.py
+++ b/autogpt_platform/backend/backend/blocks/branching.py
@@ -70,7 +70,7 @@ class ConditionBlock(Block):
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
operator = input_data.operator
value1 = input_data.value1
@@ -163,7 +163,7 @@ class IfInputMatchesBlock(Block):
},
{
"input": 10,
- "value": None,
+ "value": "None",
"yes_value": "Yes",
"no_value": "No",
},
@@ -180,7 +180,7 @@ class IfInputMatchesBlock(Block):
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
if input_data.input == input_data.value or input_data.input is input_data.value:
yield "result", True
yield "yes_output", input_data.yes_value
diff --git a/autogpt_platform/backend/backend/blocks/code_executor.py b/autogpt_platform/backend/backend/blocks/code_executor.py
index 409c02bab0..e25231e90e 100644
--- a/autogpt_platform/backend/backend/blocks/code_executor.py
+++ b/autogpt_platform/backend/backend/blocks/code_executor.py
@@ -1,7 +1,7 @@
from enum import Enum
from typing import Literal
-from e2b_code_interpreter import Sandbox
+from e2b_code_interpreter import AsyncSandbox
from pydantic import SecretStr
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
@@ -123,7 +123,7 @@ class CodeExecutionBlock(Block):
},
)
- def execute_code(
+ async def execute_code(
self,
code: str,
language: ProgrammingLanguage,
@@ -135,21 +135,21 @@ class CodeExecutionBlock(Block):
try:
sandbox = None
if template_id:
- sandbox = Sandbox(
+ sandbox = await AsyncSandbox.create(
template=template_id, api_key=api_key, timeout=timeout
)
else:
- sandbox = Sandbox(api_key=api_key, timeout=timeout)
+ sandbox = await AsyncSandbox.create(api_key=api_key, timeout=timeout)
if not sandbox:
raise Exception("Sandbox not created")
# Running setup commands
for cmd in setup_commands:
- sandbox.commands.run(cmd)
+ await sandbox.commands.run(cmd)
# Executing the code
- execution = sandbox.run_code(
+ execution = await sandbox.run_code(
code,
language=language.value,
on_error=lambda e: sandbox.kill(), # Kill the sandbox if there is an error
@@ -167,11 +167,11 @@ class CodeExecutionBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
try:
- response, stdout_logs, stderr_logs = self.execute_code(
+ response, stdout_logs, stderr_logs = await self.execute_code(
input_data.code,
input_data.language,
input_data.setup_commands,
@@ -278,11 +278,11 @@ class InstantiationBlock(Block):
},
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
try:
- sandbox_id, response, stdout_logs, stderr_logs = self.execute_code(
+ sandbox_id, response, stdout_logs, stderr_logs = await self.execute_code(
input_data.setup_code,
input_data.language,
input_data.setup_commands,
@@ -303,7 +303,7 @@ class InstantiationBlock(Block):
except Exception as e:
yield "error", str(e)
- def execute_code(
+ async def execute_code(
self,
code: str,
language: ProgrammingLanguage,
@@ -315,21 +315,21 @@ class InstantiationBlock(Block):
try:
sandbox = None
if template_id:
- sandbox = Sandbox(
+ sandbox = await AsyncSandbox.create(
template=template_id, api_key=api_key, timeout=timeout
)
else:
- sandbox = Sandbox(api_key=api_key, timeout=timeout)
+ sandbox = await AsyncSandbox.create(api_key=api_key, timeout=timeout)
if not sandbox:
raise Exception("Sandbox not created")
# Running setup commands
for cmd in setup_commands:
- sandbox.commands.run(cmd)
+ await sandbox.commands.run(cmd)
# Executing the code
- execution = sandbox.run_code(
+ execution = await sandbox.run_code(
code,
language=language.value,
on_error=lambda e: sandbox.kill(), # Kill the sandbox if there is an error
@@ -409,7 +409,7 @@ class StepExecutionBlock(Block):
},
)
- def execute_step_code(
+ async def execute_step_code(
self,
sandbox_id: str,
code: str,
@@ -417,12 +417,12 @@ class StepExecutionBlock(Block):
api_key: str,
):
try:
- sandbox = Sandbox.connect(sandbox_id=sandbox_id, api_key=api_key)
+ sandbox = await AsyncSandbox.connect(sandbox_id=sandbox_id, api_key=api_key)
if not sandbox:
raise Exception("Sandbox not found")
# Executing the code
- execution = sandbox.run_code(code, language=language.value)
+ execution = await sandbox.run_code(code, language=language.value)
if execution.error:
raise Exception(execution.error)
@@ -436,11 +436,11 @@ class StepExecutionBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
try:
- response, stdout_logs, stderr_logs = self.execute_step_code(
+ response, stdout_logs, stderr_logs = await self.execute_step_code(
input_data.sandbox_id,
input_data.step_code,
input_data.language,
diff --git a/autogpt_platform/backend/backend/blocks/code_extraction_block.py b/autogpt_platform/backend/backend/blocks/code_extraction_block.py
index ab1e35aa5d..33bf225bfd 100644
--- a/autogpt_platform/backend/backend/blocks/code_extraction_block.py
+++ b/autogpt_platform/backend/backend/blocks/code_extraction_block.py
@@ -49,7 +49,7 @@ class CodeExtractionBlock(Block):
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
# List of supported programming languages with mapped aliases
language_aliases = {
"html": ["html", "htm"],
diff --git a/autogpt_platform/backend/backend/blocks/compass/triggers.py b/autogpt_platform/backend/backend/blocks/compass/triggers.py
index 662e39ecea..6eac52ce53 100644
--- a/autogpt_platform/backend/backend/blocks/compass/triggers.py
+++ b/autogpt_platform/backend/backend/blocks/compass/triggers.py
@@ -56,5 +56,5 @@ class CompassAITriggerBlock(Block):
# ],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
yield "transcription", input_data.payload.transcription
diff --git a/autogpt_platform/backend/backend/blocks/count_words_and_char_block.py b/autogpt_platform/backend/backend/blocks/count_words_and_char_block.py
index 13f9e39779..ddbcf07876 100644
--- a/autogpt_platform/backend/backend/blocks/count_words_and_char_block.py
+++ b/autogpt_platform/backend/backend/blocks/count_words_and_char_block.py
@@ -30,7 +30,7 @@ class WordCharacterCountBlock(Block):
test_output=[("word_count", 4), ("character_count", 19)],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
try:
text = input_data.text
word_count = len(text.split())
diff --git a/autogpt_platform/backend/backend/blocks/csv.py b/autogpt_platform/backend/backend/blocks/csv.py
index 3cc3575b31..f69eeff4a9 100644
--- a/autogpt_platform/backend/backend/blocks/csv.py
+++ b/autogpt_platform/backend/backend/blocks/csv.py
@@ -69,7 +69,7 @@ class ReadCsvBlock(Block):
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
import csv
from io import StringIO
diff --git a/autogpt_platform/backend/backend/blocks/decoder_block.py b/autogpt_platform/backend/backend/blocks/decoder_block.py
index 033cdfb0b3..754d79b068 100644
--- a/autogpt_platform/backend/backend/blocks/decoder_block.py
+++ b/autogpt_platform/backend/backend/blocks/decoder_block.py
@@ -34,6 +34,6 @@ This is a "quoted" string.""",
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
decoded_text = codecs.decode(input_data.text, "unicode_escape")
yield "decoded_text", decoded_text
diff --git a/autogpt_platform/backend/backend/blocks/discord.py b/autogpt_platform/backend/backend/blocks/discord.py
index 08ba8af074..91aba5f414 100644
--- a/autogpt_platform/backend/backend/blocks/discord.py
+++ b/autogpt_platform/backend/backend/blocks/discord.py
@@ -1,4 +1,3 @@
-import asyncio
from typing import Literal
import aiohttp
@@ -74,7 +73,11 @@ class ReadDiscordMessagesBlock(Block):
("username", "test_user"),
],
test_mock={
- "run_bot": lambda token: asyncio.Future() # Create a Future object for mocking
+ "run_bot": lambda token: {
+ "output_data": "Hello!\n\nFile from user: example.txt\nContent: This is the content of the file.",
+ "channel_name": "general",
+ "username": "test_user",
+ }
},
)
@@ -106,37 +109,24 @@ class ReadDiscordMessagesBlock(Block):
if attachment.filename.endswith((".txt", ".py")):
async with aiohttp.ClientSession() as session:
async with session.get(attachment.url) as response:
- file_content = await response.text()
+ file_content = response.text()
self.output_data += f"\n\nFile from user: {attachment.filename}\nContent: {file_content}"
await client.close()
await client.start(token.get_secret_value())
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
- while True:
- for output_name, output_value in self.__run(input_data, credentials):
- yield output_name, output_value
- break
+ async for output_name, output_value in self.__run(input_data, credentials):
+ yield output_name, output_value
- def __run(self, input_data: Input, credentials: APIKeyCredentials) -> BlockOutput:
+ async def __run(
+ self, input_data: Input, credentials: APIKeyCredentials
+ ) -> BlockOutput:
try:
- loop = asyncio.get_event_loop()
- future = self.run_bot(credentials.api_key)
-
- # If it's a Future (mock), set the result
- if isinstance(future, asyncio.Future):
- future.set_result(
- {
- "output_data": "Hello!\n\nFile from user: example.txt\nContent: This is the content of the file.",
- "channel_name": "general",
- "username": "test_user",
- }
- )
-
- result = loop.run_until_complete(future)
+ result = await self.run_bot(credentials.api_key)
# For testing purposes, use the mocked result
if isinstance(result, dict):
@@ -190,7 +180,7 @@ class SendDiscordMessageBlock(Block):
},
test_output=[("status", "Message sent")],
test_mock={
- "send_message": lambda token, channel_name, message_content: asyncio.Future()
+ "send_message": lambda token, channel_name, message_content: "Message sent"
},
test_credentials=TEST_CREDENTIALS,
)
@@ -222,23 +212,16 @@ class SendDiscordMessageBlock(Block):
"""Splits a message into chunks not exceeding the Discord limit."""
return [message[i : i + limit] for i in range(0, len(message), limit)]
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
try:
- loop = asyncio.get_event_loop()
- future = self.send_message(
+ result = await self.send_message(
credentials.api_key.get_secret_value(),
input_data.channel_name,
input_data.message_content,
)
- # If it's a Future (mock), set the result
- if isinstance(future, asyncio.Future):
- future.set_result("Message sent")
-
- result = loop.run_until_complete(future)
-
# For testing purposes, use the mocked result
if isinstance(result, str):
self.output_data = result
diff --git a/autogpt_platform/backend/backend/blocks/email_block.py b/autogpt_platform/backend/backend/blocks/email_block.py
index 4159886cee..3738bf0de8 100644
--- a/autogpt_platform/backend/backend/blocks/email_block.py
+++ b/autogpt_platform/backend/backend/blocks/email_block.py
@@ -121,7 +121,7 @@ class SendEmailBlock(Block):
return "Email sent successfully"
- def run(
+ async def run(
self, input_data: Input, *, credentials: SMTPCredentials, **kwargs
) -> BlockOutput:
yield "status", self.send_email(
diff --git a/autogpt_platform/backend/backend/blocks/exa/contents.py b/autogpt_platform/backend/backend/blocks/exa/contents.py
index 7210af433d..920a5ac82f 100644
--- a/autogpt_platform/backend/backend/blocks/exa/contents.py
+++ b/autogpt_platform/backend/backend/blocks/exa/contents.py
@@ -9,7 +9,7 @@ from backend.blocks.exa._auth import (
)
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
from backend.data.model import SchemaField
-from backend.util.request import requests
+from backend.util.request import Requests
class ContentRetrievalSettings(BaseModel):
@@ -62,7 +62,7 @@ class ExaContentsBlock(Block):
output_schema=ExaContentsBlock.Output,
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: ExaCredentials, **kwargs
) -> BlockOutput:
url = "https://api.exa.ai/contents"
@@ -79,8 +79,7 @@ class ExaContentsBlock(Block):
}
try:
- response = requests.post(url, headers=headers, json=payload)
- response.raise_for_status()
+ response = await Requests().post(url, headers=headers, json=payload)
data = response.json()
yield "results", data.get("results", [])
except Exception as e:
diff --git a/autogpt_platform/backend/backend/blocks/exa/search.py b/autogpt_platform/backend/backend/blocks/exa/search.py
index 5915455a56..1f4d0005ce 100644
--- a/autogpt_platform/backend/backend/blocks/exa/search.py
+++ b/autogpt_platform/backend/backend/blocks/exa/search.py
@@ -9,7 +9,7 @@ from backend.blocks.exa._auth import (
from backend.blocks.exa.helpers import ContentSettings
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
from backend.data.model import SchemaField
-from backend.util.request import requests
+from backend.util.request import Requests
class ExaSearchBlock(Block):
@@ -91,7 +91,7 @@ class ExaSearchBlock(Block):
output_schema=ExaSearchBlock.Output,
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: ExaCredentials, **kwargs
) -> BlockOutput:
url = "https://api.exa.ai/search"
@@ -136,8 +136,7 @@ class ExaSearchBlock(Block):
payload[api_field] = value
try:
- response = requests.post(url, headers=headers, json=payload)
- response.raise_for_status()
+ response = await Requests().post(url, headers=headers, json=payload)
data = response.json()
# Extract just the results array from the response
yield "results", data.get("results", [])
diff --git a/autogpt_platform/backend/backend/blocks/exa/similar.py b/autogpt_platform/backend/backend/blocks/exa/similar.py
index 036d26a481..36dc23c5c5 100644
--- a/autogpt_platform/backend/backend/blocks/exa/similar.py
+++ b/autogpt_platform/backend/backend/blocks/exa/similar.py
@@ -8,7 +8,7 @@ from backend.blocks.exa._auth import (
)
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
from backend.data.model import SchemaField
-from backend.util.request import requests
+from backend.util.request import Requests
from .helpers import ContentSettings
@@ -78,7 +78,7 @@ class ExaFindSimilarBlock(Block):
output_schema=ExaFindSimilarBlock.Output,
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: ExaCredentials, **kwargs
) -> BlockOutput:
url = "https://api.exa.ai/findSimilar"
@@ -120,8 +120,7 @@ class ExaFindSimilarBlock(Block):
payload[api_field] = value.strftime("%Y-%m-%dT%H:%M:%S.000Z")
try:
- response = requests.post(url, headers=headers, json=payload)
- response.raise_for_status()
+ response = await Requests().post(url, headers=headers, json=payload)
data = response.json()
yield "results", data.get("results", [])
except Exception as e:
diff --git a/autogpt_platform/backend/backend/blocks/fal/ai_video_generator.py b/autogpt_platform/backend/backend/blocks/fal/ai_video_generator.py
index fc2152e0ee..2e795f0d78 100644
--- a/autogpt_platform/backend/backend/blocks/fal/ai_video_generator.py
+++ b/autogpt_platform/backend/backend/blocks/fal/ai_video_generator.py
@@ -1,10 +1,8 @@
+import asyncio
import logging
-import time
from enum import Enum
from typing import Any
-import httpx
-
from backend.blocks.fal._auth import (
TEST_CREDENTIALS,
TEST_CREDENTIALS_INPUT,
@@ -14,6 +12,7 @@ from backend.blocks.fal._auth import (
)
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
from backend.data.model import SchemaField
+from backend.util.request import ClientResponseError, Requests
logger = logging.getLogger(__name__)
@@ -66,35 +65,37 @@ class AIVideoGeneratorBlock(Block):
)
def _get_headers(self, api_key: str) -> dict[str, str]:
- """Get headers for FAL API requests."""
+ """Get headers for FAL API Requests."""
return {
"Authorization": f"Key {api_key}",
"Content-Type": "application/json",
}
- def _submit_request(
+ async def _submit_request(
self, url: str, headers: dict[str, str], data: dict[str, Any]
) -> dict[str, Any]:
"""Submit a request to the FAL API."""
try:
- response = httpx.post(url, headers=headers, json=data)
- response.raise_for_status()
+ response = await Requests().post(url, headers=headers, json=data)
return response.json()
- except httpx.HTTPError as e:
+ except ClientResponseError as e:
logger.error(f"FAL API request failed: {str(e)}")
raise RuntimeError(f"Failed to submit request: {str(e)}")
- def _poll_status(self, status_url: str, headers: dict[str, str]) -> dict[str, Any]:
+ async def _poll_status(
+ self, status_url: str, headers: dict[str, str]
+ ) -> dict[str, Any]:
"""Poll the status endpoint until completion or failure."""
try:
- response = httpx.get(status_url, headers=headers)
- response.raise_for_status()
+ response = await Requests().get(status_url, headers=headers)
return response.json()
- except httpx.HTTPError as e:
+ except ClientResponseError as e:
logger.error(f"Failed to get status: {str(e)}")
raise RuntimeError(f"Failed to get status: {str(e)}")
- def generate_video(self, input_data: Input, credentials: FalCredentials) -> str:
+ async def generate_video(
+ self, input_data: Input, credentials: FalCredentials
+ ) -> str:
"""Generate video using the specified FAL model."""
base_url = "https://queue.fal.run"
api_key = credentials.api_key.get_secret_value()
@@ -110,8 +111,9 @@ class AIVideoGeneratorBlock(Block):
try:
# Submit request to queue
- submit_response = httpx.post(submit_url, headers=headers, json=submit_data)
- submit_response.raise_for_status()
+ submit_response = await Requests().post(
+ submit_url, headers=headers, json=submit_data
+ )
request_data = submit_response.json()
# Get request_id and urls from initial response
@@ -122,14 +124,23 @@ class AIVideoGeneratorBlock(Block):
if not all([request_id, status_url, result_url]):
raise ValueError("Missing required data in submission response")
+ # Ensure status_url is a string
+ if not isinstance(status_url, str):
+ raise ValueError("Invalid status URL format")
+
+ # Ensure result_url is a string
+ if not isinstance(result_url, str):
+ raise ValueError("Invalid result URL format")
+
# Poll for status with exponential backoff
max_attempts = 30
attempt = 0
base_wait_time = 5
while attempt < max_attempts:
- status_response = httpx.get(f"{status_url}?logs=1", headers=headers)
- status_response.raise_for_status()
+ status_response = await Requests().get(
+ f"{status_url}?logs=1", headers=headers
+ )
status_data = status_response.json()
# Process new logs only
@@ -152,8 +163,7 @@ class AIVideoGeneratorBlock(Block):
status = status_data.get("status")
if status == "COMPLETED":
# Get the final result
- result_response = httpx.get(result_url, headers=headers)
- result_response.raise_for_status()
+ result_response = await Requests().get(result_url, headers=headers)
result_data = result_response.json()
if "video" not in result_data or not isinstance(
@@ -162,8 +172,8 @@ class AIVideoGeneratorBlock(Block):
raise ValueError("Invalid response format - missing video data")
video_url = result_data["video"].get("url")
- if not video_url:
- raise ValueError("No video URL in response")
+ if not video_url or not isinstance(video_url, str):
+ raise ValueError("No valid video URL in response")
return video_url
@@ -183,19 +193,19 @@ class AIVideoGeneratorBlock(Block):
logger.info(f"[FAL Generation] Status: Unknown status: {status}")
wait_time = min(base_wait_time * (2**attempt), 60) # Cap at 60 seconds
- time.sleep(wait_time)
+ await asyncio.sleep(wait_time)
attempt += 1
raise RuntimeError("Maximum polling attempts reached")
- except httpx.HTTPError as e:
+ except ClientResponseError as e:
raise RuntimeError(f"API request failed: {str(e)}")
- def run(
+ async def run(
self, input_data: Input, *, credentials: FalCredentials, **kwargs
) -> BlockOutput:
try:
- video_url = self.generate_video(input_data, credentials)
+ video_url = await self.generate_video(input_data, credentials)
yield "video_url", video_url
except Exception as e:
error_message = str(e)
diff --git a/autogpt_platform/backend/backend/blocks/flux_kontext.py b/autogpt_platform/backend/backend/blocks/flux_kontext.py
index 1cff9dbba2..f391b41939 100644
--- a/autogpt_platform/backend/backend/blocks/flux_kontext.py
+++ b/autogpt_platform/backend/backend/blocks/flux_kontext.py
@@ -123,14 +123,14 @@ class AIImageEditorBlock(Block):
test_credentials=TEST_CREDENTIALS,
)
- def run(
+ async def run(
self,
input_data: Input,
*,
credentials: APIKeyCredentials,
**kwargs,
) -> BlockOutput:
- result = self.run_model(
+ result = await self.run_model(
api_key=credentials.api_key,
model_name=input_data.model.api_name,
prompt=input_data.prompt,
@@ -140,7 +140,7 @@ class AIImageEditorBlock(Block):
)
yield "output_image", result
- def run_model(
+ async def run_model(
self,
api_key: SecretStr,
model_name: str,
@@ -157,7 +157,7 @@ class AIImageEditorBlock(Block):
**({"seed": seed} if seed is not None else {}),
}
- output: FileOutput | list[FileOutput] = client.run( # type: ignore
+ output: FileOutput | list[FileOutput] = await client.async_run( # type: ignore
model_name,
input=input_params,
wait=False,
diff --git a/autogpt_platform/backend/backend/blocks/generic_webhook/triggers.py b/autogpt_platform/backend/backend/blocks/generic_webhook/triggers.py
index 66c106b0c5..66660ac57d 100644
--- a/autogpt_platform/backend/backend/blocks/generic_webhook/triggers.py
+++ b/autogpt_platform/backend/backend/blocks/generic_webhook/triggers.py
@@ -46,6 +46,6 @@ class GenericWebhookTriggerBlock(Block):
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
yield "constants", input_data.constants
yield "payload", input_data.payload
diff --git a/autogpt_platform/backend/backend/blocks/github/checks.py b/autogpt_platform/backend/backend/blocks/github/checks.py
index 070b5179e8..9b9aecdf07 100644
--- a/autogpt_platform/backend/backend/blocks/github/checks.py
+++ b/autogpt_platform/backend/backend/blocks/github/checks.py
@@ -129,7 +129,7 @@ class GithubCreateCheckRunBlock(Block):
)
@staticmethod
- def create_check_run(
+ async def create_check_run(
credentials: GithubCredentials,
repo_url: str,
name: str,
@@ -172,7 +172,7 @@ class GithubCreateCheckRunBlock(Block):
data.output = output_data
check_runs_url = f"{repo_url}/check-runs"
- response = api.post(
+ response = await api.post(
check_runs_url, data=data.model_dump_json(exclude_none=True)
)
result = response.json()
@@ -183,7 +183,7 @@ class GithubCreateCheckRunBlock(Block):
"status": result["status"],
}
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -191,7 +191,7 @@ class GithubCreateCheckRunBlock(Block):
**kwargs,
) -> BlockOutput:
try:
- result = self.create_check_run(
+ result = await self.create_check_run(
credentials=credentials,
repo_url=input_data.repo_url,
name=input_data.name,
@@ -292,7 +292,7 @@ class GithubUpdateCheckRunBlock(Block):
)
@staticmethod
- def update_check_run(
+ async def update_check_run(
credentials: GithubCredentials,
repo_url: str,
check_run_id: int,
@@ -325,7 +325,7 @@ class GithubUpdateCheckRunBlock(Block):
data.output = output_data
check_run_url = f"{repo_url}/check-runs/{check_run_id}"
- response = api.patch(
+ response = await api.patch(
check_run_url, data=data.model_dump_json(exclude_none=True)
)
result = response.json()
@@ -337,7 +337,7 @@ class GithubUpdateCheckRunBlock(Block):
"conclusion": result.get("conclusion"),
}
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -345,7 +345,7 @@ class GithubUpdateCheckRunBlock(Block):
**kwargs,
) -> BlockOutput:
try:
- result = self.update_check_run(
+ result = await self.update_check_run(
credentials=credentials,
repo_url=input_data.repo_url,
check_run_id=input_data.check_run_id,
diff --git a/autogpt_platform/backend/backend/blocks/github/issues.py b/autogpt_platform/backend/backend/blocks/github/issues.py
index e62821a36e..42c027c493 100644
--- a/autogpt_platform/backend/backend/blocks/github/issues.py
+++ b/autogpt_platform/backend/backend/blocks/github/issues.py
@@ -80,7 +80,7 @@ class GithubCommentBlock(Block):
)
@staticmethod
- def post_comment(
+ async def post_comment(
credentials: GithubCredentials, issue_url: str, body_text: str
) -> tuple[int, str]:
api = get_api(credentials)
@@ -88,18 +88,18 @@ class GithubCommentBlock(Block):
if "pull" in issue_url:
issue_url = issue_url.replace("pull", "issues")
comments_url = issue_url + "/comments"
- response = api.post(comments_url, json=data)
+ response = await api.post(comments_url, json=data)
comment = response.json()
return comment["id"], comment["html_url"]
- def run(
+ async def run(
self,
input_data: Input,
*,
credentials: GithubCredentials,
**kwargs,
) -> BlockOutput:
- id, url = self.post_comment(
+ id, url = await self.post_comment(
credentials,
input_data.issue_url,
input_data.comment,
@@ -171,7 +171,7 @@ class GithubUpdateCommentBlock(Block):
)
@staticmethod
- def update_comment(
+ async def update_comment(
credentials: GithubCredentials, comment_url: str, body_text: str
) -> tuple[int, str]:
api = get_api(credentials, convert_urls=False)
@@ -179,11 +179,11 @@ class GithubUpdateCommentBlock(Block):
url = convert_comment_url_to_api_endpoint(comment_url)
logger.info(url)
- response = api.patch(url, json=data)
+ response = await api.patch(url, json=data)
comment = response.json()
return comment["id"], comment["html_url"]
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -209,7 +209,7 @@ class GithubUpdateCommentBlock(Block):
raise ValueError(
"Must provide either comment_url or comment_id and issue_url"
)
- id, url = self.update_comment(
+ id, url = await self.update_comment(
credentials,
input_data.comment_url,
input_data.comment,
@@ -288,7 +288,7 @@ class GithubListCommentsBlock(Block):
)
@staticmethod
- def list_comments(
+ async def list_comments(
credentials: GithubCredentials, issue_url: str
) -> list[Output.CommentItem]:
parsed_url = urlparse(issue_url)
@@ -305,7 +305,7 @@ class GithubListCommentsBlock(Block):
# Set convert_urls=False since we're already providing an API URL
api = get_api(credentials, convert_urls=False)
- response = api.get(api_url)
+ response = await api.get(api_url)
comments = response.json()
parsed_comments: list[GithubListCommentsBlock.Output.CommentItem] = [
{
@@ -318,18 +318,19 @@ class GithubListCommentsBlock(Block):
]
return parsed_comments
- def run(
+ async def run(
self,
input_data: Input,
*,
credentials: GithubCredentials,
**kwargs,
) -> BlockOutput:
- comments = self.list_comments(
+ comments = await self.list_comments(
credentials,
input_data.issue_url,
)
- yield from (("comment", comment) for comment in comments)
+ for comment in comments:
+ yield "comment", comment
yield "comments", comments
@@ -381,24 +382,24 @@ class GithubMakeIssueBlock(Block):
)
@staticmethod
- def create_issue(
+ async def create_issue(
credentials: GithubCredentials, repo_url: str, title: str, body: str
) -> tuple[int, str]:
api = get_api(credentials)
data = {"title": title, "body": body}
issues_url = repo_url + "/issues"
- response = api.post(issues_url, json=data)
+ response = await api.post(issues_url, json=data)
issue = response.json()
return issue["number"], issue["html_url"]
- def run(
+ async def run(
self,
input_data: Input,
*,
credentials: GithubCredentials,
**kwargs,
) -> BlockOutput:
- number, url = self.create_issue(
+ number, url = await self.create_issue(
credentials,
input_data.repo_url,
input_data.title,
@@ -451,25 +452,25 @@ class GithubReadIssueBlock(Block):
)
@staticmethod
- def read_issue(
+ async def read_issue(
credentials: GithubCredentials, issue_url: str
) -> tuple[str, str, str]:
api = get_api(credentials)
- response = api.get(issue_url)
+ response = await api.get(issue_url)
data = response.json()
title = data.get("title", "No title found")
body = data.get("body", "No body content found")
user = data.get("user", {}).get("login", "No user found")
return title, body, user
- def run(
+ async def run(
self,
input_data: Input,
*,
credentials: GithubCredentials,
**kwargs,
) -> BlockOutput:
- title, body, user = self.read_issue(
+ title, body, user = await self.read_issue(
credentials,
input_data.issue_url,
)
@@ -531,30 +532,30 @@ class GithubListIssuesBlock(Block):
)
@staticmethod
- def list_issues(
+ async def list_issues(
credentials: GithubCredentials, repo_url: str
) -> list[Output.IssueItem]:
api = get_api(credentials)
issues_url = repo_url + "/issues"
- response = api.get(issues_url)
+ response = await api.get(issues_url)
data = response.json()
issues: list[GithubListIssuesBlock.Output.IssueItem] = [
{"title": issue["title"], "url": issue["html_url"]} for issue in data
]
return issues
- def run(
+ async def run(
self,
input_data: Input,
*,
credentials: GithubCredentials,
**kwargs,
) -> BlockOutput:
- issues = self.list_issues(
+ for issue in await self.list_issues(
credentials,
input_data.repo_url,
- )
- yield from (("issue", issue) for issue in issues)
+ ):
+ yield "issue", issue
class GithubAddLabelBlock(Block):
@@ -593,21 +594,23 @@ class GithubAddLabelBlock(Block):
)
@staticmethod
- def add_label(credentials: GithubCredentials, issue_url: str, label: str) -> str:
+ async def add_label(
+ credentials: GithubCredentials, issue_url: str, label: str
+ ) -> str:
api = get_api(credentials)
data = {"labels": [label]}
labels_url = issue_url + "/labels"
- api.post(labels_url, json=data)
+ await api.post(labels_url, json=data)
return "Label added successfully"
- def run(
+ async def run(
self,
input_data: Input,
*,
credentials: GithubCredentials,
**kwargs,
) -> BlockOutput:
- status = self.add_label(
+ status = await self.add_label(
credentials,
input_data.issue_url,
input_data.label,
@@ -653,20 +656,22 @@ class GithubRemoveLabelBlock(Block):
)
@staticmethod
- def remove_label(credentials: GithubCredentials, issue_url: str, label: str) -> str:
+ async def remove_label(
+ credentials: GithubCredentials, issue_url: str, label: str
+ ) -> str:
api = get_api(credentials)
label_url = issue_url + f"/labels/{label}"
- api.delete(label_url)
+ await api.delete(label_url)
return "Label removed successfully"
- def run(
+ async def run(
self,
input_data: Input,
*,
credentials: GithubCredentials,
**kwargs,
) -> BlockOutput:
- status = self.remove_label(
+ status = await self.remove_label(
credentials,
input_data.issue_url,
input_data.label,
@@ -714,7 +719,7 @@ class GithubAssignIssueBlock(Block):
)
@staticmethod
- def assign_issue(
+ async def assign_issue(
credentials: GithubCredentials,
issue_url: str,
assignee: str,
@@ -722,17 +727,17 @@ class GithubAssignIssueBlock(Block):
api = get_api(credentials)
assignees_url = issue_url + "/assignees"
data = {"assignees": [assignee]}
- api.post(assignees_url, json=data)
+ await api.post(assignees_url, json=data)
return "Issue assigned successfully"
- def run(
+ async def run(
self,
input_data: Input,
*,
credentials: GithubCredentials,
**kwargs,
) -> BlockOutput:
- status = self.assign_issue(
+ status = await self.assign_issue(
credentials,
input_data.issue_url,
input_data.assignee,
@@ -780,7 +785,7 @@ class GithubUnassignIssueBlock(Block):
)
@staticmethod
- def unassign_issue(
+ async def unassign_issue(
credentials: GithubCredentials,
issue_url: str,
assignee: str,
@@ -788,17 +793,17 @@ class GithubUnassignIssueBlock(Block):
api = get_api(credentials)
assignees_url = issue_url + "/assignees"
data = {"assignees": [assignee]}
- api.delete(assignees_url, json=data)
+ await api.delete(assignees_url, json=data)
return "Issue unassigned successfully"
- def run(
+ async def run(
self,
input_data: Input,
*,
credentials: GithubCredentials,
**kwargs,
) -> BlockOutput:
- status = self.unassign_issue(
+ status = await self.unassign_issue(
credentials,
input_data.issue_url,
input_data.assignee,
diff --git a/autogpt_platform/backend/backend/blocks/github/pull_requests.py b/autogpt_platform/backend/backend/blocks/github/pull_requests.py
index b29db0ff34..dbb940217c 100644
--- a/autogpt_platform/backend/backend/blocks/github/pull_requests.py
+++ b/autogpt_platform/backend/backend/blocks/github/pull_requests.py
@@ -65,28 +65,31 @@ class GithubListPullRequestsBlock(Block):
)
@staticmethod
- def list_prs(credentials: GithubCredentials, repo_url: str) -> list[Output.PRItem]:
+ async def list_prs(
+ credentials: GithubCredentials, repo_url: str
+ ) -> list[Output.PRItem]:
api = get_api(credentials)
pulls_url = repo_url + "/pulls"
- response = api.get(pulls_url)
+ response = await api.get(pulls_url)
data = response.json()
pull_requests: list[GithubListPullRequestsBlock.Output.PRItem] = [
{"title": pr["title"], "url": pr["html_url"]} for pr in data
]
return pull_requests
- def run(
+ async def run(
self,
input_data: Input,
*,
credentials: GithubCredentials,
**kwargs,
) -> BlockOutput:
- pull_requests = self.list_prs(
+ pull_requests = await self.list_prs(
credentials,
input_data.repo_url,
)
- yield from (("pull_request", pr) for pr in pull_requests)
+ for pr in pull_requests:
+ yield "pull_request", pr
class GithubMakePullRequestBlock(Block):
@@ -153,7 +156,7 @@ class GithubMakePullRequestBlock(Block):
)
@staticmethod
- def create_pr(
+ async def create_pr(
credentials: GithubCredentials,
repo_url: str,
title: str,
@@ -164,11 +167,11 @@ class GithubMakePullRequestBlock(Block):
api = get_api(credentials)
pulls_url = repo_url + "/pulls"
data = {"title": title, "body": body, "head": head, "base": base}
- response = api.post(pulls_url, json=data)
+ response = await api.post(pulls_url, json=data)
pr_data = response.json()
return pr_data["number"], pr_data["html_url"]
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -176,7 +179,7 @@ class GithubMakePullRequestBlock(Block):
**kwargs,
) -> BlockOutput:
try:
- number, url = self.create_pr(
+ number, url = await self.create_pr(
credentials,
input_data.repo_url,
input_data.title,
@@ -242,39 +245,39 @@ class GithubReadPullRequestBlock(Block):
)
@staticmethod
- def read_pr(credentials: GithubCredentials, pr_url: str) -> tuple[str, str, str]:
+ async def read_pr(
+ credentials: GithubCredentials, pr_url: str
+ ) -> tuple[str, str, str]:
api = get_api(credentials)
- # Adjust the URL to access the issue endpoint for PR metadata
issue_url = pr_url.replace("/pull/", "/issues/")
- response = api.get(issue_url)
+ response = await api.get(issue_url)
data = response.json()
title = data.get("title", "No title found")
body = data.get("body", "No body content found")
- author = data.get("user", {}).get("login", "No user found")
+ author = data.get("user", {}).get("login", "Unknown author")
return title, body, author
@staticmethod
- def read_pr_changes(credentials: GithubCredentials, pr_url: str) -> str:
+ async def read_pr_changes(credentials: GithubCredentials, pr_url: str) -> str:
api = get_api(credentials)
files_url = prepare_pr_api_url(pr_url=pr_url, path="files")
- response = api.get(files_url)
+ response = await api.get(files_url)
files = response.json()
changes = []
for file in files:
- filename = file.get("filename")
- patch = file.get("patch")
- if filename and patch:
- changes.append(f"File: {filename}\n{patch}")
- return "\n\n".join(changes)
+ filename = file.get("filename", "")
+ status = file.get("status", "")
+ changes.append(f"{filename}: {status}")
+ return "\n".join(changes)
- def run(
+ async def run(
self,
input_data: Input,
*,
credentials: GithubCredentials,
**kwargs,
) -> BlockOutput:
- title, body, author = self.read_pr(
+ title, body, author = await self.read_pr(
credentials,
input_data.pr_url,
)
@@ -283,7 +286,7 @@ class GithubReadPullRequestBlock(Block):
yield "author", author
if input_data.include_pr_changes:
- changes = self.read_pr_changes(
+ changes = await self.read_pr_changes(
credentials,
input_data.pr_url,
)
@@ -330,16 +333,16 @@ class GithubAssignPRReviewerBlock(Block):
)
@staticmethod
- def assign_reviewer(
+ async def assign_reviewer(
credentials: GithubCredentials, pr_url: str, reviewer: str
) -> str:
api = get_api(credentials)
reviewers_url = prepare_pr_api_url(pr_url=pr_url, path="requested_reviewers")
data = {"reviewers": [reviewer]}
- api.post(reviewers_url, json=data)
+ await api.post(reviewers_url, json=data)
return "Reviewer assigned successfully"
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -347,7 +350,7 @@ class GithubAssignPRReviewerBlock(Block):
**kwargs,
) -> BlockOutput:
try:
- status = self.assign_reviewer(
+ status = await self.assign_reviewer(
credentials,
input_data.pr_url,
input_data.reviewer,
@@ -397,16 +400,16 @@ class GithubUnassignPRReviewerBlock(Block):
)
@staticmethod
- def unassign_reviewer(
+ async def unassign_reviewer(
credentials: GithubCredentials, pr_url: str, reviewer: str
) -> str:
api = get_api(credentials)
reviewers_url = prepare_pr_api_url(pr_url=pr_url, path="requested_reviewers")
data = {"reviewers": [reviewer]}
- api.delete(reviewers_url, json=data)
+ await api.delete(reviewers_url, json=data)
return "Reviewer unassigned successfully"
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -414,7 +417,7 @@ class GithubUnassignPRReviewerBlock(Block):
**kwargs,
) -> BlockOutput:
try:
- status = self.unassign_reviewer(
+ status = await self.unassign_reviewer(
credentials,
input_data.pr_url,
input_data.reviewer,
@@ -477,12 +480,12 @@ class GithubListPRReviewersBlock(Block):
)
@staticmethod
- def list_reviewers(
+ async def list_reviewers(
credentials: GithubCredentials, pr_url: str
) -> list[Output.ReviewerItem]:
api = get_api(credentials)
reviewers_url = prepare_pr_api_url(pr_url=pr_url, path="requested_reviewers")
- response = api.get(reviewers_url)
+ response = await api.get(reviewers_url)
data = response.json()
reviewers: list[GithubListPRReviewersBlock.Output.ReviewerItem] = [
{"username": reviewer["login"], "url": reviewer["html_url"]}
@@ -490,18 +493,18 @@ class GithubListPRReviewersBlock(Block):
]
return reviewers
- def run(
+ async def run(
self,
input_data: Input,
*,
credentials: GithubCredentials,
**kwargs,
) -> BlockOutput:
- reviewers = self.list_reviewers(
+ for reviewer in await self.list_reviewers(
credentials,
input_data.pr_url,
- )
- yield from (("reviewer", reviewer) for reviewer in reviewers)
+ ):
+ yield "reviewer", reviewer
def prepare_pr_api_url(pr_url: str, path: str) -> str:
diff --git a/autogpt_platform/backend/backend/blocks/github/repo.py b/autogpt_platform/backend/backend/blocks/github/repo.py
index 82bef9475b..f44cd95e1a 100644
--- a/autogpt_platform/backend/backend/blocks/github/repo.py
+++ b/autogpt_platform/backend/backend/blocks/github/repo.py
@@ -65,12 +65,12 @@ class GithubListTagsBlock(Block):
)
@staticmethod
- def list_tags(
+ async def list_tags(
credentials: GithubCredentials, repo_url: str
) -> list[Output.TagItem]:
api = get_api(credentials)
tags_url = repo_url + "/tags"
- response = api.get(tags_url)
+ response = await api.get(tags_url)
data = response.json()
repo_path = repo_url.replace("https://github.com/", "")
tags: list[GithubListTagsBlock.Output.TagItem] = [
@@ -82,18 +82,19 @@ class GithubListTagsBlock(Block):
]
return tags
- def run(
+ async def run(
self,
input_data: Input,
*,
credentials: GithubCredentials,
**kwargs,
) -> BlockOutput:
- tags = self.list_tags(
+ tags = await self.list_tags(
credentials,
input_data.repo_url,
)
- yield from (("tag", tag) for tag in tags)
+ for tag in tags:
+ yield "tag", tag
class GithubListBranchesBlock(Block):
@@ -147,12 +148,12 @@ class GithubListBranchesBlock(Block):
)
@staticmethod
- def list_branches(
+ async def list_branches(
credentials: GithubCredentials, repo_url: str
) -> list[Output.BranchItem]:
api = get_api(credentials)
branches_url = repo_url + "/branches"
- response = api.get(branches_url)
+ response = await api.get(branches_url)
data = response.json()
repo_path = repo_url.replace("https://github.com/", "")
branches: list[GithubListBranchesBlock.Output.BranchItem] = [
@@ -164,18 +165,19 @@ class GithubListBranchesBlock(Block):
]
return branches
- def run(
+ async def run(
self,
input_data: Input,
*,
credentials: GithubCredentials,
**kwargs,
) -> BlockOutput:
- branches = self.list_branches(
+ branches = await self.list_branches(
credentials,
input_data.repo_url,
)
- yield from (("branch", branch) for branch in branches)
+ for branch in branches:
+ yield "branch", branch
class GithubListDiscussionsBlock(Block):
@@ -234,7 +236,7 @@ class GithubListDiscussionsBlock(Block):
)
@staticmethod
- def list_discussions(
+ async def list_discussions(
credentials: GithubCredentials, repo_url: str, num_discussions: int
) -> list[Output.DiscussionItem]:
api = get_api(credentials)
@@ -254,7 +256,7 @@ class GithubListDiscussionsBlock(Block):
}
"""
variables = {"owner": owner, "repo": repo, "num": num_discussions}
- response = api.post(
+ response = await api.post(
"https://api.github.com/graphql",
json={"query": query, "variables": variables},
)
@@ -265,17 +267,20 @@ class GithubListDiscussionsBlock(Block):
]
return discussions
- def run(
+ async def run(
self,
input_data: Input,
*,
credentials: GithubCredentials,
**kwargs,
) -> BlockOutput:
- discussions = self.list_discussions(
- credentials, input_data.repo_url, input_data.num_discussions
+ discussions = await self.list_discussions(
+ credentials,
+ input_data.repo_url,
+ input_data.num_discussions,
)
- yield from (("discussion", discussion) for discussion in discussions)
+ for discussion in discussions:
+ yield "discussion", discussion
class GithubListReleasesBlock(Block):
@@ -329,30 +334,31 @@ class GithubListReleasesBlock(Block):
)
@staticmethod
- def list_releases(
+ async def list_releases(
credentials: GithubCredentials, repo_url: str
) -> list[Output.ReleaseItem]:
api = get_api(credentials)
releases_url = repo_url + "/releases"
- response = api.get(releases_url)
+ response = await api.get(releases_url)
data = response.json()
releases: list[GithubListReleasesBlock.Output.ReleaseItem] = [
{"name": release["name"], "url": release["html_url"]} for release in data
]
return releases
- def run(
+ async def run(
self,
input_data: Input,
*,
credentials: GithubCredentials,
**kwargs,
) -> BlockOutput:
- releases = self.list_releases(
+ releases = await self.list_releases(
credentials,
input_data.repo_url,
)
- yield from (("release", release) for release in releases)
+ for release in releases:
+ yield "release", release
class GithubReadFileBlock(Block):
@@ -405,40 +411,40 @@ class GithubReadFileBlock(Block):
)
@staticmethod
- def read_file(
+ async def read_file(
credentials: GithubCredentials, repo_url: str, file_path: str, branch: str
) -> tuple[str, int]:
api = get_api(credentials)
content_url = repo_url + f"/contents/{file_path}?ref={branch}"
- response = api.get(content_url)
- content = response.json()
+ response = await api.get(content_url)
+ data = response.json()
- if isinstance(content, list):
+ if isinstance(data, list):
# Multiple entries of different types exist at this path
- if not (file := next((f for f in content if f["type"] == "file"), None)):
+ if not (file := next((f for f in data if f["type"] == "file"), None)):
raise TypeError("Not a file")
- content = file
+ data = file
- if content["type"] != "file":
+ if data["type"] != "file":
raise TypeError("Not a file")
- return content["content"], content["size"]
+ return data["content"], data["size"]
- def run(
+ async def run(
self,
input_data: Input,
*,
credentials: GithubCredentials,
**kwargs,
) -> BlockOutput:
- raw_content, size = self.read_file(
+ content, size = await self.read_file(
credentials,
input_data.repo_url,
- input_data.file_path.lstrip("/"),
+ input_data.file_path,
input_data.branch,
)
- yield "raw_content", raw_content
- yield "text_content", base64.b64decode(raw_content).decode("utf-8")
+ yield "raw_content", content
+ yield "text_content", base64.b64decode(content).decode("utf-8")
yield "size", size
@@ -515,52 +521,55 @@ class GithubReadFolderBlock(Block):
)
@staticmethod
- def read_folder(
+ async def read_folder(
credentials: GithubCredentials, repo_url: str, folder_path: str, branch: str
) -> tuple[list[Output.FileEntry], list[Output.DirEntry]]:
api = get_api(credentials)
contents_url = repo_url + f"/contents/{folder_path}?ref={branch}"
- response = api.get(contents_url)
- content = response.json()
+ response = await api.get(contents_url)
+ data = response.json()
- if not isinstance(content, list):
+ if not isinstance(data, list):
raise TypeError("Not a folder")
- files = [
+ files: list[GithubReadFolderBlock.Output.FileEntry] = [
GithubReadFolderBlock.Output.FileEntry(
name=entry["name"],
path=entry["path"],
size=entry["size"],
)
- for entry in content
+ for entry in data
if entry["type"] == "file"
]
- dirs = [
+
+ dirs: list[GithubReadFolderBlock.Output.DirEntry] = [
GithubReadFolderBlock.Output.DirEntry(
name=entry["name"],
path=entry["path"],
)
- for entry in content
+ for entry in data
if entry["type"] == "dir"
]
return files, dirs
- def run(
+ async def run(
self,
input_data: Input,
*,
credentials: GithubCredentials,
**kwargs,
) -> BlockOutput:
- files, dirs = self.read_folder(
+ files, dirs = await self.read_folder(
credentials,
input_data.repo_url,
input_data.folder_path.lstrip("/"),
input_data.branch,
)
- yield from (("file", file) for file in files)
- yield from (("dir", dir) for dir in dirs)
+ for file in files:
+ yield "file", file
+ for dir in dirs:
+ yield "dir", dir
class GithubMakeBranchBlock(Block):
@@ -606,32 +615,35 @@ class GithubMakeBranchBlock(Block):
)
@staticmethod
- def create_branch(
+ async def create_branch(
credentials: GithubCredentials,
repo_url: str,
new_branch: str,
source_branch: str,
) -> str:
api = get_api(credentials)
- # Get the SHA of the source branch
ref_url = repo_url + f"/git/refs/heads/{source_branch}"
- response = api.get(ref_url)
- sha = response.json()["object"]["sha"]
+ response = await api.get(ref_url)
+ data = response.json()
+ sha = data["object"]["sha"]
# Create the new branch
- create_ref_url = repo_url + "/git/refs"
- data = {"ref": f"refs/heads/{new_branch}", "sha": sha}
- response = api.post(create_ref_url, json=data)
+ new_ref_url = repo_url + "/git/refs"
+ data = {
+ "ref": f"refs/heads/{new_branch}",
+ "sha": sha,
+ }
+ response = await api.post(new_ref_url, json=data)
return "Branch created successfully"
- def run(
+ async def run(
self,
input_data: Input,
*,
credentials: GithubCredentials,
**kwargs,
) -> BlockOutput:
- status = self.create_branch(
+ status = await self.create_branch(
credentials,
input_data.repo_url,
input_data.new_branch,
@@ -678,22 +690,22 @@ class GithubDeleteBranchBlock(Block):
)
@staticmethod
- def delete_branch(
+ async def delete_branch(
credentials: GithubCredentials, repo_url: str, branch: str
) -> str:
api = get_api(credentials)
ref_url = repo_url + f"/git/refs/heads/{branch}"
- api.delete(ref_url)
+ await api.delete(ref_url)
return "Branch deleted successfully"
- def run(
+ async def run(
self,
input_data: Input,
*,
credentials: GithubCredentials,
**kwargs,
) -> BlockOutput:
- status = self.delete_branch(
+ status = await self.delete_branch(
credentials,
input_data.repo_url,
input_data.branch,
@@ -761,7 +773,7 @@ class GithubCreateFileBlock(Block):
)
@staticmethod
- def create_file(
+ async def create_file(
credentials: GithubCredentials,
repo_url: str,
file_path: str,
@@ -770,23 +782,18 @@ class GithubCreateFileBlock(Block):
commit_message: str,
) -> tuple[str, str]:
api = get_api(credentials)
- # Convert content to base64
- content_bytes = content.encode("utf-8")
- content_base64 = base64.b64encode(content_bytes).decode("utf-8")
-
- # Create the file using the GitHub API
- contents_url = f"{repo_url}/contents/{file_path}"
+ contents_url = repo_url + f"/contents/{file_path}"
+ content_base64 = base64.b64encode(content.encode()).decode()
data = {
"message": commit_message,
"content": content_base64,
"branch": branch,
}
- response = api.put(contents_url, json=data)
- result = response.json()
+ response = await api.put(contents_url, json=data)
+ data = response.json()
+ return data["content"]["html_url"], data["commit"]["sha"]
- return result["content"]["html_url"], result["commit"]["sha"]
-
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -794,7 +801,7 @@ class GithubCreateFileBlock(Block):
**kwargs,
) -> BlockOutput:
try:
- url, sha = self.create_file(
+ url, sha = await self.create_file(
credentials,
input_data.repo_url,
input_data.file_path,
@@ -866,7 +873,7 @@ class GithubUpdateFileBlock(Block):
)
@staticmethod
- def update_file(
+ async def update_file(
credentials: GithubCredentials,
repo_url: str,
file_path: str,
@@ -875,30 +882,24 @@ class GithubUpdateFileBlock(Block):
commit_message: str,
) -> tuple[str, str]:
api = get_api(credentials)
-
- # First get the current file to get its SHA
- contents_url = f"{repo_url}/contents/{file_path}"
+ contents_url = repo_url + f"/contents/{file_path}"
params = {"ref": branch}
- response = api.get(contents_url, params=params)
- current_file = response.json()
+ response = await api.get(contents_url, params=params)
+ data = response.json()
# Convert new content to base64
- content_bytes = content.encode("utf-8")
- content_base64 = base64.b64encode(content_bytes).decode("utf-8")
-
- # Update the file
+ content_base64 = base64.b64encode(content.encode()).decode()
data = {
"message": commit_message,
"content": content_base64,
- "sha": current_file["sha"],
+ "sha": data["sha"],
"branch": branch,
}
- response = api.put(contents_url, json=data)
- result = response.json()
+ response = await api.put(contents_url, json=data)
+ data = response.json()
+ return data["content"]["html_url"], data["commit"]["sha"]
- return result["content"]["html_url"], result["commit"]["sha"]
-
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -906,7 +907,7 @@ class GithubUpdateFileBlock(Block):
**kwargs,
) -> BlockOutput:
try:
- url, sha = self.update_file(
+ url, sha = await self.update_file(
credentials,
input_data.repo_url,
input_data.file_path,
@@ -981,7 +982,7 @@ class GithubCreateRepositoryBlock(Block):
)
@staticmethod
- def create_repository(
+ async def create_repository(
credentials: GithubCredentials,
name: str,
description: str,
@@ -989,24 +990,19 @@ class GithubCreateRepositoryBlock(Block):
auto_init: bool,
gitignore_template: str,
) -> tuple[str, str]:
- api = get_api(credentials, convert_urls=False) # Disable URL conversion
+ api = get_api(credentials)
data = {
"name": name,
"description": description,
"private": private,
"auto_init": auto_init,
+ "gitignore_template": gitignore_template,
}
+ response = await api.post("https://api.github.com/user/repos", json=data)
+ data = response.json()
+ return data["html_url"], data["clone_url"]
- if gitignore_template:
- data["gitignore_template"] = gitignore_template
-
- # Create repository using the user endpoint
- response = api.post("https://api.github.com/user/repos", json=data)
- result = response.json()
-
- return result["html_url"], result["clone_url"]
-
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -1014,7 +1010,7 @@ class GithubCreateRepositoryBlock(Block):
**kwargs,
) -> BlockOutput:
try:
- url, clone_url = self.create_repository(
+ url, clone_url = await self.create_repository(
credentials,
input_data.name,
input_data.description,
@@ -1081,17 +1077,13 @@ class GithubListStargazersBlock(Block):
)
@staticmethod
- def list_stargazers(
+ async def list_stargazers(
credentials: GithubCredentials, repo_url: str
) -> list[Output.StargazerItem]:
api = get_api(credentials)
- # Add /stargazers to the repo URL to get stargazers endpoint
- stargazers_url = f"{repo_url}/stargazers"
- # Set accept header to get starred_at timestamp
- headers = {"Accept": "application/vnd.github.star+json"}
- response = api.get(stargazers_url, headers=headers)
+ stargazers_url = repo_url + "/stargazers"
+ response = await api.get(stargazers_url)
data = response.json()
-
stargazers: list[GithubListStargazersBlock.Output.StargazerItem] = [
{
"username": stargazer["login"],
@@ -1101,18 +1093,16 @@ class GithubListStargazersBlock(Block):
]
return stargazers
- def run(
+ async def run(
self,
input_data: Input,
*,
credentials: GithubCredentials,
**kwargs,
) -> BlockOutput:
- try:
- stargazers = self.list_stargazers(
- credentials,
- input_data.repo_url,
- )
- yield from (("stargazer", stargazer) for stargazer in stargazers)
- except Exception as e:
- yield "error", str(e)
+ stargazers = await self.list_stargazers(
+ credentials,
+ input_data.repo_url,
+ )
+ for stargazer in stargazers:
+ yield "stargazer", stargazer
diff --git a/autogpt_platform/backend/backend/blocks/github/statuses.py b/autogpt_platform/backend/backend/blocks/github/statuses.py
index a69b0e3d61..a7e2b006aa 100644
--- a/autogpt_platform/backend/backend/blocks/github/statuses.py
+++ b/autogpt_platform/backend/backend/blocks/github/statuses.py
@@ -115,7 +115,7 @@ class GithubCreateStatusBlock(Block):
)
@staticmethod
- def create_status(
+ async def create_status(
credentials: GithubFineGrainedAPICredentials,
repo_url: str,
sha: str,
@@ -144,7 +144,9 @@ class GithubCreateStatusBlock(Block):
data.description = description
status_url = f"{repo_url}/statuses/{sha}"
- response = api.post(status_url, data=data.model_dump_json(exclude_none=True))
+ response = await api.post(
+ status_url, data=data.model_dump_json(exclude_none=True)
+ )
result = response.json()
return {
@@ -158,7 +160,7 @@ class GithubCreateStatusBlock(Block):
"updated_at": result["updated_at"],
}
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -166,7 +168,7 @@ class GithubCreateStatusBlock(Block):
**kwargs,
) -> BlockOutput:
try:
- result = self.create_status(
+ result = await self.create_status(
credentials=credentials,
repo_url=input_data.repo_url,
sha=input_data.sha,
diff --git a/autogpt_platform/backend/backend/blocks/github/triggers.py b/autogpt_platform/backend/backend/blocks/github/triggers.py
index 0410ed02a3..83b1689b89 100644
--- a/autogpt_platform/backend/backend/blocks/github/triggers.py
+++ b/autogpt_platform/backend/backend/blocks/github/triggers.py
@@ -53,7 +53,7 @@ class GitHubTriggerBase:
description="Error message if the payload could not be processed"
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
yield "payload", input_data.payload
yield "triggered_by_user", input_data.payload["sender"]
@@ -148,8 +148,9 @@ class GithubPullRequestTriggerBlock(GitHubTriggerBase, Block):
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput: # type: ignore
- yield from super().run(input_data, **kwargs)
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput: # type: ignore
+ async for name, value in super().run(input_data, **kwargs):
+ yield name, value
yield "event", input_data.payload["action"]
yield "number", input_data.payload["number"]
yield "pull_request", input_data.payload["pull_request"]
diff --git a/autogpt_platform/backend/backend/blocks/google/calendar.py b/autogpt_platform/backend/backend/blocks/google/calendar.py
index f119527f26..27cc9e5958 100644
--- a/autogpt_platform/backend/backend/blocks/google/calendar.py
+++ b/autogpt_platform/backend/backend/blocks/google/calendar.py
@@ -1,3 +1,4 @@
+import asyncio
import enum
import uuid
from datetime import datetime, timedelta, timezone
@@ -168,7 +169,7 @@ class GoogleCalendarReadEventsBlock(Block):
},
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: GoogleCredentials, **kwargs
) -> BlockOutput:
try:
@@ -180,7 +181,8 @@ class GoogleCalendarReadEventsBlock(Block):
)
# Call Google Calendar API
- result = self._read_calendar(
+ result = await asyncio.to_thread(
+ self._read_calendar,
service=service,
calendarId=input_data.calendar_id,
time_min=input_data.start_time.isoformat(),
@@ -477,12 +479,13 @@ class GoogleCalendarCreateEventBlock(Block):
},
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: GoogleCredentials, **kwargs
) -> BlockOutput:
try:
service = self._build_service(credentials, **kwargs)
+ # Create event body
# Get start and end times based on the timing option
if input_data.timing.discriminator == "exact_timing":
start_datetime = input_data.timing.start_datetime
@@ -543,7 +546,8 @@ class GoogleCalendarCreateEventBlock(Block):
event_body["recurrence"] = [rule]
# Create the event
- result = self._create_event(
+ result = await asyncio.to_thread(
+ self._create_event,
service=service,
calendar_id=input_data.calendar_id,
event_body=event_body,
@@ -551,8 +555,9 @@ class GoogleCalendarCreateEventBlock(Block):
conference_data_version=1 if input_data.add_google_meet else 0,
)
- yield "event_id", result.get("id", "")
- yield "event_link", result.get("htmlLink", "")
+ yield "event_id", result["id"]
+ yield "event_link", result["htmlLink"]
+
except Exception as e:
yield "error", str(e)
diff --git a/autogpt_platform/backend/backend/blocks/google/gmail.py b/autogpt_platform/backend/backend/blocks/google/gmail.py
index 780cc1b16f..a6d2db3665 100644
--- a/autogpt_platform/backend/backend/blocks/google/gmail.py
+++ b/autogpt_platform/backend/backend/blocks/google/gmail.py
@@ -1,3 +1,4 @@
+import asyncio
import base64
from email.utils import parseaddr
from typing import List
@@ -128,11 +129,13 @@ class GmailReadBlock(Block):
},
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: GoogleCredentials, **kwargs
) -> BlockOutput:
- service = self._build_service(credentials, **kwargs)
- messages = self._read_emails(service, input_data.query, input_data.max_results)
+ service = GmailReadBlock._build_service(credentials, **kwargs)
+ messages = await asyncio.to_thread(
+ self._read_emails, service, input_data.query, input_data.max_results
+ )
for email in messages:
yield "email", email
yield "emails", messages
@@ -286,14 +289,18 @@ class GmailSendBlock(Block):
},
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: GoogleCredentials, **kwargs
) -> BlockOutput:
service = GmailReadBlock._build_service(credentials, **kwargs)
- send_result = self._send_email(
- service, input_data.to, input_data.subject, input_data.body
+ result = await asyncio.to_thread(
+ self._send_email,
+ service,
+ input_data.to,
+ input_data.subject,
+ input_data.body,
)
- yield "result", send_result
+ yield "result", result
def _send_email(self, service, to: str, subject: str, body: str) -> dict:
if not to or not subject or not body:
@@ -358,12 +365,12 @@ class GmailListLabelsBlock(Block):
},
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: GoogleCredentials, **kwargs
) -> BlockOutput:
service = GmailReadBlock._build_service(credentials, **kwargs)
- labels = self._list_labels(service)
- yield "result", labels
+ result = await asyncio.to_thread(self._list_labels, service)
+ yield "result", result
def _list_labels(self, service) -> list[dict]:
results = service.users().labels().list(userId="me").execute()
@@ -419,11 +426,13 @@ class GmailAddLabelBlock(Block):
},
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: GoogleCredentials, **kwargs
) -> BlockOutput:
service = GmailReadBlock._build_service(credentials, **kwargs)
- result = self._add_label(service, input_data.message_id, input_data.label_name)
+ result = await asyncio.to_thread(
+ self._add_label, service, input_data.message_id, input_data.label_name
+ )
yield "result", result
def _add_label(self, service, message_id: str, label_name: str) -> dict:
@@ -502,12 +511,12 @@ class GmailRemoveLabelBlock(Block):
},
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: GoogleCredentials, **kwargs
) -> BlockOutput:
service = GmailReadBlock._build_service(credentials, **kwargs)
- result = self._remove_label(
- service, input_data.message_id, input_data.label_name
+ result = await asyncio.to_thread(
+ self._remove_label, service, input_data.message_id, input_data.label_name
)
yield "result", result
diff --git a/autogpt_platform/backend/backend/blocks/google/sheets.py b/autogpt_platform/backend/backend/blocks/google/sheets.py
index 141e359184..6a866051ff 100644
--- a/autogpt_platform/backend/backend/blocks/google/sheets.py
+++ b/autogpt_platform/backend/backend/blocks/google/sheets.py
@@ -1,3 +1,5 @@
+import asyncio
+
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
@@ -68,11 +70,13 @@ class GoogleSheetsReadBlock(Block):
},
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: GoogleCredentials, **kwargs
) -> BlockOutput:
service = self._build_service(credentials, **kwargs)
- data = self._read_sheet(service, input_data.spreadsheet_id, input_data.range)
+ data = await asyncio.to_thread(
+ self._read_sheet, service, input_data.spreadsheet_id, input_data.range
+ )
yield "result", data
@staticmethod
@@ -157,11 +161,12 @@ class GoogleSheetsWriteBlock(Block):
},
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: GoogleCredentials, **kwargs
) -> BlockOutput:
service = GoogleSheetsReadBlock._build_service(credentials, **kwargs)
- result = self._write_sheet(
+ result = await asyncio.to_thread(
+ self._write_sheet,
service,
input_data.spreadsheet_id,
input_data.range,
diff --git a/autogpt_platform/backend/backend/blocks/google_maps.py b/autogpt_platform/backend/backend/blocks/google_maps.py
index 9e7f793531..01e81c69c9 100644
--- a/autogpt_platform/backend/backend/blocks/google_maps.py
+++ b/autogpt_platform/backend/backend/blocks/google_maps.py
@@ -103,7 +103,7 @@ class GoogleMapsSearchBlock(Block):
test_credentials=TEST_CREDENTIALS,
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
places = self.search_places(
diff --git a/autogpt_platform/backend/backend/blocks/helpers/http.py b/autogpt_platform/backend/backend/blocks/helpers/http.py
index 33579ba0d9..f68b9f5a8b 100644
--- a/autogpt_platform/backend/backend/blocks/helpers/http.py
+++ b/autogpt_platform/backend/backend/blocks/helpers/http.py
@@ -1,14 +1,17 @@
from typing import Any, Optional
-from backend.util.request import requests
+from backend.util.request import Requests
class GetRequest:
@classmethod
- def get_request(
+ async def get_request(
cls, url: str, headers: Optional[dict] = None, json: bool = False
) -> Any:
if headers is None:
headers = {}
- response = requests.get(url, headers=headers)
- return response.json() if json else response.text
+ response = await Requests().get(url, headers=headers)
+ if json:
+ return response.json()
+ else:
+ return response.text()
diff --git a/autogpt_platform/backend/backend/blocks/http.py b/autogpt_platform/backend/backend/blocks/http.py
index d186e7f70b..9bb6d9b55e 100644
--- a/autogpt_platform/backend/backend/blocks/http.py
+++ b/autogpt_platform/backend/backend/blocks/http.py
@@ -1,10 +1,10 @@
import json
import logging
from enum import Enum
-from io import BufferedReader
+from io import BytesIO
from pathlib import Path
-from requests.exceptions import HTTPError, RequestException
+import aiofiles
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
from backend.data.model import SchemaField
@@ -14,7 +14,7 @@ from backend.util.file import (
get_mime_type,
store_media_file,
)
-from backend.util.request import requests
+from backend.util.request import Requests
logger = logging.getLogger(name=__name__)
@@ -77,54 +77,64 @@ class SendWebRequestBlock(Block):
)
@staticmethod
- def _prepare_files(
+ async def _prepare_files(
graph_exec_id: str,
files_name: str,
files: list[MediaFileType],
- ) -> tuple[list[tuple[str, tuple[str, BufferedReader, str]]], list[BufferedReader]]:
- """Convert the `files` mapping into the structure expected by `requests`.
-
- Returns a tuple of (**files_payload**, **open_handles**) so we can close handles later.
+ ) -> list[tuple[str, tuple[str, BytesIO, str]]]:
"""
- files_payload: list[tuple[str, tuple[str, BufferedReader, str]]] = []
- open_handles: list[BufferedReader] = []
+ Prepare files for the request by storing them and reading their content.
+ Returns a list of tuples in the format:
+ (files_name, (filename, BytesIO, mime_type))
+ """
+ files_payload: list[tuple[str, tuple[str, BytesIO, str]]] = []
for media in files:
# Normalise to a list so we can repeat the same key
- rel_path = store_media_file(graph_exec_id, media, return_content=False)
+ rel_path = await store_media_file(
+ graph_exec_id, media, return_content=False
+ )
abs_path = get_exec_file_path(graph_exec_id, rel_path)
- try:
- handle = open(abs_path, "rb")
- except Exception as e:
- for h in open_handles:
- try:
- h.close()
- except Exception:
- pass
- raise RuntimeError(f"Failed to open file '{abs_path}': {e}") from e
+ async with aiofiles.open(abs_path, "rb") as f:
+ content = await f.read()
+ handle = BytesIO(content)
+ mime = get_mime_type(abs_path)
+ files_payload.append((files_name, (Path(abs_path).name, handle, mime)))
- open_handles.append(handle)
- mime = get_mime_type(abs_path)
- files_payload.append((files_name, (Path(abs_path).name, handle, mime)))
+ return files_payload
- return files_payload, open_handles
-
- def run(self, input_data: Input, *, graph_exec_id: str, **kwargs) -> BlockOutput:
+ async def run(
+ self, input_data: Input, *, graph_exec_id: str, **kwargs
+ ) -> BlockOutput:
# ─── Parse/normalise body ────────────────────────────────────
body = input_data.body
if isinstance(body, str):
try:
- body = json.loads(body)
- except json.JSONDecodeError:
- # plain text – treat as form‑field value instead
+ # Validate JSON string length to prevent DoS attacks
+ if len(body) > 10_000_000: # 10MB limit
+ raise ValueError("JSON body too large")
+
+ parsed_body = json.loads(body)
+
+ # Validate that parsed JSON is safe (basic object/array/primitive types)
+ if (
+ isinstance(parsed_body, (dict, list, str, int, float, bool))
+ or parsed_body is None
+ ):
+ body = parsed_body
+ else:
+ # Unexpected type, treat as plain text
+ input_data.json_format = False
+
+ except (json.JSONDecodeError, ValueError):
+ # Invalid JSON or too large – treat as form‑field value instead
input_data.json_format = False
# ─── Prepare files (if any) ──────────────────────────────────
use_files = bool(input_data.files)
- files_payload: list[tuple[str, tuple[str, BufferedReader, str]]] = []
- open_handles: list[BufferedReader] = []
+ files_payload: list[tuple[str, tuple[str, BytesIO, str]]] = []
if use_files:
- files_payload, open_handles = self._prepare_files(
+ files_payload = await self._prepare_files(
graph_exec_id, input_data.files_name, input_data.files
)
@@ -135,47 +145,27 @@ class SendWebRequestBlock(Block):
)
# ─── Execute request ─────────────────────────────────────────
- try:
- response = requests.request(
- input_data.method.value,
- input_data.url,
- headers=input_data.headers,
- files=files_payload if use_files else None,
- # * If files → multipart ⇒ pass form‑fields via data=
- data=body if not input_data.json_format else None,
- # * Else, choose JSON vs url‑encoded based on flag
- json=body if (input_data.json_format and not use_files) else None,
- )
+ response = await Requests().request(
+ input_data.method.value,
+ input_data.url,
+ headers=input_data.headers,
+ files=files_payload if use_files else None,
+ # * If files → multipart ⇒ pass form‑fields via data=
+ data=body if not input_data.json_format else None,
+ # * Else, choose JSON vs url‑encoded based on flag
+ json=body if (input_data.json_format and not use_files) else None,
+ )
- # Decide how to parse the response
- if input_data.json_format or response.headers.get(
- "content-type", ""
- ).startswith("application/json"):
- result = (
- None
- if (response.status_code == 204 or not response.content.strip())
- else response.json()
- )
- else:
- result = response.text
+ # Decide how to parse the response
+ if response.headers.get("content-type", "").startswith("application/json"):
+ result = None if response.status == 204 else response.json()
+ else:
+ result = response.text()
- # Yield according to status code bucket
- if 200 <= response.status_code < 300:
- yield "response", result
- elif 400 <= response.status_code < 500:
- yield "client_error", result
- else:
- yield "server_error", result
-
- except HTTPError as e:
- yield "error", f"HTTP error: {str(e)}"
- except RequestException as e:
- yield "error", f"Request error: {str(e)}"
- except Exception as e:
- yield "error", str(e)
- finally:
- for h in open_handles:
- try:
- h.close()
- except Exception:
- pass
+ # Yield according to status code bucket
+ if 200 <= response.status < 300:
+ yield "response", result
+ elif 400 <= response.status < 500:
+ yield "client_error", result
+ else:
+ yield "server_error", result
diff --git a/autogpt_platform/backend/backend/blocks/hubspot/company.py b/autogpt_platform/backend/backend/blocks/hubspot/company.py
index 81d0fdaf9e..3026112259 100644
--- a/autogpt_platform/backend/backend/blocks/hubspot/company.py
+++ b/autogpt_platform/backend/backend/blocks/hubspot/company.py
@@ -5,7 +5,7 @@ from backend.blocks.hubspot._auth import (
)
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
from backend.data.model import SchemaField
-from backend.util.request import requests
+from backend.util.request import Requests
class HubSpotCompanyBlock(Block):
@@ -35,7 +35,7 @@ class HubSpotCompanyBlock(Block):
output_schema=HubSpotCompanyBlock.Output,
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: HubSpotCredentials, **kwargs
) -> BlockOutput:
base_url = "https://api.hubapi.com/crm/v3/objects/companies"
@@ -45,7 +45,7 @@ class HubSpotCompanyBlock(Block):
}
if input_data.operation == "create":
- response = requests.post(
+ response = await Requests().post(
base_url, headers=headers, json={"properties": input_data.company_data}
)
result = response.json()
@@ -67,14 +67,16 @@ class HubSpotCompanyBlock(Block):
}
]
}
- response = requests.post(search_url, headers=headers, json=search_data)
- result = response.json()
- yield "company", result.get("results", [{}])[0]
+ search_response = await Requests().post(
+ search_url, headers=headers, json=search_data
+ )
+ search_result = search_response.json()
+ yield "search_company", search_result.get("results", [{}])[0]
yield "status", "retrieved"
elif input_data.operation == "update":
# First get company ID by domain
- search_response = requests.post(
+ search_response = await Requests().post(
f"{base_url}/search",
headers=headers,
json={
@@ -91,10 +93,11 @@ class HubSpotCompanyBlock(Block):
]
},
)
- company_id = search_response.json().get("results", [{}])[0].get("id")
+ search_result = search_response.json()
+ company_id = search_result.get("results", [{}])[0].get("id")
if company_id:
- response = requests.patch(
+ response = await Requests().patch(
f"{base_url}/{company_id}",
headers=headers,
json={"properties": input_data.company_data},
diff --git a/autogpt_platform/backend/backend/blocks/hubspot/contact.py b/autogpt_platform/backend/backend/blocks/hubspot/contact.py
index b27649e1dc..2029adaca1 100644
--- a/autogpt_platform/backend/backend/blocks/hubspot/contact.py
+++ b/autogpt_platform/backend/backend/blocks/hubspot/contact.py
@@ -5,7 +5,7 @@ from backend.blocks.hubspot._auth import (
)
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
from backend.data.model import SchemaField
-from backend.util.request import requests
+from backend.util.request import Requests
class HubSpotContactBlock(Block):
@@ -35,7 +35,7 @@ class HubSpotContactBlock(Block):
output_schema=HubSpotContactBlock.Output,
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: HubSpotCredentials, **kwargs
) -> BlockOutput:
base_url = "https://api.hubapi.com/crm/v3/objects/contacts"
@@ -45,7 +45,7 @@ class HubSpotContactBlock(Block):
}
if input_data.operation == "create":
- response = requests.post(
+ response = await Requests().post(
base_url, headers=headers, json={"properties": input_data.contact_data}
)
result = response.json()
@@ -53,7 +53,6 @@ class HubSpotContactBlock(Block):
yield "status", "created"
elif input_data.operation == "get":
- # Search for contact by email
search_url = f"{base_url}/search"
search_data = {
"filterGroups": [
@@ -68,13 +67,15 @@ class HubSpotContactBlock(Block):
}
]
}
- response = requests.post(search_url, headers=headers, json=search_data)
+ response = await Requests().post(
+ search_url, headers=headers, json=search_data
+ )
result = response.json()
yield "contact", result.get("results", [{}])[0]
yield "status", "retrieved"
elif input_data.operation == "update":
- search_response = requests.post(
+ search_response = await Requests().post(
f"{base_url}/search",
headers=headers,
json={
@@ -91,10 +92,11 @@ class HubSpotContactBlock(Block):
]
},
)
- contact_id = search_response.json().get("results", [{}])[0].get("id")
+ search_result = search_response.json()
+ contact_id = search_result.get("results", [{}])[0].get("id")
if contact_id:
- response = requests.patch(
+ response = await Requests().patch(
f"{base_url}/{contact_id}",
headers=headers,
json={"properties": input_data.contact_data},
diff --git a/autogpt_platform/backend/backend/blocks/hubspot/engagement.py b/autogpt_platform/backend/backend/blocks/hubspot/engagement.py
index 15d0296117..7e4dbc3d01 100644
--- a/autogpt_platform/backend/backend/blocks/hubspot/engagement.py
+++ b/autogpt_platform/backend/backend/blocks/hubspot/engagement.py
@@ -7,7 +7,7 @@ from backend.blocks.hubspot._auth import (
)
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
from backend.data.model import SchemaField
-from backend.util.request import requests
+from backend.util.request import Requests
class HubSpotEngagementBlock(Block):
@@ -42,7 +42,7 @@ class HubSpotEngagementBlock(Block):
output_schema=HubSpotEngagementBlock.Output,
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: HubSpotCredentials, **kwargs
) -> BlockOutput:
base_url = "https://api.hubapi.com"
@@ -66,7 +66,9 @@ class HubSpotEngagementBlock(Block):
}
}
- response = requests.post(email_url, headers=headers, json=email_data)
+ response = await Requests().post(
+ email_url, headers=headers, json=email_data
+ )
result = response.json()
yield "result", result
yield "status", "email_sent"
@@ -80,7 +82,9 @@ class HubSpotEngagementBlock(Block):
params = {"limit": 100, "after": from_date.isoformat()}
- response = requests.get(engagement_url, headers=headers, params=params)
+ response = await Requests().get(
+ engagement_url, headers=headers, params=params
+ )
engagements = response.json()
# Process engagement metrics
diff --git a/autogpt_platform/backend/backend/blocks/ideogram.py b/autogpt_platform/backend/backend/blocks/ideogram.py
index ca9ba69a80..468f8f1d1e 100644
--- a/autogpt_platform/backend/backend/blocks/ideogram.py
+++ b/autogpt_platform/backend/backend/blocks/ideogram.py
@@ -12,7 +12,7 @@ from backend.data.model import (
SchemaField,
)
from backend.integrations.providers import ProviderName
-from backend.util.request import requests
+from backend.util.request import Requests
TEST_CREDENTIALS = APIKeyCredentials(
id="01234567-89ab-cdef-0123-456789abcdef",
@@ -196,13 +196,13 @@ class IdeogramModelBlock(Block):
test_credentials=TEST_CREDENTIALS,
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
seed = input_data.seed
# Step 1: Generate the image
- result = self.run_model(
+ result = await self.run_model(
api_key=credentials.api_key,
model_name=input_data.ideogram_model_name.value,
prompt=input_data.prompt,
@@ -217,14 +217,14 @@ class IdeogramModelBlock(Block):
# Step 2: Upscale the image if requested
if input_data.upscale == UpscaleOption.AI_UPSCALE:
- result = self.upscale_image(
+ result = await self.upscale_image(
api_key=credentials.api_key,
image_url=result,
)
yield "result", result
- def run_model(
+ async def run_model(
self,
api_key: SecretStr,
model_name: str,
@@ -267,12 +267,12 @@ class IdeogramModelBlock(Block):
}
try:
- response = requests.post(url, json=data, headers=headers)
+ response = await Requests().post(url, headers=headers, json=data)
return response.json()["data"][0]["url"]
except RequestException as e:
raise Exception(f"Failed to fetch image: {str(e)}")
- def upscale_image(self, api_key: SecretStr, image_url: str):
+ async def upscale_image(self, api_key: SecretStr, image_url: str):
url = "https://api.ideogram.ai/upscale"
headers = {
"Api-Key": api_key.get_secret_value(),
@@ -280,21 +280,22 @@ class IdeogramModelBlock(Block):
try:
# Step 1: Download the image from the provided URL
- image_response = requests.get(image_url)
+ response = await Requests().get(image_url)
+ image_content = response.content
# Step 2: Send the downloaded image to the upscale API
files = {
- "image_file": ("image.png", image_response.content, "image/png"),
+ "image_file": ("image.png", image_content, "image/png"),
}
- response = requests.post(
+ response = await Requests().post(
url,
headers=headers,
data={"image_request": "{}"},
files=files,
)
- return response.json()["data"][0]["url"]
+ return (response.json())["data"][0]["url"]
except RequestException as e:
raise Exception(f"Failed to upscale image: {str(e)}")
diff --git a/autogpt_platform/backend/backend/blocks/io.py b/autogpt_platform/backend/backend/blocks/io.py
index f9f9b85fb0..c42e6c1dd7 100644
--- a/autogpt_platform/backend/backend/blocks/io.py
+++ b/autogpt_platform/backend/backend/blocks/io.py
@@ -95,7 +95,7 @@ class AgentInputBlock(Block):
}
)
- def run(self, input_data: Input, *args, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, *args, **kwargs) -> BlockOutput:
if input_data.value is not None:
yield "result", input_data.value
@@ -186,7 +186,7 @@ class AgentOutputBlock(Block):
static_output=True,
)
- def run(self, input_data: Input, *args, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, *args, **kwargs) -> BlockOutput:
"""
Attempts to format the recorded_value using the fmt_string if provided.
If formatting fails or no fmt_string is given, returns the original recorded_value.
@@ -436,7 +436,7 @@ class AgentFileInputBlock(AgentInputBlock):
],
)
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -446,7 +446,7 @@ class AgentFileInputBlock(AgentInputBlock):
if not input_data.value:
return
- file_path = store_media_file(
+ file_path = await store_media_file(
graph_exec_id=graph_exec_id,
file=input_data.value,
return_content=False,
diff --git a/autogpt_platform/backend/backend/blocks/iteration.py b/autogpt_platform/backend/backend/blocks/iteration.py
index 0159e62d21..c0b66a2ed0 100644
--- a/autogpt_platform/backend/backend/blocks/iteration.py
+++ b/autogpt_platform/backend/backend/blocks/iteration.py
@@ -53,7 +53,7 @@ class StepThroughItemsBlock(Block):
test_mock={},
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
for data in [input_data.items, input_data.items_object, input_data.items_str]:
if not data:
continue
diff --git a/autogpt_platform/backend/backend/blocks/jina/chunking.py b/autogpt_platform/backend/backend/blocks/jina/chunking.py
index 0ebc72f1ca..052fa8e815 100644
--- a/autogpt_platform/backend/backend/blocks/jina/chunking.py
+++ b/autogpt_platform/backend/backend/blocks/jina/chunking.py
@@ -5,7 +5,7 @@ from backend.blocks.jina._auth import (
)
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
from backend.data.model import SchemaField
-from backend.util.request import requests
+from backend.util.request import Requests
class JinaChunkingBlock(Block):
@@ -35,7 +35,7 @@ class JinaChunkingBlock(Block):
output_schema=JinaChunkingBlock.Output,
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: JinaCredentials, **kwargs
) -> BlockOutput:
url = "https://segment.jina.ai/"
@@ -55,7 +55,7 @@ class JinaChunkingBlock(Block):
"max_chunk_length": str(input_data.max_chunk_length),
}
- response = requests.post(url, headers=headers, json=data)
+ response = await Requests().post(url, headers=headers, json=data)
result = response.json()
all_chunks.extend(result.get("chunks", []))
diff --git a/autogpt_platform/backend/backend/blocks/jina/embeddings.py b/autogpt_platform/backend/backend/blocks/jina/embeddings.py
index 67a17bf2c3..abc2f9d6ae 100644
--- a/autogpt_platform/backend/backend/blocks/jina/embeddings.py
+++ b/autogpt_platform/backend/backend/blocks/jina/embeddings.py
@@ -5,7 +5,7 @@ from backend.blocks.jina._auth import (
)
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
from backend.data.model import SchemaField
-from backend.util.request import requests
+from backend.util.request import Requests
class JinaEmbeddingBlock(Block):
@@ -29,7 +29,7 @@ class JinaEmbeddingBlock(Block):
output_schema=JinaEmbeddingBlock.Output,
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: JinaCredentials, **kwargs
) -> BlockOutput:
url = "https://api.jina.ai/v1/embeddings"
@@ -38,6 +38,6 @@ class JinaEmbeddingBlock(Block):
"Authorization": f"Bearer {credentials.api_key.get_secret_value()}",
}
data = {"input": input_data.texts, "model": input_data.model}
- response = requests.post(url, headers=headers, json=data)
+ response = await Requests().post(url, headers=headers, json=data)
embeddings = [e["embedding"] for e in response.json()["data"]]
yield "embeddings", embeddings
diff --git a/autogpt_platform/backend/backend/blocks/jina/fact_checker.py b/autogpt_platform/backend/backend/blocks/jina/fact_checker.py
index c9b8c08d1d..9cf1e277fd 100644
--- a/autogpt_platform/backend/backend/blocks/jina/fact_checker.py
+++ b/autogpt_platform/backend/backend/blocks/jina/fact_checker.py
@@ -1,7 +1,5 @@
from urllib.parse import quote
-import requests
-
from backend.blocks.jina._auth import (
JinaCredentials,
JinaCredentialsField,
@@ -9,6 +7,7 @@ from backend.blocks.jina._auth import (
)
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
from backend.data.model import SchemaField
+from backend.util.request import Requests
class FactCheckerBlock(Block):
@@ -35,7 +34,7 @@ class FactCheckerBlock(Block):
output_schema=FactCheckerBlock.Output,
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: JinaCredentials, **kwargs
) -> BlockOutput:
encoded_statement = quote(input_data.statement)
@@ -46,8 +45,7 @@ class FactCheckerBlock(Block):
"Authorization": f"Bearer {credentials.api_key.get_secret_value()}",
}
- response = requests.get(url, headers=headers)
- response.raise_for_status()
+ response = await Requests().get(url, headers=headers)
data = response.json()
if "data" in data:
diff --git a/autogpt_platform/backend/backend/blocks/jina/search.py b/autogpt_platform/backend/backend/blocks/jina/search.py
index 248d8af720..90a6eea51c 100644
--- a/autogpt_platform/backend/backend/blocks/jina/search.py
+++ b/autogpt_platform/backend/backend/blocks/jina/search.py
@@ -39,7 +39,7 @@ class SearchTheWebBlock(Block, GetRequest):
test_mock={"get_request": lambda *args, **kwargs: "search content"},
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: JinaCredentials, **kwargs
) -> BlockOutput:
# Encode the search query
@@ -51,7 +51,7 @@ class SearchTheWebBlock(Block, GetRequest):
# Prepend the Jina Search URL to the encoded query
jina_search_url = f"https://s.jina.ai/{encoded_query}"
- results = self.get_request(jina_search_url, headers=headers, json=False)
+ results = await self.get_request(jina_search_url, headers=headers, json=False)
# Output the search results
yield "results", results
@@ -90,7 +90,7 @@ class ExtractWebsiteContentBlock(Block, GetRequest):
test_mock={"get_request": lambda *args, **kwargs: "scraped content"},
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: JinaCredentials, **kwargs
) -> BlockOutput:
if input_data.raw_content:
@@ -103,5 +103,5 @@ class ExtractWebsiteContentBlock(Block, GetRequest):
"Authorization": f"Bearer {credentials.api_key.get_secret_value()}",
}
- content = self.get_request(url, json=False, headers=headers)
+ content = await self.get_request(url, json=False, headers=headers)
yield "content", content
diff --git a/autogpt_platform/backend/backend/blocks/linear/_api.py b/autogpt_platform/backend/backend/blocks/linear/_api.py
index c43f46fa70..0acee7fada 100644
--- a/autogpt_platform/backend/backend/blocks/linear/_api.py
+++ b/autogpt_platform/backend/backend/blocks/linear/_api.py
@@ -48,7 +48,7 @@ class LinearClient:
raise_for_status=False,
)
- def _execute_graphql_request(
+ async def _execute_graphql_request(
self, query: str, variables: dict | None = None
) -> Any:
"""
@@ -65,19 +65,18 @@ class LinearClient:
if variables:
payload["variables"] = variables
- response = self._requests.post(self.API_URL, json=payload)
+ response = await self._requests.post(self.API_URL, json=payload)
if not response.ok:
-
try:
error_data = response.json()
error_message = error_data.get("errors", [{}])[0].get("message", "")
except json.JSONDecodeError:
- error_message = response.text
+ error_message = response.text()
raise LinearAPIException(
- f"Linear API request failed ({response.status_code}): {error_message}",
- response.status_code,
+ f"Linear API request failed ({response.status}): {error_message}",
+ response.status,
)
response_data = response.json()
@@ -88,12 +87,12 @@ class LinearClient:
]
raise LinearAPIException(
f"Linear API returned errors: {', '.join(error_messages)}",
- response.status_code,
+ response.status,
)
return response_data["data"]
- def query(self, query: str, variables: Optional[dict] = None) -> dict:
+ async def query(self, query: str, variables: Optional[dict] = None) -> dict:
"""Executes a GraphQL query.
Args:
@@ -103,9 +102,9 @@ class LinearClient:
Returns:
The response data.
"""
- return self._execute_graphql_request(query, variables)
+ return await self._execute_graphql_request(query, variables)
- def mutate(self, mutation: str, variables: Optional[dict] = None) -> dict:
+ async def mutate(self, mutation: str, variables: Optional[dict] = None) -> dict:
"""Executes a GraphQL mutation.
Args:
@@ -115,9 +114,11 @@ class LinearClient:
Returns:
The response data.
"""
- return self._execute_graphql_request(mutation, variables)
+ return await self._execute_graphql_request(mutation, variables)
- def try_create_comment(self, issue_id: str, comment: str) -> CreateCommentResponse:
+ async def try_create_comment(
+ self, issue_id: str, comment: str
+ ) -> CreateCommentResponse:
try:
mutation = """
mutation CommentCreate($input: CommentCreateInput!) {
@@ -138,13 +139,13 @@ class LinearClient:
}
}
- added_comment = self.mutate(mutation, variables)
+ added_comment = await self.mutate(mutation, variables)
# Select the commentCreate field from the mutation response
return CreateCommentResponse(**added_comment["commentCreate"])
except LinearAPIException as e:
raise e
- def try_get_team_by_name(self, team_name: str) -> str:
+ async def try_get_team_by_name(self, team_name: str) -> str:
try:
query = """
query GetTeamId($searchTerm: String!) {
@@ -167,12 +168,12 @@ class LinearClient:
"searchTerm": team_name,
}
- team_id = self.query(query, variables)
+ team_id = await self.query(query, variables)
return team_id["teams"]["nodes"][0]["id"]
except LinearAPIException as e:
raise e
- def try_create_issue(
+ async def try_create_issue(
self,
team_id: str,
title: str,
@@ -211,12 +212,12 @@ class LinearClient:
if priority:
variables["input"]["priority"] = priority
- added_issue = self.mutate(mutation, variables)
+ added_issue = await self.mutate(mutation, variables)
return CreateIssueResponse(**added_issue["issueCreate"])
except LinearAPIException as e:
raise e
- def try_search_projects(self, term: str) -> list[Project]:
+ async def try_search_projects(self, term: str) -> list[Project]:
try:
query = """
query SearchProjects($term: String!, $includeComments: Boolean!) {
@@ -238,14 +239,14 @@ class LinearClient:
"includeComments": True,
}
- projects = self.query(query, variables)
+ projects = await self.query(query, variables)
return [
Project(**project) for project in projects["searchProjects"]["nodes"]
]
except LinearAPIException as e:
raise e
- def try_search_issues(self, term: str) -> list[Issue]:
+ async def try_search_issues(self, term: str) -> list[Issue]:
try:
query = """
query SearchIssues($term: String!, $includeComments: Boolean!) {
@@ -266,7 +267,7 @@ class LinearClient:
"includeComments": True,
}
- issues = self.query(query, variables)
+ issues = await self.query(query, variables)
return [Issue(**issue) for issue in issues["searchIssues"]["nodes"]]
except LinearAPIException as e:
raise e
diff --git a/autogpt_platform/backend/backend/blocks/linear/comment.py b/autogpt_platform/backend/backend/blocks/linear/comment.py
index 6789fd12e3..d065609bf8 100644
--- a/autogpt_platform/backend/backend/blocks/linear/comment.py
+++ b/autogpt_platform/backend/backend/blocks/linear/comment.py
@@ -54,21 +54,21 @@ class LinearCreateCommentBlock(Block):
)
@staticmethod
- def create_comment(
+ async def create_comment(
credentials: LinearCredentials, issue_id: str, comment: str
) -> tuple[str, str]:
client = LinearClient(credentials=credentials)
- response: CreateCommentResponse = client.try_create_comment(
+ response: CreateCommentResponse = await client.try_create_comment(
issue_id=issue_id, comment=comment
)
return response.comment.id, response.comment.body
- def run(
+ async def run(
self, input_data: Input, *, credentials: LinearCredentials, **kwargs
) -> BlockOutput:
"""Execute the comment creation"""
try:
- comment_id, comment_body = self.create_comment(
+ comment_id, comment_body = await self.create_comment(
credentials=credentials,
issue_id=input_data.issue_id,
comment=input_data.comment,
diff --git a/autogpt_platform/backend/backend/blocks/linear/issues.py b/autogpt_platform/backend/backend/blocks/linear/issues.py
index f45e7fac0d..9f9d46d19a 100644
--- a/autogpt_platform/backend/backend/blocks/linear/issues.py
+++ b/autogpt_platform/backend/backend/blocks/linear/issues.py
@@ -67,7 +67,7 @@ class LinearCreateIssueBlock(Block):
)
@staticmethod
- def create_issue(
+ async def create_issue(
credentials: LinearCredentials,
team_name: str,
title: str,
@@ -76,15 +76,15 @@ class LinearCreateIssueBlock(Block):
project_name: str | None = None,
) -> tuple[str, str]:
client = LinearClient(credentials=credentials)
- team_id = client.try_get_team_by_name(team_name=team_name)
+ team_id = await client.try_get_team_by_name(team_name=team_name)
project_id: str | None = None
if project_name:
- projects = client.try_search_projects(term=project_name)
+ projects = await client.try_search_projects(term=project_name)
if projects:
project_id = projects[0].id
else:
raise LinearAPIException("Project not found", status_code=404)
- response: CreateIssueResponse = client.try_create_issue(
+ response: CreateIssueResponse = await client.try_create_issue(
team_id=team_id,
title=title,
description=description,
@@ -93,12 +93,12 @@ class LinearCreateIssueBlock(Block):
)
return response.issue.identifier, response.issue.title
- def run(
+ async def run(
self, input_data: Input, *, credentials: LinearCredentials, **kwargs
) -> BlockOutput:
"""Execute the issue creation"""
try:
- issue_id, issue_title = self.create_issue(
+ issue_id, issue_title = await self.create_issue(
credentials=credentials,
team_name=input_data.team_name,
title=input_data.title,
@@ -168,20 +168,22 @@ class LinearSearchIssuesBlock(Block):
)
@staticmethod
- def search_issues(
+ async def search_issues(
credentials: LinearCredentials,
term: str,
) -> list[Issue]:
client = LinearClient(credentials=credentials)
- response: list[Issue] = client.try_search_issues(term=term)
+ response: list[Issue] = await client.try_search_issues(term=term)
return response
- def run(
+ async def run(
self, input_data: Input, *, credentials: LinearCredentials, **kwargs
) -> BlockOutput:
"""Execute the issue search"""
try:
- issues = self.search_issues(credentials=credentials, term=input_data.term)
+ issues = await self.search_issues(
+ credentials=credentials, term=input_data.term
+ )
yield "issues", issues
except LinearAPIException as e:
yield "error", str(e)
diff --git a/autogpt_platform/backend/backend/blocks/linear/projects.py b/autogpt_platform/backend/backend/blocks/linear/projects.py
index 695064a6a1..84f2b9ca53 100644
--- a/autogpt_platform/backend/backend/blocks/linear/projects.py
+++ b/autogpt_platform/backend/backend/blocks/linear/projects.py
@@ -69,20 +69,20 @@ class LinearSearchProjectsBlock(Block):
)
@staticmethod
- def search_projects(
+ async def search_projects(
credentials: LinearCredentials,
term: str,
) -> list[Project]:
client = LinearClient(credentials=credentials)
- response: list[Project] = client.try_search_projects(term=term)
+ response: list[Project] = await client.try_search_projects(term=term)
return response
- def run(
+ async def run(
self, input_data: Input, *, credentials: LinearCredentials, **kwargs
) -> BlockOutput:
"""Execute the project search"""
try:
- projects = self.search_projects(
+ projects = await self.search_projects(
credentials=credentials,
term=input_data.term,
)
diff --git a/autogpt_platform/backend/backend/blocks/llm.py b/autogpt_platform/backend/backend/blocks/llm.py
index a1fedeec52..5230cb4428 100644
--- a/autogpt_platform/backend/backend/blocks/llm.py
+++ b/autogpt_platform/backend/backend/blocks/llm.py
@@ -3,14 +3,13 @@ import logging
from abc import ABC
from enum import Enum, EnumMeta
from json import JSONDecodeError
-from types import MappingProxyType
from typing import Any, Iterable, List, Literal, NamedTuple, Optional
import anthropic
import ollama
import openai
from anthropic.types import ToolParam
-from groq import Groq
+from groq import AsyncGroq
from pydantic import BaseModel, SecretStr
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
@@ -24,7 +23,6 @@ from backend.data.model import (
from backend.integrations.providers import ProviderName
from backend.util import json
from backend.util.logging import TruncatedLogger
-from backend.util.settings import BehaveAs, Settings
from backend.util.text import TextFormatter
logger = TruncatedLogger(logging.getLogger(__name__), "[LLM-Block]")
@@ -73,20 +71,7 @@ class ModelMetadata(NamedTuple):
class LlmModelMeta(EnumMeta):
- @property
- def __members__(self) -> MappingProxyType:
- if Settings().config.behave_as == BehaveAs.LOCAL:
- members = super().__members__
- return MappingProxyType(members)
- else:
- removed_providers = ["ollama"]
- existing_members = super().__members__
- members = {
- name: member
- for name, member in existing_members.items()
- if LlmModel[name].provider not in removed_providers
- }
- return MappingProxyType(members)
+ pass
class LlmModel(str, Enum, metaclass=LlmModelMeta):
@@ -328,7 +313,7 @@ def estimate_token_count(prompt_messages: list[dict]) -> int:
return int(estimated_tokens * 1.2)
-def llm_call(
+async def llm_call(
credentials: APIKeyCredentials,
llm_model: LlmModel,
prompt: list[dict],
@@ -363,14 +348,14 @@ def llm_call(
# Calculate available tokens based on context window and input length
estimated_input_tokens = estimate_token_count(prompt)
context_window = llm_model.context_window
- model_max_output = llm_model.max_output_tokens or 4096
+ model_max_output = llm_model.max_output_tokens or int(2**15)
user_max = max_tokens or model_max_output
available_tokens = max(context_window - estimated_input_tokens, 0)
- max_tokens = max(min(available_tokens, model_max_output, user_max), 0)
+ max_tokens = max(min(available_tokens, model_max_output, user_max), 1)
if provider == "openai":
tools_param = tools if tools else openai.NOT_GIVEN
- oai_client = openai.OpenAI(api_key=credentials.api_key.get_secret_value())
+ oai_client = openai.AsyncOpenAI(api_key=credentials.api_key.get_secret_value())
response_format = None
if llm_model in [LlmModel.O1_MINI, LlmModel.O1_PREVIEW]:
@@ -383,7 +368,7 @@ def llm_call(
elif json_format:
response_format = {"type": "json_object"}
- response = oai_client.chat.completions.create(
+ response = await oai_client.chat.completions.create(
model=llm_model.value,
messages=prompt, # type: ignore
response_format=response_format, # type: ignore
@@ -439,9 +424,11 @@ def llm_call(
messages.append({"role": p["role"], "content": p["content"]})
last_role = p["role"]
- client = anthropic.Anthropic(api_key=credentials.api_key.get_secret_value())
+ client = anthropic.AsyncAnthropic(
+ api_key=credentials.api_key.get_secret_value()
+ )
try:
- resp = client.messages.create(
+ resp = await client.messages.create(
model=llm_model.value,
system=sysprompt,
messages=messages,
@@ -495,9 +482,9 @@ def llm_call(
if tools:
raise ValueError("Groq does not support tools.")
- client = Groq(api_key=credentials.api_key.get_secret_value())
+ client = AsyncGroq(api_key=credentials.api_key.get_secret_value())
response_format = {"type": "json_object"} if json_format else None
- response = client.chat.completions.create(
+ response = await client.chat.completions.create(
model=llm_model.value,
messages=prompt, # type: ignore
response_format=response_format, # type: ignore
@@ -515,10 +502,10 @@ def llm_call(
if tools:
raise ValueError("Ollama does not support tools.")
- client = ollama.Client(host=ollama_host)
+ client = ollama.AsyncClient(host=ollama_host)
sys_messages = [p["content"] for p in prompt if p["role"] == "system"]
usr_messages = [p["content"] for p in prompt if p["role"] != "system"]
- response = client.generate(
+ response = await client.generate(
model=llm_model.value,
prompt=f"{sys_messages}\n\n{usr_messages}",
stream=False,
@@ -534,12 +521,12 @@ def llm_call(
)
elif provider == "open_router":
tools_param = tools if tools else openai.NOT_GIVEN
- client = openai.OpenAI(
+ client = openai.AsyncOpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=credentials.api_key.get_secret_value(),
)
- response = client.chat.completions.create(
+ response = await client.chat.completions.create(
extra_headers={
"HTTP-Referer": "https://agpt.co",
"X-Title": "AutoGPT",
@@ -581,12 +568,12 @@ def llm_call(
)
elif provider == "llama_api":
tools_param = tools if tools else openai.NOT_GIVEN
- client = openai.OpenAI(
+ client = openai.AsyncOpenAI(
base_url="https://api.llama.com/compat/v1/",
api_key=credentials.api_key.get_secret_value(),
)
- response = client.chat.completions.create(
+ response = await client.chat.completions.create(
extra_headers={
"HTTP-Referer": "https://agpt.co",
"X-Title": "AutoGPT",
@@ -676,6 +663,11 @@ class AIStructuredResponseGeneratorBlock(AIBlockBase):
description="Expected format of the response. If provided, the response will be validated against this format. "
"The keys should be the expected fields in the response, and the values should be the description of the field.",
)
+ list_result: bool = SchemaField(
+ title="List Result",
+ default=False,
+ description="Whether the response should be a list of objects in the expected format.",
+ )
model: LlmModel = SchemaField(
title="LLM Model",
default=LlmModel.GPT4O,
@@ -715,7 +707,7 @@ class AIStructuredResponseGeneratorBlock(AIBlockBase):
)
class Output(BlockSchema):
- response: dict[str, Any] = SchemaField(
+ response: dict[str, Any] | list[dict[str, Any]] = SchemaField(
description="The response object generated by the language model."
)
prompt: list = SchemaField(description="The prompt sent to the language model.")
@@ -759,7 +751,7 @@ class AIStructuredResponseGeneratorBlock(AIBlockBase):
},
)
- def llm_call(
+ async def llm_call(
self,
credentials: APIKeyCredentials,
llm_model: LlmModel,
@@ -774,7 +766,7 @@ class AIStructuredResponseGeneratorBlock(AIBlockBase):
so that it can be mocked withing the block testing framework.
"""
self.prompt = prompt
- return llm_call(
+ return await llm_call(
credentials=credentials,
llm_model=llm_model,
prompt=prompt,
@@ -784,7 +776,7 @@ class AIStructuredResponseGeneratorBlock(AIBlockBase):
ollama_host=ollama_host,
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
logger.debug(f"Calling LLM with input data: {input_data}")
@@ -806,13 +798,22 @@ class AIStructuredResponseGeneratorBlock(AIBlockBase):
expected_format = [
f'"{k}": "{v}"' for k, v in input_data.expected_format.items()
]
- format_prompt = ",\n ".join(expected_format)
+ if input_data.list_result:
+ format_prompt = (
+ f'"results": [\n {{\n {", ".join(expected_format)}\n }}\n]'
+ )
+ else:
+ format_prompt = "\n ".join(expected_format)
+
sys_prompt = trim_prompt(
f"""
|Reply strictly only in the following JSON format:
|{{
| {format_prompt}
|}}
+ |
+ |Ensure the response is valid JSON. Do not include any additional text outside of the JSON.
+ |If you cannot provide all the keys, provide an empty string for the values you cannot answer.
"""
)
prompt.append({"role": "system", "content": sys_prompt})
@@ -820,17 +821,16 @@ class AIStructuredResponseGeneratorBlock(AIBlockBase):
if input_data.prompt:
prompt.append({"role": "user", "content": input_data.prompt})
- def parse_response(resp: str) -> tuple[dict[str, Any], str | None]:
+ def validate_response(parsed: object) -> str | None:
try:
- parsed = json.loads(resp)
if not isinstance(parsed, dict):
- return {}, f"Expected a dictionary, but got {type(parsed)}"
+ return f"Expected a dictionary, but got {type(parsed)}"
miss_keys = set(input_data.expected_format.keys()) - set(parsed.keys())
if miss_keys:
- return parsed, f"Missing keys: {miss_keys}"
- return parsed, None
+ return f"Missing keys: {miss_keys}"
+ return None
except JSONDecodeError as e:
- return {}, f"JSON decode error: {e}"
+ return f"JSON decode error: {e}"
logger.info(f"LLM request: {prompt}")
retry_prompt = ""
@@ -838,7 +838,7 @@ class AIStructuredResponseGeneratorBlock(AIBlockBase):
for retry_count in range(input_data.retry):
try:
- llm_response = self.llm_call(
+ llm_response = await self.llm_call(
credentials=credentials,
llm_model=llm_model,
prompt=prompt,
@@ -856,18 +856,29 @@ class AIStructuredResponseGeneratorBlock(AIBlockBase):
logger.info(f"LLM attempt-{retry_count} response: {response_text}")
if input_data.expected_format:
- parsed_dict, parsed_error = parse_response(response_text)
- if not parsed_error:
- yield "response", {
- k: (
- json.loads(v)
- if isinstance(v, str)
- and v.startswith("[")
- and v.endswith("]")
- else (", ".join(v) if isinstance(v, list) else v)
+
+ response_obj = json.loads(response_text)
+
+ if input_data.list_result and isinstance(response_obj, dict):
+ if "results" in response_obj:
+ response_obj = response_obj.get("results", [])
+ elif len(response_obj) == 1:
+ response_obj = list(response_obj.values())
+
+ response_error = "\n".join(
+ [
+ validation_error
+ for response_item in (
+ response_obj
+ if isinstance(response_obj, list)
+ else [response_obj]
)
- for k, v in parsed_dict.items()
- }
+ if (validation_error := validate_response(response_item))
+ ]
+ )
+
+ if not response_error:
+ yield "response", response_obj
yield "prompt", self.prompt
return
else:
@@ -884,7 +895,7 @@ class AIStructuredResponseGeneratorBlock(AIBlockBase):
|
|And this is the error:
|--
- |{parsed_error}
+ |{response_error}
|--
"""
)
@@ -978,17 +989,17 @@ class AITextGeneratorBlock(AIBlockBase):
test_mock={"llm_call": lambda *args, **kwargs: "Response text"},
)
- def llm_call(
+ async def llm_call(
self,
input_data: AIStructuredResponseGeneratorBlock.Input,
credentials: APIKeyCredentials,
- ) -> str:
+ ) -> dict:
block = AIStructuredResponseGeneratorBlock()
- response = block.run_once(input_data, "response", credentials=credentials)
+ response = await block.run_once(input_data, "response", credentials=credentials)
self.merge_llm_stats(block)
return response["response"]
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
object_input_data = AIStructuredResponseGeneratorBlock.Input(
@@ -998,7 +1009,8 @@ class AITextGeneratorBlock(AIBlockBase):
},
expected_format={},
)
- yield "response", self.llm_call(object_input_data, credentials)
+ response = await self.llm_call(object_input_data, credentials)
+ yield "response", response
yield "prompt", self.prompt
@@ -1080,23 +1092,27 @@ class AITextSummarizerBlock(AIBlockBase):
},
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
- for output_name, output_data in self._run(input_data, credentials):
+ async for output_name, output_data in self._run(input_data, credentials):
yield output_name, output_data
- def _run(self, input_data: Input, credentials: APIKeyCredentials) -> BlockOutput:
+ async def _run(
+ self, input_data: Input, credentials: APIKeyCredentials
+ ) -> BlockOutput:
chunks = self._split_text(
input_data.text, input_data.max_tokens, input_data.chunk_overlap
)
summaries = []
for chunk in chunks:
- chunk_summary = self._summarize_chunk(chunk, input_data, credentials)
+ chunk_summary = await self._summarize_chunk(chunk, input_data, credentials)
summaries.append(chunk_summary)
- final_summary = self._combine_summaries(summaries, input_data, credentials)
+ final_summary = await self._combine_summaries(
+ summaries, input_data, credentials
+ )
yield "summary", final_summary
yield "prompt", self.prompt
@@ -1112,22 +1128,22 @@ class AITextSummarizerBlock(AIBlockBase):
return chunks
- def llm_call(
+ async def llm_call(
self,
input_data: AIStructuredResponseGeneratorBlock.Input,
credentials: APIKeyCredentials,
) -> dict:
block = AIStructuredResponseGeneratorBlock()
- response = block.run_once(input_data, "response", credentials=credentials)
+ response = await block.run_once(input_data, "response", credentials=credentials)
self.merge_llm_stats(block)
return response
- def _summarize_chunk(
+ async def _summarize_chunk(
self, chunk: str, input_data: Input, credentials: APIKeyCredentials
) -> str:
prompt = f"Summarize the following text in a {input_data.style} form. Focus your summary on the topic of `{input_data.focus}` if present, otherwise just provide a general summary:\n\n```{chunk}```"
- llm_response = self.llm_call(
+ llm_response = await self.llm_call(
AIStructuredResponseGeneratorBlock.Input(
prompt=prompt,
credentials=input_data.credentials,
@@ -1139,7 +1155,7 @@ class AITextSummarizerBlock(AIBlockBase):
return llm_response["summary"]
- def _combine_summaries(
+ async def _combine_summaries(
self, summaries: list[str], input_data: Input, credentials: APIKeyCredentials
) -> str:
combined_text = "\n\n".join(summaries)
@@ -1147,7 +1163,7 @@ class AITextSummarizerBlock(AIBlockBase):
if len(combined_text.split()) <= input_data.max_tokens:
prompt = f"Provide a final summary of the following section summaries in a {input_data.style} form, focus your summary on the topic of `{input_data.focus}` if present:\n\n ```{combined_text}```\n\n Just respond with the final_summary in the format specified."
- llm_response = self.llm_call(
+ llm_response = await self.llm_call(
AIStructuredResponseGeneratorBlock.Input(
prompt=prompt,
credentials=input_data.credentials,
@@ -1162,7 +1178,8 @@ class AITextSummarizerBlock(AIBlockBase):
return llm_response["final_summary"]
else:
# If combined summaries are still too long, recursively summarize
- return self._run(
+ block = AITextSummarizerBlock()
+ return await block.run_once(
AITextSummarizerBlock.Input(
text=combined_text,
credentials=input_data.credentials,
@@ -1170,10 +1187,9 @@ class AITextSummarizerBlock(AIBlockBase):
max_tokens=input_data.max_tokens,
chunk_overlap=input_data.chunk_overlap,
),
+ "summary",
credentials=credentials,
- ).send(None)[
- 1
- ] # Get the first yielded value
+ )
class AIConversationBlock(AIBlockBase):
@@ -1244,20 +1260,20 @@ class AIConversationBlock(AIBlockBase):
},
)
- def llm_call(
+ async def llm_call(
self,
input_data: AIStructuredResponseGeneratorBlock.Input,
credentials: APIKeyCredentials,
- ) -> str:
+ ) -> dict:
block = AIStructuredResponseGeneratorBlock()
- response = block.run_once(input_data, "response", credentials=credentials)
+ response = await block.run_once(input_data, "response", credentials=credentials)
self.merge_llm_stats(block)
- return response["response"]
+ return response
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
- response = self.llm_call(
+ response = await self.llm_call(
AIStructuredResponseGeneratorBlock.Input(
prompt=input_data.prompt,
credentials=input_data.credentials,
@@ -1269,7 +1285,6 @@ class AIConversationBlock(AIBlockBase):
),
credentials=credentials,
)
-
yield "response", response
yield "prompt", self.prompt
@@ -1363,13 +1378,15 @@ class AIListGeneratorBlock(AIBlockBase):
},
)
- def llm_call(
+ async def llm_call(
self,
input_data: AIStructuredResponseGeneratorBlock.Input,
credentials: APIKeyCredentials,
) -> dict[str, str]:
llm_block = AIStructuredResponseGeneratorBlock()
- response = llm_block.run_once(input_data, "response", credentials=credentials)
+ response = await llm_block.run_once(
+ input_data, "response", credentials=credentials
+ )
self.merge_llm_stats(llm_block)
return response
@@ -1392,7 +1409,7 @@ class AIListGeneratorBlock(AIBlockBase):
logger.error(f"Failed to convert string to list: {e}")
raise ValueError("Invalid list format. Could not convert to list.")
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
logger.debug(f"Starting AIListGeneratorBlock.run with input data: {input_data}")
@@ -1458,7 +1475,7 @@ class AIListGeneratorBlock(AIBlockBase):
for attempt in range(input_data.max_retries):
try:
logger.debug("Calling LLM")
- llm_response = self.llm_call(
+ llm_response = await self.llm_call(
AIStructuredResponseGeneratorBlock.Input(
sys_prompt=sys_prompt,
prompt=prompt,
diff --git a/autogpt_platform/backend/backend/blocks/maths.py b/autogpt_platform/backend/backend/blocks/maths.py
index cb65de1c09..0559d9673d 100644
--- a/autogpt_platform/backend/backend/blocks/maths.py
+++ b/autogpt_platform/backend/backend/blocks/maths.py
@@ -52,7 +52,7 @@ class CalculatorBlock(Block):
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
operation = input_data.operation
a = input_data.a
b = input_data.b
@@ -107,7 +107,7 @@ class CountItemsBlock(Block):
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
collection = input_data.collection
try:
diff --git a/autogpt_platform/backend/backend/blocks/media.py b/autogpt_platform/backend/backend/blocks/media.py
index 6c9afcd10a..15a3d5d17e 100644
--- a/autogpt_platform/backend/backend/blocks/media.py
+++ b/autogpt_platform/backend/backend/blocks/media.py
@@ -39,7 +39,7 @@ class MediaDurationBlock(Block):
output_schema=MediaDurationBlock.Output,
)
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -47,7 +47,7 @@ class MediaDurationBlock(Block):
**kwargs,
) -> BlockOutput:
# 1) Store the input media locally
- local_media_path = store_media_file(
+ local_media_path = await store_media_file(
graph_exec_id=graph_exec_id,
file=input_data.media_in,
return_content=False,
@@ -105,7 +105,7 @@ class LoopVideoBlock(Block):
output_schema=LoopVideoBlock.Output,
)
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -114,7 +114,7 @@ class LoopVideoBlock(Block):
**kwargs,
) -> BlockOutput:
# 1) Store the input video locally
- local_video_path = store_media_file(
+ local_video_path = await store_media_file(
graph_exec_id=graph_exec_id,
file=input_data.video_in,
return_content=False,
@@ -146,7 +146,7 @@ class LoopVideoBlock(Block):
looped_clip.write_videofile(output_abspath, codec="libx264", audio_codec="aac")
# Return as data URI
- video_out = store_media_file(
+ video_out = await store_media_file(
graph_exec_id=graph_exec_id,
file=output_filename,
return_content=input_data.output_return_type == "data_uri",
@@ -194,7 +194,7 @@ class AddAudioToVideoBlock(Block):
output_schema=AddAudioToVideoBlock.Output,
)
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -203,12 +203,12 @@ class AddAudioToVideoBlock(Block):
**kwargs,
) -> BlockOutput:
# 1) Store the inputs locally
- local_video_path = store_media_file(
+ local_video_path = await store_media_file(
graph_exec_id=graph_exec_id,
file=input_data.video_in,
return_content=False,
)
- local_audio_path = store_media_file(
+ local_audio_path = await store_media_file(
graph_exec_id=graph_exec_id,
file=input_data.audio_in,
return_content=False,
@@ -236,7 +236,7 @@ class AddAudioToVideoBlock(Block):
final_clip.write_videofile(output_abspath, codec="libx264", audio_codec="aac")
# 5) Return either path or data URI
- video_out = store_media_file(
+ video_out = await store_media_file(
graph_exec_id=graph_exec_id,
file=output_filename,
return_content=input_data.output_return_type == "data_uri",
diff --git a/autogpt_platform/backend/backend/blocks/medium.py b/autogpt_platform/backend/backend/blocks/medium.py
index 6d871b4caa..a8964ca940 100644
--- a/autogpt_platform/backend/backend/blocks/medium.py
+++ b/autogpt_platform/backend/backend/blocks/medium.py
@@ -13,7 +13,7 @@ from backend.data.model import (
SecretField,
)
from backend.integrations.providers import ProviderName
-from backend.util.request import requests
+from backend.util.request import Requests
TEST_CREDENTIALS = APIKeyCredentials(
id="01234567-89ab-cdef-0123-456789abcdef",
@@ -130,7 +130,7 @@ class PublishToMediumBlock(Block):
test_credentials=TEST_CREDENTIALS,
)
- def create_post(
+ async def create_post(
self,
api_key: SecretStr,
author_id,
@@ -160,18 +160,17 @@ class PublishToMediumBlock(Block):
"notifyFollowers": notify_followers,
}
- response = requests.post(
+ response = await Requests().post(
f"https://api.medium.com/v1/users/{author_id}/posts",
headers=headers,
json=data,
)
-
return response.json()
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
- response = self.create_post(
+ response = await self.create_post(
credentials.api_key,
input_data.author_id.get_secret_value(),
input_data.title,
diff --git a/autogpt_platform/backend/backend/blocks/mem0.py b/autogpt_platform/backend/backend/blocks/mem0.py
index 64d7ca4bec..ad2c64f8f0 100644
--- a/autogpt_platform/backend/backend/blocks/mem0.py
+++ b/autogpt_platform/backend/backend/blocks/mem0.py
@@ -109,7 +109,7 @@ class AddMemoryBlock(Block, Mem0Base):
test_mock={"_get_client": lambda credentials: MockMemoryClient()},
)
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -208,7 +208,7 @@ class SearchMemoryBlock(Block, Mem0Base):
test_mock={"_get_client": lambda credentials: MockMemoryClient()},
)
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -288,7 +288,7 @@ class GetAllMemoriesBlock(Block, Mem0Base):
test_mock={"_get_client": lambda credentials: MockMemoryClient()},
)
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/blocks/nvidia/deepfake.py b/autogpt_platform/backend/backend/blocks/nvidia/deepfake.py
index f7fa145312..f5205f6e72 100644
--- a/autogpt_platform/backend/backend/blocks/nvidia/deepfake.py
+++ b/autogpt_platform/backend/backend/blocks/nvidia/deepfake.py
@@ -5,7 +5,7 @@ from backend.blocks.nvidia._auth import (
)
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
from backend.data.model import SchemaField
-from backend.util.request import requests
+from backend.util.request import Requests
from backend.util.type import MediaFileType
@@ -40,7 +40,7 @@ class NvidiaDeepfakeDetectBlock(Block):
output_schema=NvidiaDeepfakeDetectBlock.Output,
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: NvidiaCredentials, **kwargs
) -> BlockOutput:
url = "https://ai.api.nvidia.com/v1/cv/hive/deepfake-image-detection"
@@ -59,8 +59,7 @@ class NvidiaDeepfakeDetectBlock(Block):
}
try:
- response = requests.post(url, headers=headers, json=payload)
- response.raise_for_status()
+ response = await Requests().post(url, headers=headers, json=payload)
data = response.json()
result = data.get("data", [{}])[0]
diff --git a/autogpt_platform/backend/backend/blocks/pinecone.py b/autogpt_platform/backend/backend/blocks/pinecone.py
index 6f8a83a24c..529940b7cf 100644
--- a/autogpt_platform/backend/backend/blocks/pinecone.py
+++ b/autogpt_platform/backend/backend/blocks/pinecone.py
@@ -56,7 +56,7 @@ class PineconeInitBlock(Block):
output_schema=PineconeInitBlock.Output,
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
pc = Pinecone(api_key=credentials.api_key.get_secret_value())
@@ -117,7 +117,7 @@ class PineconeQueryBlock(Block):
output_schema=PineconeQueryBlock.Output,
)
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -195,7 +195,7 @@ class PineconeInsertBlock(Block):
output_schema=PineconeInsertBlock.Output,
)
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/blocks/reddit.py b/autogpt_platform/backend/backend/blocks/reddit.py
index b3dca4ca74..c88407f6d1 100644
--- a/autogpt_platform/backend/backend/blocks/reddit.py
+++ b/autogpt_platform/backend/backend/blocks/reddit.py
@@ -146,7 +146,7 @@ class GetRedditPostsBlock(Block):
subreddit = client.subreddit(input_data.subreddit)
return subreddit.new(limit=input_data.post_limit or 10)
- def run(
+ async def run(
self, input_data: Input, *, credentials: RedditCredentials, **kwargs
) -> BlockOutput:
current_time = datetime.now(tz=timezone.utc)
@@ -207,7 +207,7 @@ class PostRedditCommentBlock(Block):
raise ValueError("Failed to post comment.")
return new_comment.id
- def run(
+ async def run(
self, input_data: Input, *, credentials: RedditCredentials, **kwargs
) -> BlockOutput:
yield "comment_id", self.reply_post(credentials, input_data.data)
diff --git a/autogpt_platform/backend/backend/blocks/replicate_flux_advanced.py b/autogpt_platform/backend/backend/blocks/replicate_flux_advanced.py
index e75e0ad1cf..30744a28f7 100644
--- a/autogpt_platform/backend/backend/blocks/replicate_flux_advanced.py
+++ b/autogpt_platform/backend/backend/blocks/replicate_flux_advanced.py
@@ -159,7 +159,7 @@ class ReplicateFluxAdvancedModelBlock(Block):
test_credentials=TEST_CREDENTIALS,
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
# If the seed is not provided, generate a random seed
@@ -168,7 +168,7 @@ class ReplicateFluxAdvancedModelBlock(Block):
seed = int.from_bytes(os.urandom(4), "big")
# Run the model using the provided inputs
- result = self.run_model(
+ result = await self.run_model(
api_key=credentials.api_key,
model_name=input_data.replicate_model_name.api_name,
prompt=input_data.prompt,
@@ -183,7 +183,7 @@ class ReplicateFluxAdvancedModelBlock(Block):
)
yield "result", result
- def run_model(
+ async def run_model(
self,
api_key: SecretStr,
model_name,
@@ -201,7 +201,7 @@ class ReplicateFluxAdvancedModelBlock(Block):
client = ReplicateClient(api_token=api_key.get_secret_value())
# Run the model with additional parameters
- output: FileOutput | list[FileOutput] = client.run( # type: ignore This is because they changed the return type, and didn't update the type hint! It should be overloaded depending on the value of `use_file_output` to `FileOutput | list[FileOutput]` but it's `Any | Iterator[Any]`
+ output: FileOutput | list[FileOutput] = await client.async_run( # type: ignore This is because they changed the return type, and didn't update the type hint! It should be overloaded depending on the value of `use_file_output` to `FileOutput | list[FileOutput]` but it's `Any | Iterator[Any]`
f"{model_name}",
input={
"prompt": prompt,
diff --git a/autogpt_platform/backend/backend/blocks/rss.py b/autogpt_platform/backend/backend/blocks/rss.py
index 9a5a17ebee..e3f5da3139 100644
--- a/autogpt_platform/backend/backend/blocks/rss.py
+++ b/autogpt_platform/backend/backend/blocks/rss.py
@@ -1,4 +1,4 @@
-import time
+import asyncio
from datetime import datetime, timedelta, timezone
from typing import Any
@@ -87,7 +87,7 @@ class ReadRSSFeedBlock(Block):
def parse_feed(url: str) -> dict[str, Any]:
return feedparser.parse(url) # type: ignore
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
keep_going = True
start_time = datetime.now(timezone.utc) - timedelta(
minutes=input_data.time_period
@@ -113,4 +113,4 @@ class ReadRSSFeedBlock(Block):
),
)
- time.sleep(input_data.polling_rate)
+ await asyncio.sleep(input_data.polling_rate)
diff --git a/autogpt_platform/backend/backend/blocks/sampling.py b/autogpt_platform/backend/backend/blocks/sampling.py
index d2257db06f..ffd509ff75 100644
--- a/autogpt_platform/backend/backend/blocks/sampling.py
+++ b/autogpt_platform/backend/backend/blocks/sampling.py
@@ -93,7 +93,7 @@ class DataSamplingBlock(Block):
)
self.accumulated_data = []
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
if input_data.accumulate:
if isinstance(input_data.data, dict):
self.accumulated_data.append(input_data.data)
diff --git a/autogpt_platform/backend/backend/blocks/screenshotone.py b/autogpt_platform/backend/backend/blocks/screenshotone.py
index fed43b4281..7dd026a5c5 100644
--- a/autogpt_platform/backend/backend/blocks/screenshotone.py
+++ b/autogpt_platform/backend/backend/blocks/screenshotone.py
@@ -105,7 +105,7 @@ class ScreenshotWebPageBlock(Block):
)
@staticmethod
- def take_screenshot(
+ async def take_screenshot(
credentials: APIKeyCredentials,
graph_exec_id: str,
url: str,
@@ -121,11 +121,10 @@ class ScreenshotWebPageBlock(Block):
"""
Takes a screenshot using the ScreenshotOne API
"""
- api = Requests(trusted_origins=["https://api.screenshotone.com"])
+ api = Requests()
- # Build API URL with parameters
+ # Build API parameters
params = {
- "access_key": credentials.api_key.get_secret_value(),
"url": url,
"viewport_width": viewport_width,
"viewport_height": viewport_height,
@@ -137,19 +136,28 @@ class ScreenshotWebPageBlock(Block):
"cache": str(cache).lower(),
}
- response = api.get("https://api.screenshotone.com/take", params=params)
+ # Make the API request
+ # Use header-based authentication instead of query parameter
+ headers = {
+ "X-Access-Key": credentials.api_key.get_secret_value(),
+ }
+
+ response = await api.get(
+ "https://api.screenshotone.com/take", params=params, headers=headers
+ )
+ content = response.content
return {
- "image": store_media_file(
+ "image": await store_media_file(
graph_exec_id=graph_exec_id,
file=MediaFileType(
- f"data:image/{format.value};base64,{b64encode(response.content).decode('utf-8')}"
+ f"data:image/{format.value};base64,{b64encode(content).decode('utf-8')}"
),
return_content=True,
)
}
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -158,7 +166,7 @@ class ScreenshotWebPageBlock(Block):
**kwargs,
) -> BlockOutput:
try:
- screenshot_data = self.take_screenshot(
+ screenshot_data = await self.take_screenshot(
credentials=credentials,
graph_exec_id=graph_exec_id,
url=input_data.url,
diff --git a/autogpt_platform/backend/backend/blocks/search.py b/autogpt_platform/backend/backend/blocks/search.py
index 633ad31091..51eadf215e 100644
--- a/autogpt_platform/backend/backend/blocks/search.py
+++ b/autogpt_platform/backend/backend/blocks/search.py
@@ -36,10 +36,10 @@ class GetWikipediaSummaryBlock(Block, GetRequest):
test_mock={"get_request": lambda url, json: {"extract": "summary content"}},
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
topic = input_data.topic
url = f"https://en.wikipedia.org/api/rest_v1/page/summary/{topic}"
- response = self.get_request(url, json=True)
+ response = await self.get_request(url, json=True)
if "extract" not in response:
raise RuntimeError(f"Unable to parse Wikipedia response: {response}")
yield "summary", response["extract"]
@@ -113,14 +113,14 @@ class GetWeatherInformationBlock(Block, GetRequest):
test_credentials=TEST_CREDENTIALS,
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
units = "metric" if input_data.use_celsius else "imperial"
api_key = credentials.api_key
location = input_data.location
url = f"http://api.openweathermap.org/data/2.5/weather?q={quote(location)}&appid={api_key}&units={units}"
- weather_data = self.get_request(url, json=True)
+ weather_data = await self.get_request(url, json=True)
if "main" in weather_data and "weather" in weather_data:
yield "temperature", str(weather_data["main"]["temp"])
diff --git a/autogpt_platform/backend/backend/blocks/slant3d/base.py b/autogpt_platform/backend/backend/blocks/slant3d/base.py
index d5d1681e1d..e368a1b451 100644
--- a/autogpt_platform/backend/backend/blocks/slant3d/base.py
+++ b/autogpt_platform/backend/backend/blocks/slant3d/base.py
@@ -1,7 +1,7 @@
from typing import Any, Dict
from backend.data.block import Block
-from backend.util.request import requests
+from backend.util.request import Requests
from ._api import Color, CustomerDetails, OrderItem, Profile
@@ -14,20 +14,25 @@ class Slant3DBlockBase(Block):
def _get_headers(self, api_key: str) -> Dict[str, str]:
return {"api-key": api_key, "Content-Type": "application/json"}
- def _make_request(self, method: str, endpoint: str, api_key: str, **kwargs) -> Dict:
+ async def _make_request(
+ self, method: str, endpoint: str, api_key: str, **kwargs
+ ) -> Dict:
url = f"{self.BASE_URL}/{endpoint}"
- response = requests.request(
+ response = await Requests().request(
method=method, url=url, headers=self._get_headers(api_key), **kwargs
)
+ resp = response.json()
if not response.ok:
- error_msg = response.json().get("error", "Unknown error")
+ error_msg = resp.get("error", "Unknown error")
raise RuntimeError(f"API request failed: {error_msg}")
- return response.json()
+ return resp
- def _check_valid_color(self, profile: Profile, color: Color, api_key: str) -> str:
- response = self._make_request(
+ async def _check_valid_color(
+ self, profile: Profile, color: Color, api_key: str
+ ) -> str:
+ response = await self._make_request(
"GET",
"filament",
api_key,
@@ -48,10 +53,12 @@ Valid colors for {profile.value} are:
)
return color_tag
- def _convert_to_color(self, profile: Profile, color: Color, api_key: str) -> str:
- return self._check_valid_color(profile, color, api_key)
+ async def _convert_to_color(
+ self, profile: Profile, color: Color, api_key: str
+ ) -> str:
+ return await self._check_valid_color(profile, color, api_key)
- def _format_order_data(
+ async def _format_order_data(
self,
customer: CustomerDetails,
order_number: str,
@@ -61,6 +68,7 @@ Valid colors for {profile.value} are:
"""Helper function to format order data for API requests"""
orders = []
for item in items:
+ color_tag = await self._convert_to_color(item.profile, item.color, api_key)
order_data = {
"email": customer.email,
"phone": customer.phone,
@@ -85,9 +93,7 @@ Valid colors for {profile.value} are:
"order_quantity": item.quantity,
"order_image_url": "",
"order_sku": "NOT_USED",
- "order_item_color": self._convert_to_color(
- item.profile, item.color, api_key
- ),
+ "order_item_color": color_tag,
"profile": item.profile.value,
}
orders.append(order_data)
diff --git a/autogpt_platform/backend/backend/blocks/slant3d/filament.py b/autogpt_platform/backend/backend/blocks/slant3d/filament.py
index c232c2ba8d..0659a45561 100644
--- a/autogpt_platform/backend/backend/blocks/slant3d/filament.py
+++ b/autogpt_platform/backend/backend/blocks/slant3d/filament.py
@@ -72,11 +72,11 @@ class Slant3DFilamentBlock(Slant3DBlockBase):
},
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
try:
- result = self._make_request(
+ result = await self._make_request(
"GET", "filament", credentials.api_key.get_secret_value()
)
yield "filaments", result["filaments"]
diff --git a/autogpt_platform/backend/backend/blocks/slant3d/order.py b/autogpt_platform/backend/backend/blocks/slant3d/order.py
index a1a342a98e..f1cab18d27 100644
--- a/autogpt_platform/backend/backend/blocks/slant3d/order.py
+++ b/autogpt_platform/backend/backend/blocks/slant3d/order.py
@@ -1,8 +1,6 @@
import uuid
from typing import List
-import requests as baserequests
-
from backend.data.block import BlockOutput, BlockSchema
from backend.data.model import APIKeyCredentials, SchemaField
from backend.util import settings
@@ -76,17 +74,17 @@ class Slant3DCreateOrderBlock(Slant3DBlockBase):
},
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
try:
- order_data = self._format_order_data(
+ order_data = await self._format_order_data(
input_data.customer,
input_data.order_number,
input_data.items,
credentials.api_key.get_secret_value(),
)
- result = self._make_request(
+ result = await self._make_request(
"POST", "order", credentials.api_key.get_secret_value(), json=order_data
)
yield "order_id", result["orderId"]
@@ -162,28 +160,24 @@ class Slant3DEstimateOrderBlock(Slant3DBlockBase):
},
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
- order_data = self._format_order_data(
+ order_data = await self._format_order_data(
input_data.customer,
input_data.order_number,
input_data.items,
credentials.api_key.get_secret_value(),
)
- try:
- result = self._make_request(
- "POST",
- "order/estimate",
- credentials.api_key.get_secret_value(),
- json=order_data,
- )
- yield "total_price", result["totalPrice"]
- yield "shipping_cost", result["shippingCost"]
- yield "printing_cost", result["printingCost"]
- except baserequests.HTTPError as e:
- yield "error", str(f"Error estimating order: {e} {e.response.text}")
- raise
+ result = await self._make_request(
+ "POST",
+ "order/estimate",
+ credentials.api_key.get_secret_value(),
+ json=order_data,
+ )
+ yield "total_price", result["totalPrice"]
+ yield "shipping_cost", result["shippingCost"]
+ yield "printing_cost", result["printingCost"]
class Slant3DEstimateShippingBlock(Slant3DBlockBase):
@@ -246,17 +240,17 @@ class Slant3DEstimateShippingBlock(Slant3DBlockBase):
},
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
try:
- order_data = self._format_order_data(
+ order_data = await self._format_order_data(
input_data.customer,
input_data.order_number,
input_data.items,
credentials.api_key.get_secret_value(),
)
- result = self._make_request(
+ result = await self._make_request(
"POST",
"order/estimateShipping",
credentials.api_key.get_secret_value(),
@@ -312,11 +306,11 @@ class Slant3DGetOrdersBlock(Slant3DBlockBase):
},
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
try:
- result = self._make_request(
+ result = await self._make_request(
"GET", "order", credentials.api_key.get_secret_value()
)
yield "orders", [str(order["orderId"]) for order in result["ordersData"]]
@@ -359,11 +353,11 @@ class Slant3DTrackingBlock(Slant3DBlockBase):
},
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
try:
- result = self._make_request(
+ result = await self._make_request(
"GET",
f"order/{input_data.order_id}/get-tracking",
credentials.api_key.get_secret_value(),
@@ -403,11 +397,11 @@ class Slant3DCancelOrderBlock(Slant3DBlockBase):
},
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
try:
- result = self._make_request(
+ result = await self._make_request(
"DELETE",
f"order/{input_data.order_id}",
credentials.api_key.get_secret_value(),
diff --git a/autogpt_platform/backend/backend/blocks/slant3d/slicing.py b/autogpt_platform/backend/backend/blocks/slant3d/slicing.py
index 1b868efc9e..6abe3045ac 100644
--- a/autogpt_platform/backend/backend/blocks/slant3d/slicing.py
+++ b/autogpt_platform/backend/backend/blocks/slant3d/slicing.py
@@ -44,11 +44,11 @@ class Slant3DSlicerBlock(Slant3DBlockBase):
},
)
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
try:
- result = self._make_request(
+ result = await self._make_request(
"POST",
"slicer",
credentials.api_key.get_secret_value(),
diff --git a/autogpt_platform/backend/backend/blocks/slant3d/webhook.py b/autogpt_platform/backend/backend/blocks/slant3d/webhook.py
index 866a1c9afe..8a690cf1ad 100644
--- a/autogpt_platform/backend/backend/blocks/slant3d/webhook.py
+++ b/autogpt_platform/backend/backend/blocks/slant3d/webhook.py
@@ -37,7 +37,7 @@ class Slant3DTriggerBase:
description="Error message if payload processing failed"
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
yield "payload", input_data.payload
yield "order_id", input_data.payload["orderId"]
@@ -117,8 +117,9 @@ class Slant3DOrderWebhookBlock(Slant3DTriggerBase, Block):
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput: # type: ignore
- yield from super().run(input_data, **kwargs)
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput: # type: ignore
+ async for name, value in super().run(input_data, **kwargs):
+ yield name, value
# Extract and normalize values from the payload
yield "status", input_data.payload["status"]
diff --git a/autogpt_platform/backend/backend/blocks/smart_decision_maker.py b/autogpt_platform/backend/backend/blocks/smart_decision_maker.py
index dc45cf0fbb..2fe43af806 100644
--- a/autogpt_platform/backend/backend/blocks/smart_decision_maker.py
+++ b/autogpt_platform/backend/backend/blocks/smart_decision_maker.py
@@ -142,6 +142,12 @@ class SmartDecisionMakerBlock(Block):
advanced=False,
)
credentials: llm.AICredentials = llm.AICredentialsField()
+ multiple_tool_calls: bool = SchemaField(
+ title="Multiple Tool Calls",
+ default=False,
+ description="Whether to allow multiple tool calls in a single response.",
+ advanced=True,
+ )
sys_prompt: str = SchemaField(
title="System Prompt",
default="Thinking carefully step by step decide which function to call. "
@@ -150,7 +156,7 @@ class SmartDecisionMakerBlock(Block):
"matching the required jsonschema signature, no missing argument is allowed. "
"If you have already completed the task objective, you can end the task "
"by providing the end result of your work as a finish message. "
- "Only provide EXACTLY one function call, multiple tool calls is strictly prohibited.",
+ "Function parameters that has no default value and not optional typed has to be provided. ",
description="The system prompt to provide additional context to the model.",
)
conversation_history: list[dict] = SchemaField(
@@ -273,29 +279,18 @@ class SmartDecisionMakerBlock(Block):
"name": SmartDecisionMakerBlock.cleanup(block.name),
"description": block.description,
}
-
+ sink_block_input_schema = block.input_schema
properties = {}
- required = []
for link in links:
- sink_block_input_schema = block.input_schema
- description = (
- sink_block_input_schema.model_fields[link.sink_name].description
- if link.sink_name in sink_block_input_schema.model_fields
- and sink_block_input_schema.model_fields[link.sink_name].description
- else f"The {link.sink_name} of the tool"
+ sink_name = SmartDecisionMakerBlock.cleanup(link.sink_name)
+ properties[sink_name] = sink_block_input_schema.get_field_schema(
+ link.sink_name
)
- properties[SmartDecisionMakerBlock.cleanup(link.sink_name)] = {
- "type": "string",
- "description": description,
- }
tool_function["parameters"] = {
- "type": "object",
+ **block.input_schema.jsonschema(),
"properties": properties,
- "required": required,
- "additionalProperties": False,
- "strict": True,
}
return {"type": "function", "function": tool_function}
@@ -335,25 +330,27 @@ class SmartDecisionMakerBlock(Block):
}
properties = {}
- required = []
for link in links:
sink_block_input_schema = sink_node.input_default["input_schema"]
+ sink_block_properties = sink_block_input_schema.get("properties", {}).get(
+ link.sink_name, {}
+ )
+ sink_name = SmartDecisionMakerBlock.cleanup(link.sink_name)
description = (
- sink_block_input_schema["properties"][link.sink_name]["description"]
- if "description"
- in sink_block_input_schema["properties"][link.sink_name]
+ sink_block_properties["description"]
+ if "description" in sink_block_properties
else f"The {link.sink_name} of the tool"
)
- properties[SmartDecisionMakerBlock.cleanup(link.sink_name)] = {
+ properties[sink_name] = {
"type": "string",
"description": description,
+ "default": json.dumps(sink_block_properties.get("default", None)),
}
tool_function["parameters"] = {
"type": "object",
"properties": properties,
- "required": required,
"additionalProperties": False,
"strict": True,
}
@@ -417,7 +414,7 @@ class SmartDecisionMakerBlock(Block):
return return_tool_functions
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -430,6 +427,7 @@ class SmartDecisionMakerBlock(Block):
**kwargs,
) -> BlockOutput:
tool_functions = self._create_function_signature(node_id)
+ yield "tool_functions", json.dumps(tool_functions)
input_data.conversation_history = input_data.conversation_history or []
prompt = [json.to_dict(p) for p in input_data.conversation_history if p]
@@ -469,6 +467,10 @@ class SmartDecisionMakerBlock(Block):
)
prompt.extend(tool_output)
+ if input_data.multiple_tool_calls:
+ input_data.sys_prompt += "\nYou can call a tool (different tools) multiple times in a single response."
+ else:
+ input_data.sys_prompt += "\nOnly provide EXACTLY one function call, multiple tool calls is strictly prohibited."
values = input_data.prompt_values
if values:
@@ -487,7 +489,7 @@ class SmartDecisionMakerBlock(Block):
):
prompt.append({"role": "user", "content": prefix + input_data.prompt})
- response = llm.llm_call(
+ response = await llm.llm_call(
credentials=credentials,
llm_model=input_data.model,
prompt=prompt,
@@ -495,7 +497,7 @@ class SmartDecisionMakerBlock(Block):
max_tokens=input_data.max_tokens,
tools=tool_functions,
ollama_host=input_data.ollama_host,
- parallel_tool_calls=False,
+ parallel_tool_calls=True if input_data.multiple_tool_calls else None,
)
if not response.tool_calls:
@@ -506,8 +508,31 @@ class SmartDecisionMakerBlock(Block):
tool_name = tool_call.function.name
tool_args = json.loads(tool_call.function.arguments)
- for arg_name, arg_value in tool_args.items():
- yield f"tools_^_{tool_name}_~_{arg_name}", arg_value
+ # Find the tool definition to get the expected arguments
+ tool_def = next(
+ (
+ tool
+ for tool in tool_functions
+ if tool["function"]["name"] == tool_name
+ ),
+ None,
+ )
+
+ if (
+ tool_def
+ and "function" in tool_def
+ and "parameters" in tool_def["function"]
+ ):
+ expected_args = tool_def["function"]["parameters"].get("properties", {})
+ else:
+ expected_args = tool_args.keys()
+
+ # Yield provided arguments and None for missing ones
+ for arg_name in expected_args:
+ if arg_name in tool_args:
+ yield f"tools_^_{tool_name}_~_{arg_name}", tool_args[arg_name]
+ else:
+ yield f"tools_^_{tool_name}_~_{arg_name}", None
response.prompt.append(response.raw_response)
yield "conversations", response.prompt
diff --git a/autogpt_platform/backend/backend/blocks/smartlead/_api.py b/autogpt_platform/backend/backend/blocks/smartlead/_api.py
index 8caa266c2c..cff1c63b72 100644
--- a/autogpt_platform/backend/backend/blocks/smartlead/_api.py
+++ b/autogpt_platform/backend/backend/blocks/smartlead/_api.py
@@ -27,9 +27,11 @@ class SmartLeadClient:
def _handle_error(self, e: Exception) -> str:
return e.__str__().replace(self.api_key, "API KEY")
- def create_campaign(self, request: CreateCampaignRequest) -> CreateCampaignResponse:
+ async def create_campaign(
+ self, request: CreateCampaignRequest
+ ) -> CreateCampaignResponse:
try:
- response = self.requests.post(
+ response = await self.requests.post(
self._add_auth_to_url(f"{self.API_URL}/campaigns/create"),
json=request.model_dump(),
)
@@ -40,11 +42,11 @@ class SmartLeadClient:
except Exception as e:
raise ValueError(f"Failed to create campaign: {self._handle_error(e)}")
- def add_leads_to_campaign(
+ async def add_leads_to_campaign(
self, request: AddLeadsRequest
) -> AddLeadsToCampaignResponse:
try:
- response = self.requests.post(
+ response = await self.requests.post(
self._add_auth_to_url(
f"{self.API_URL}/campaigns/{request.campaign_id}/leads"
),
@@ -64,7 +66,7 @@ class SmartLeadClient:
f"Failed to add leads to campaign: {self._handle_error(e)}"
)
- def save_campaign_sequences(
+ async def save_campaign_sequences(
self, campaign_id: int, request: SaveSequencesRequest
) -> SaveSequencesResponse:
"""
@@ -84,13 +86,13 @@ class SmartLeadClient:
- MANUAL_PERCENTAGE: Requires variant_distribution_percentage in seq_variants
"""
try:
- response = self.requests.post(
+ response = await self.requests.post(
self._add_auth_to_url(
f"{self.API_URL}/campaigns/{campaign_id}/sequences"
),
json=request.model_dump(exclude_none=True),
)
- return SaveSequencesResponse(**response.json())
+ return SaveSequencesResponse(**(response.json()))
except Exception as e:
raise ValueError(
f"Failed to save campaign sequences: {e.__str__().replace(self.api_key, 'API KEY')}"
diff --git a/autogpt_platform/backend/backend/blocks/smartlead/campaign.py b/autogpt_platform/backend/backend/blocks/smartlead/campaign.py
index 3b4ef95749..0e6c72416b 100644
--- a/autogpt_platform/backend/backend/blocks/smartlead/campaign.py
+++ b/autogpt_platform/backend/backend/blocks/smartlead/campaign.py
@@ -80,20 +80,20 @@ class CreateCampaignBlock(Block):
)
@staticmethod
- def create_campaign(
+ async def create_campaign(
name: str, credentials: SmartLeadCredentials
) -> CreateCampaignResponse:
client = SmartLeadClient(credentials.api_key.get_secret_value())
- return client.create_campaign(CreateCampaignRequest(name=name))
+ return await client.create_campaign(CreateCampaignRequest(name=name))
- def run(
+ async def run(
self,
input_data: Input,
*,
credentials: SmartLeadCredentials,
**kwargs,
) -> BlockOutput:
- response = self.create_campaign(input_data.name, credentials)
+ response = await self.create_campaign(input_data.name, credentials)
yield "id", response.id
yield "name", response.name
@@ -193,11 +193,11 @@ class AddLeadToCampaignBlock(Block):
)
@staticmethod
- def add_leads_to_campaign(
+ async def add_leads_to_campaign(
campaign_id: int, lead_list: list[LeadInput], credentials: SmartLeadCredentials
) -> AddLeadsToCampaignResponse:
client = SmartLeadClient(credentials.api_key.get_secret_value())
- return client.add_leads_to_campaign(
+ return await client.add_leads_to_campaign(
AddLeadsRequest(
campaign_id=campaign_id,
lead_list=lead_list,
@@ -210,14 +210,14 @@ class AddLeadToCampaignBlock(Block):
),
)
- def run(
+ async def run(
self,
input_data: Input,
*,
credentials: SmartLeadCredentials,
**kwargs,
) -> BlockOutput:
- response = self.add_leads_to_campaign(
+ response = await self.add_leads_to_campaign(
input_data.campaign_id, input_data.lead_list, credentials
)
@@ -297,22 +297,22 @@ class SaveCampaignSequencesBlock(Block):
)
@staticmethod
- def save_campaign_sequences(
+ async def save_campaign_sequences(
campaign_id: int, sequences: list[Sequence], credentials: SmartLeadCredentials
) -> SaveSequencesResponse:
client = SmartLeadClient(credentials.api_key.get_secret_value())
- return client.save_campaign_sequences(
+ return await client.save_campaign_sequences(
campaign_id=campaign_id, request=SaveSequencesRequest(sequences=sequences)
)
- def run(
+ async def run(
self,
input_data: Input,
*,
credentials: SmartLeadCredentials,
**kwargs,
) -> BlockOutput:
- response = self.save_campaign_sequences(
+ response = await self.save_campaign_sequences(
input_data.campaign_id, input_data.sequences, credentials
)
diff --git a/autogpt_platform/backend/backend/blocks/talking_head.py b/autogpt_platform/backend/backend/blocks/talking_head.py
index b57a9b0da6..3861cb7752 100644
--- a/autogpt_platform/backend/backend/blocks/talking_head.py
+++ b/autogpt_platform/backend/backend/blocks/talking_head.py
@@ -1,4 +1,4 @@
-import time
+import asyncio
from typing import Literal
from pydantic import SecretStr
@@ -11,7 +11,7 @@ from backend.data.model import (
SchemaField,
)
from backend.integrations.providers import ProviderName
-from backend.util.request import requests
+from backend.util.request import Requests
TEST_CREDENTIALS = APIKeyCredentials(
id="01234567-89ab-cdef-0123-456789abcdef",
@@ -113,26 +113,26 @@ class CreateTalkingAvatarVideoBlock(Block):
test_credentials=TEST_CREDENTIALS,
)
- def create_clip(self, api_key: SecretStr, payload: dict) -> dict:
+ async def create_clip(self, api_key: SecretStr, payload: dict) -> dict:
url = "https://api.d-id.com/clips"
headers = {
"accept": "application/json",
"content-type": "application/json",
"authorization": f"Basic {api_key.get_secret_value()}",
}
- response = requests.post(url, json=payload, headers=headers)
+ response = await Requests().post(url, json=payload, headers=headers)
return response.json()
- def get_clip_status(self, api_key: SecretStr, clip_id: str) -> dict:
+ async def get_clip_status(self, api_key: SecretStr, clip_id: str) -> dict:
url = f"https://api.d-id.com/clips/{clip_id}"
headers = {
"accept": "application/json",
"authorization": f"Basic {api_key.get_secret_value()}",
}
- response = requests.get(url, headers=headers)
+ response = await Requests().get(url, headers=headers)
return response.json()
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
# Create the clip
@@ -153,12 +153,12 @@ class CreateTalkingAvatarVideoBlock(Block):
"driver_id": input_data.driver_id,
}
- response = self.create_clip(credentials.api_key, payload)
+ response = await self.create_clip(credentials.api_key, payload)
clip_id = response["id"]
# Poll for clip status
for _ in range(input_data.max_polling_attempts):
- status_response = self.get_clip_status(credentials.api_key, clip_id)
+ status_response = await self.get_clip_status(credentials.api_key, clip_id)
if status_response["status"] == "done":
yield "video_url", status_response["result_url"]
return
@@ -167,6 +167,6 @@ class CreateTalkingAvatarVideoBlock(Block):
f"Clip creation failed: {status_response.get('error', 'Unknown error')}"
)
- time.sleep(input_data.polling_interval)
+ await asyncio.sleep(input_data.polling_interval)
raise TimeoutError("Clip creation timed out")
diff --git a/autogpt_platform/backend/backend/blocks/text.py b/autogpt_platform/backend/backend/blocks/text.py
index 21351bbbd6..f4357a468c 100644
--- a/autogpt_platform/backend/backend/blocks/text.py
+++ b/autogpt_platform/backend/backend/blocks/text.py
@@ -43,7 +43,7 @@ class MatchTextPatternBlock(Block):
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
output = input_data.data or input_data.text
flags = 0
if not input_data.case_sensitive:
@@ -133,7 +133,7 @@ class ExtractTextInformationBlock(Block):
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
flags = 0
if not input_data.case_sensitive:
flags = flags | re.IGNORECASE
@@ -201,7 +201,7 @@ class FillTextTemplateBlock(Block):
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
yield "output", formatter.format_string(input_data.format, input_data.values)
@@ -232,7 +232,7 @@ class CombineTextsBlock(Block):
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
combined_text = input_data.delimiter.join(input_data.input)
yield "output", combined_text
@@ -267,7 +267,7 @@ class TextSplitBlock(Block):
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
if len(input_data.text) == 0:
yield "texts", []
else:
@@ -301,5 +301,5 @@ class TextReplaceBlock(Block):
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
yield "output", input_data.text.replace(input_data.old, input_data.new)
diff --git a/autogpt_platform/backend/backend/blocks/text_to_speech_block.py b/autogpt_platform/backend/backend/blocks/text_to_speech_block.py
index dbaef7c9bb..1599e2e26f 100644
--- a/autogpt_platform/backend/backend/blocks/text_to_speech_block.py
+++ b/autogpt_platform/backend/backend/blocks/text_to_speech_block.py
@@ -10,7 +10,7 @@ from backend.data.model import (
SchemaField,
)
from backend.integrations.providers import ProviderName
-from backend.util.request import requests
+from backend.util.request import Requests
TEST_CREDENTIALS = APIKeyCredentials(
id="01234567-89ab-cdef-0123-456789abcdef",
@@ -71,7 +71,7 @@ class UnrealTextToSpeechBlock(Block):
)
@staticmethod
- def call_unreal_speech_api(
+ async def call_unreal_speech_api(
api_key: SecretStr, text: str, voice_id: str
) -> dict[str, Any]:
url = "https://api.v8.unrealspeech.com/speech"
@@ -88,13 +88,13 @@ class UnrealTextToSpeechBlock(Block):
"TimestampType": "sentence",
}
- response = requests.post(url, headers=headers, json=data)
+ response = await Requests().post(url, headers=headers, json=data)
return response.json()
- def run(
+ async def run(
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs
) -> BlockOutput:
- api_response = self.call_unreal_speech_api(
+ api_response = await self.call_unreal_speech_api(
credentials.api_key,
input_data.text,
input_data.voice_id,
diff --git a/autogpt_platform/backend/backend/blocks/time_blocks.py b/autogpt_platform/backend/backend/blocks/time_blocks.py
index adeeb3bee0..05d8e3699f 100644
--- a/autogpt_platform/backend/backend/blocks/time_blocks.py
+++ b/autogpt_platform/backend/backend/blocks/time_blocks.py
@@ -1,3 +1,4 @@
+import asyncio
import time
from datetime import datetime, timedelta
from typing import Any, Union
@@ -37,7 +38,7 @@ class GetCurrentTimeBlock(Block):
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
current_time = time.strftime(input_data.format)
yield "time", current_time
@@ -87,7 +88,7 @@ class GetCurrentDateBlock(Block):
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
try:
offset = int(input_data.offset)
except ValueError:
@@ -132,7 +133,7 @@ class GetCurrentDateAndTimeBlock(Block):
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
current_date_time = time.strftime(input_data.format)
yield "date_time", current_date_time
@@ -183,7 +184,7 @@ class CountdownTimerBlock(Block):
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
seconds = int(input_data.seconds)
minutes = int(input_data.minutes)
hours = int(input_data.hours)
@@ -192,5 +193,6 @@ class CountdownTimerBlock(Block):
total_seconds = seconds + minutes * 60 + hours * 3600 + days * 86400
for _ in range(input_data.repeat):
- time.sleep(total_seconds)
+ if total_seconds > 0:
+ await asyncio.sleep(total_seconds)
yield "output_message", input_data.input_message
diff --git a/autogpt_platform/backend/backend/blocks/todoist/comments.py b/autogpt_platform/backend/backend/blocks/todoist/comments.py
index 210aa504b3..703afb696f 100644
--- a/autogpt_platform/backend/backend/blocks/todoist/comments.py
+++ b/autogpt_platform/backend/backend/blocks/todoist/comments.py
@@ -108,7 +108,7 @@ class TodoistCreateCommentBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -215,7 +215,7 @@ class TodoistGetCommentsBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -307,7 +307,7 @@ class TodoistGetCommentBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -371,7 +371,7 @@ class TodoistUpdateCommentBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -429,7 +429,7 @@ class TodoistDeleteCommentBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/blocks/todoist/labels.py b/autogpt_platform/backend/backend/blocks/todoist/labels.py
index fc1c381a42..4700ebb6c0 100644
--- a/autogpt_platform/backend/backend/blocks/todoist/labels.py
+++ b/autogpt_platform/backend/backend/blocks/todoist/labels.py
@@ -80,7 +80,7 @@ class TodoistCreateLabelBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -174,7 +174,7 @@ class TodoistListLabelsBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -248,7 +248,7 @@ class TodoistGetLabelBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -321,7 +321,7 @@ class TodoistUpdateLabelBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -389,7 +389,7 @@ class TodoistDeleteLabelBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -444,7 +444,7 @@ class TodoistGetSharedLabelsBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -499,7 +499,7 @@ class TodoistRenameSharedLabelsBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -551,7 +551,7 @@ class TodoistRemoveSharedLabelsBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/blocks/todoist/projects.py b/autogpt_platform/backend/backend/blocks/todoist/projects.py
index 6955e0c136..33ad7950fa 100644
--- a/autogpt_platform/backend/backend/blocks/todoist/projects.py
+++ b/autogpt_platform/backend/backend/blocks/todoist/projects.py
@@ -95,7 +95,7 @@ class TodoistListProjectsBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -185,7 +185,7 @@ class TodoistCreateProjectBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -277,7 +277,7 @@ class TodoistGetProjectBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -375,7 +375,7 @@ class TodoistUpdateProjectBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -438,7 +438,7 @@ class TodoistDeleteProjectBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -548,7 +548,7 @@ class TodoistListCollaboratorsBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/blocks/todoist/sections.py b/autogpt_platform/backend/backend/blocks/todoist/sections.py
index fd9273c0c3..764f7e166e 100644
--- a/autogpt_platform/backend/backend/blocks/todoist/sections.py
+++ b/autogpt_platform/backend/backend/blocks/todoist/sections.py
@@ -96,7 +96,7 @@ class TodoistListSectionsBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -166,7 +166,7 @@ class TodoistListSectionsBlock(Block):
# except Exception as e:
# raise e
-# def run(
+# async def run(
# self,
# input_data: Input,
# *,
@@ -238,7 +238,7 @@ class TodoistGetSectionBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -295,7 +295,7 @@ class TodoistDeleteSectionBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/blocks/todoist/tasks.py b/autogpt_platform/backend/backend/blocks/todoist/tasks.py
index 67786efe11..d50124a9ef 100644
--- a/autogpt_platform/backend/backend/blocks/todoist/tasks.py
+++ b/autogpt_platform/backend/backend/blocks/todoist/tasks.py
@@ -130,7 +130,7 @@ class TodoistCreateTaskBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -261,7 +261,7 @@ class TodoistGetTasksBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -345,7 +345,7 @@ class TodoistGetTaskBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -452,7 +452,7 @@ class TodoistUpdateTaskBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -539,7 +539,7 @@ class TodoistCloseTaskBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -592,7 +592,7 @@ class TodoistReopenTaskBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -645,7 +645,7 @@ class TodoistDeleteTaskBlock(Block):
except Exception as e:
raise e
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/blocks/twitter/direct_message/direct_message_lookup.py b/autogpt_platform/backend/backend/blocks/twitter/direct_message/direct_message_lookup.py
index 14aee69379..99c5bcab79 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/direct_message/direct_message_lookup.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/direct_message/direct_message_lookup.py
@@ -162,7 +162,7 @@
# except tweepy.TweepyException:
# raise
-# def run(
+# async def run(
# self,
# input_data: Input,
# *,
diff --git a/autogpt_platform/backend/backend/blocks/twitter/direct_message/manage_direct_message.py b/autogpt_platform/backend/backend/blocks/twitter/direct_message/manage_direct_message.py
index caeb470bf6..19fdb2819f 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/direct_message/manage_direct_message.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/direct_message/manage_direct_message.py
@@ -122,7 +122,7 @@
# print(f"Unexpected error: {str(e)}")
# raise
-# def run(
+# async def run(
# self,
# input_data: Input,
# *,
@@ -239,7 +239,7 @@
# print(f"Unexpected error: {str(e)}")
# raise
-# def run(
+# async def run(
# self,
# input_data: Input,
# *,
diff --git a/autogpt_platform/backend/backend/blocks/twitter/lists/list_follows.py b/autogpt_platform/backend/backend/blocks/twitter/lists/list_follows.py
index 10722ce146..62c6c05f0c 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/lists/list_follows.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/lists/list_follows.py
@@ -68,7 +68,7 @@ class TwitterUnfollowListBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -131,7 +131,7 @@ class TwitterFollowListBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -276,7 +276,7 @@ class TwitterFollowListBlock(Block):
# except tweepy.TweepyException:
# raise
-# def run(
+# async def run(
# self,
# input_data: Input,
# *,
@@ -438,7 +438,7 @@ class TwitterFollowListBlock(Block):
# except tweepy.TweepyException:
# raise
-# def run(
+# async def run(
# self,
# input_data: Input,
# *,
diff --git a/autogpt_platform/backend/backend/blocks/twitter/lists/list_lookup.py b/autogpt_platform/backend/backend/blocks/twitter/lists/list_lookup.py
index 5860b6e165..6dbaf2b23d 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/lists/list_lookup.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/lists/list_lookup.py
@@ -140,7 +140,7 @@ class TwitterGetListBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -312,7 +312,7 @@ class TwitterGetOwnedListsBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/blocks/twitter/lists/list_members.py b/autogpt_platform/backend/backend/blocks/twitter/lists/list_members.py
index 8ad5125c20..9bcd8f15a2 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/lists/list_members.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/lists/list_members.py
@@ -90,7 +90,7 @@ class TwitterRemoveListMemberBlock(Block):
except Exception:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -164,7 +164,7 @@ class TwitterAddListMemberBlock(Block):
except Exception:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -327,7 +327,7 @@ class TwitterGetListMembersBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -493,7 +493,7 @@ class TwitterGetListMembershipsBlock(Block):
except Exception:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/blocks/twitter/lists/list_tweets_lookup.py b/autogpt_platform/backend/backend/blocks/twitter/lists/list_tweets_lookup.py
index 5faa855019..bda25e1d2d 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/lists/list_tweets_lookup.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/lists/list_tweets_lookup.py
@@ -178,7 +178,7 @@ class TwitterGetListTweetsBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/blocks/twitter/lists/manage_lists.py b/autogpt_platform/backend/backend/blocks/twitter/lists/manage_lists.py
index 800b1219c9..2ba8158f9c 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/lists/manage_lists.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/lists/manage_lists.py
@@ -64,7 +64,7 @@ class TwitterDeleteListBlock(Block):
except Exception:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -158,7 +158,7 @@ class TwitterUpdateListBlock(Block):
except Exception:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -263,7 +263,7 @@ class TwitterCreateListBlock(Block):
except Exception:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/blocks/twitter/lists/pinned_lists.py b/autogpt_platform/backend/backend/blocks/twitter/lists/pinned_lists.py
index 7da93b531a..a31d1059f6 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/lists/pinned_lists.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/lists/pinned_lists.py
@@ -76,7 +76,7 @@ class TwitterUnpinListBlock(Block):
except Exception:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -140,7 +140,7 @@ class TwitterPinListBlock(Block):
except Exception:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -257,7 +257,7 @@ class TwitterGetPinnedListsBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/blocks/twitter/spaces/search_spaces.py b/autogpt_platform/backend/backend/blocks/twitter/spaces/search_spaces.py
index 2640d78bf9..77b28fa654 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/spaces/search_spaces.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/spaces/search_spaces.py
@@ -158,7 +158,7 @@ class TwitterSearchSpacesBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/blocks/twitter/spaces/spaces_lookup.py b/autogpt_platform/backend/backend/blocks/twitter/spaces/spaces_lookup.py
index bf1f527970..d4ff5459e4 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/spaces/spaces_lookup.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/spaces/spaces_lookup.py
@@ -186,7 +186,7 @@ class TwitterGetSpacesBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -341,7 +341,7 @@ class TwitterGetSpaceByIdBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -477,7 +477,7 @@ class TwitterGetSpaceBuyersBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -618,7 +618,7 @@ class TwitterGetSpaceTweetsBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/blocks/twitter/tweets/bookmark.py b/autogpt_platform/backend/backend/blocks/twitter/tweets/bookmark.py
index 50add77be8..ec8976fc2f 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/tweets/bookmark.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/tweets/bookmark.py
@@ -85,7 +85,7 @@ class TwitterBookmarkTweetBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -262,7 +262,7 @@ class TwitterGetBookmarkedTweetsBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -362,7 +362,7 @@ class TwitterRemoveBookmarkTweetBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/blocks/twitter/tweets/hide.py b/autogpt_platform/backend/backend/blocks/twitter/tweets/hide.py
index 78ab250c7f..65faa315ae 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/tweets/hide.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/tweets/hide.py
@@ -68,7 +68,7 @@ class TwitterHideReplyBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -140,7 +140,7 @@ class TwitterUnhideReplyBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/blocks/twitter/tweets/like.py b/autogpt_platform/backend/backend/blocks/twitter/tweets/like.py
index 609c1c6bb4..8bbc30e8e9 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/tweets/like.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/tweets/like.py
@@ -90,7 +90,7 @@ class TwitterLikeTweetBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -249,7 +249,7 @@ class TwitterGetLikingUsersBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -467,7 +467,7 @@ class TwitterGetLikedTweetsBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -564,7 +564,7 @@ class TwitterUnlikeTweetBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/blocks/twitter/tweets/manage.py b/autogpt_platform/backend/backend/blocks/twitter/tweets/manage.py
index e9a59afec2..6dca0d74c8 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/tweets/manage.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/tweets/manage.py
@@ -211,7 +211,7 @@ class TwitterPostTweetBlock(Block):
except Exception:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -288,7 +288,7 @@ class TwitterDeleteTweetBlock(Block):
except Exception:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -508,7 +508,7 @@ class TwitterSearchRecentTweetsBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/blocks/twitter/tweets/quote.py b/autogpt_platform/backend/backend/blocks/twitter/tweets/quote.py
index 40df117b1c..b15271b072 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/tweets/quote.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/tweets/quote.py
@@ -186,7 +186,7 @@ class TwitterGetQuoteTweetsBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/blocks/twitter/tweets/retweet.py b/autogpt_platform/backend/backend/blocks/twitter/tweets/retweet.py
index c0645e54fd..9b1ba81b78 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/tweets/retweet.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/tweets/retweet.py
@@ -85,7 +85,7 @@ class TwitterRetweetBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -162,7 +162,7 @@ class TwitterRemoveRetweetBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -328,7 +328,7 @@ class TwitterGetRetweetersBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/blocks/twitter/tweets/timeline.py b/autogpt_platform/backend/backend/blocks/twitter/tweets/timeline.py
index 1dcce6d12a..ca89039c2e 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/tweets/timeline.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/tweets/timeline.py
@@ -234,7 +234,7 @@ class TwitterGetUserMentionsBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -467,7 +467,7 @@ class TwitterGetHomeTimelineBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -713,7 +713,7 @@ class TwitterGetUserTweetsBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/blocks/twitter/tweets/tweet_lookup.py b/autogpt_platform/backend/backend/blocks/twitter/tweets/tweet_lookup.py
index a71eb11b60..5021161b9e 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/tweets/tweet_lookup.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/tweets/tweet_lookup.py
@@ -153,7 +153,7 @@ class TwitterGetTweetBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -327,7 +327,7 @@ class TwitterGetTweetsBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/blocks/twitter/users/blocks.py b/autogpt_platform/backend/backend/blocks/twitter/users/blocks.py
index c83632067a..ca118e91e2 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/users/blocks.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/users/blocks.py
@@ -147,7 +147,7 @@ class TwitterGetBlockedUsersBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/blocks/twitter/users/follows.py b/autogpt_platform/backend/backend/blocks/twitter/users/follows.py
index a810750cbd..160ffe9b35 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/users/follows.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/users/follows.py
@@ -82,7 +82,7 @@ class TwitterUnfollowUserBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -152,7 +152,7 @@ class TwitterFollowUserBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -308,7 +308,7 @@ class TwitterGetFollowersBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -482,7 +482,7 @@ class TwitterGetFollowingBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/blocks/twitter/users/mutes.py b/autogpt_platform/backend/backend/blocks/twitter/users/mutes.py
index 6be5534bee..36bb4028f9 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/users/mutes.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/users/mutes.py
@@ -82,7 +82,7 @@ class TwitterUnmuteUserBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -232,7 +232,7 @@ class TwitterGetMutedUsersBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -318,7 +318,7 @@ class TwitterMuteUserBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/blocks/twitter/users/user_lookup.py b/autogpt_platform/backend/backend/blocks/twitter/users/user_lookup.py
index 7c4bc8322d..585ebff3db 100644
--- a/autogpt_platform/backend/backend/blocks/twitter/users/user_lookup.py
+++ b/autogpt_platform/backend/backend/blocks/twitter/users/user_lookup.py
@@ -168,7 +168,7 @@ class TwitterGetUserBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
@@ -357,7 +357,7 @@ class TwitterGetUsersBlock(Block):
except tweepy.TweepyException:
raise
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/blocks/xml_parser.py b/autogpt_platform/backend/backend/blocks/xml_parser.py
index 523fe1a69d..a3d5854499 100644
--- a/autogpt_platform/backend/backend/blocks/xml_parser.py
+++ b/autogpt_platform/backend/backend/blocks/xml_parser.py
@@ -25,7 +25,7 @@ class XMLParserBlock(Block):
],
)
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
try:
tokens = tokenize(input_data.input_xml)
parser = Parser(tokens)
diff --git a/autogpt_platform/backend/backend/blocks/youtube.py b/autogpt_platform/backend/backend/blocks/youtube.py
index 648d9d6dae..cc16c4ae41 100644
--- a/autogpt_platform/backend/backend/blocks/youtube.py
+++ b/autogpt_platform/backend/backend/blocks/youtube.py
@@ -79,7 +79,7 @@ class TranscribeYoutubeVideoBlock(Block):
except Exception:
raise ValueError(f"No transcripts found for the video: {video_id}")
- def run(self, input_data: Input, **kwargs) -> BlockOutput:
+ async def run(self, input_data: Input, **kwargs) -> BlockOutput:
video_id = self.extract_video_id(input_data.youtube_url)
yield "video_id", video_id
diff --git a/autogpt_platform/backend/backend/blocks/zerobounce/validate_emails.py b/autogpt_platform/backend/backend/blocks/zerobounce/validate_emails.py
index ee87a8f285..b23e822ddc 100644
--- a/autogpt_platform/backend/backend/blocks/zerobounce/validate_emails.py
+++ b/autogpt_platform/backend/backend/blocks/zerobounce/validate_emails.py
@@ -159,7 +159,7 @@ class ValidateEmailsBlock(Block):
client = ZeroBounceClient(credentials.api_key.get_secret_value())
return client.validate_email(email, ip_address)
- def run(
+ async def run(
self,
input_data: Input,
*,
diff --git a/autogpt_platform/backend/backend/cli.py b/autogpt_platform/backend/backend/cli.py
index 87fadb88de..988961b2de 100755
--- a/autogpt_platform/backend/backend/cli.py
+++ b/autogpt_platform/backend/backend/cli.py
@@ -117,20 +117,21 @@ def test():
@test.command()
@click.argument("server_address")
-def reddit(server_address: str):
+async def reddit(server_address: str):
"""
Create an event graph
"""
- import requests
-
from backend.usecases.reddit_marketing import create_test_graph
+ from backend.util.request import Requests
test_graph = create_test_graph()
url = f"{server_address}/graphs"
headers = {"Content-Type": "application/json"}
data = test_graph.model_dump_json()
- response = requests.post(url, headers=headers, data=data)
+ response = await Requests(trusted_origins=[server_address]).post(
+ url, headers=headers, data=data
+ )
graph_id = response.json()["id"]
print(f"Graph created with ID: {graph_id}")
@@ -138,28 +139,32 @@ def reddit(server_address: str):
@test.command()
@click.argument("server_address")
-def populate_db(server_address: str):
+async def populate_db(server_address: str):
"""
Create an event graph
"""
- import requests
from backend.usecases.sample import create_test_graph
+ from backend.util.request import Requests
test_graph = create_test_graph()
url = f"{server_address}/graphs"
headers = {"Content-Type": "application/json"}
data = test_graph.model_dump_json()
- response = requests.post(url, headers=headers, data=data)
+ response = await Requests(trusted_origins=[server_address]).post(
+ url, headers=headers, data=data
+ )
graph_id = response.json()["id"]
- if response.status_code == 200:
+ if response.status == 200:
execute_url = f"{server_address}/graphs/{response.json()['id']}/execute"
text = "Hello, World!"
input_data = {"input": text}
- response = requests.post(execute_url, headers=headers, json=input_data)
+ response = Requests(trusted_origins=[server_address]).post(
+ execute_url, headers=headers, json=input_data
+ )
schedule_url = f"{server_address}/graphs/{graph_id}/schedules"
data = {
@@ -167,51 +172,60 @@ def populate_db(server_address: str):
"cron": "*/5 * * * *",
"input_data": {"input": "Hello, World!"},
}
- response = requests.post(schedule_url, headers=headers, json=data)
+ response = Requests(trusted_origins=[server_address]).post(
+ schedule_url, headers=headers, json=data
+ )
print("Database populated with: \n- graph\n- execution\n- schedule")
@test.command()
@click.argument("server_address")
-def graph(server_address: str):
+async def graph(server_address: str):
"""
Create an event graph
"""
- import requests
from backend.usecases.sample import create_test_graph
+ from backend.util.request import Requests
url = f"{server_address}/graphs"
headers = {"Content-Type": "application/json"}
data = create_test_graph().model_dump_json()
- response = requests.post(url, headers=headers, data=data)
+ response = await Requests(trusted_origins=[server_address]).post(
+ url, headers=headers, data=data
+ )
- if response.status_code == 200:
+ if response.status == 200:
print(response.json()["id"])
execute_url = f"{server_address}/graphs/{response.json()['id']}/execute"
text = "Hello, World!"
input_data = {"input": text}
- response = requests.post(execute_url, headers=headers, json=input_data)
+ response = await Requests(trusted_origins=[server_address]).post(
+ execute_url, headers=headers, json=input_data
+ )
else:
print("Failed to send graph")
- print(f"Response: {response.text}")
+ print(f"Response: {response.text()}")
@test.command()
@click.argument("graph_id")
@click.argument("content")
-def execute(graph_id: str, content: dict):
+async def execute(graph_id: str, content: dict):
"""
Create an event graph
"""
- import requests
+
+ from backend.util.request import Requests
headers = {"Content-Type": "application/json"}
execute_url = f"http://0.0.0.0:8000/graphs/{graph_id}/execute"
- requests.post(execute_url, headers=headers, json=content)
+ await Requests(trusted_origins=["http://0.0.0.0:8000"]).post(
+ execute_url, headers=headers, json=content
+ )
@test.command()
diff --git a/autogpt_platform/backend/backend/data/block.py b/autogpt_platform/backend/backend/data/block.py
index eca44fd7cd..5283997d4c 100644
--- a/autogpt_platform/backend/backend/data/block.py
+++ b/autogpt_platform/backend/backend/data/block.py
@@ -1,12 +1,12 @@
import functools
import inspect
from abc import ABC, abstractmethod
+from collections.abc import AsyncGenerator as AsyncGen
from enum import Enum
from typing import (
TYPE_CHECKING,
Any,
ClassVar,
- Generator,
Generic,
Optional,
Sequence,
@@ -42,7 +42,7 @@ app_config = Config()
BlockData = tuple[str, Any] # Input & Output data should be a tuple of (name, data).
BlockInput = dict[str, Any] # Input: 1 input pin consumes 1 data.
-BlockOutput = Generator[BlockData, None, None] # Output: 1 output pin produces n data.
+BlockOutput = AsyncGen[BlockData, None] # Output: 1 output pin produces n data.
CompletedBlockOutput = dict[str, list[Any]] # Completed stream, collected as a dict.
@@ -118,7 +118,10 @@ class BlockSchema(BaseModel):
@classmethod
def validate_data(cls, data: BlockInput) -> str | None:
- return json.validate_with_jsonschema(schema=cls.jsonschema(), data=data)
+ return json.validate_with_jsonschema(
+ schema=cls.jsonschema(),
+ data={k: v for k, v in data.items() if v is not None},
+ )
@classmethod
def get_mismatch_error(cls, data: BlockInput) -> str | None:
@@ -388,7 +391,7 @@ class Block(ABC, Generic[BlockSchemaInputType, BlockSchemaOutputType]):
return cls()
@abstractmethod
- def run(self, input_data: BlockSchemaInputType, **kwargs) -> BlockOutput:
+ async def run(self, input_data: BlockSchemaInputType, **kwargs) -> BlockOutput:
"""
Run the block with the given input data.
Args:
@@ -406,10 +409,16 @@ class Block(ABC, Generic[BlockSchemaInputType, BlockSchemaOutputType]):
output_name: One of the output name defined in Block's output_schema.
output_data: The data for the output_name, matching the defined schema.
"""
- pass
+ # --- satisfy the type checker, never executed -------------
+ if False: # noqa: SIM115
+ yield "name", "value" # pyright: ignore[reportMissingYield]
+ raise NotImplementedError(f"{self.name} does not implement the run method.")
- def run_once(self, input_data: BlockSchemaInputType, output: str, **kwargs) -> Any:
- for name, data in self.run(input_data, **kwargs):
+ async def run_once(
+ self, input_data: BlockSchemaInputType, output: str, **kwargs
+ ) -> Any:
+ async for item in self.run(input_data, **kwargs):
+ name, data = item
if name == output:
return data
raise ValueError(f"{self.name} did not produce any output for {output}")
@@ -458,14 +467,15 @@ class Block(ABC, Generic[BlockSchemaInputType, BlockSchemaOutputType]):
"uiType": self.block_type.value,
}
- def execute(self, input_data: BlockInput, **kwargs) -> BlockOutput:
+ async def execute(self, input_data: BlockInput, **kwargs) -> BlockOutput:
if error := self.input_schema.validate_data(input_data):
raise ValueError(
f"Unable to execute block with invalid input data: {error}"
)
- for output_name, output_data in self.run(
- self.input_schema(**input_data), **kwargs
+ 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,
):
if output_name == "error":
raise RuntimeError(output_data)
diff --git a/autogpt_platform/backend/backend/data/block_cost_config.py b/autogpt_platform/backend/backend/data/block_cost_config.py
index 864ed0e989..730512e4ea 100644
--- a/autogpt_platform/backend/backend/data/block_cost_config.py
+++ b/autogpt_platform/backend/backend/data/block_cost_config.py
@@ -2,6 +2,8 @@ from typing import Type
from backend.blocks.ai_music_generator import AIMusicGeneratorBlock
from backend.blocks.ai_shortform_video_block import AIShortformVideoCreatorBlock
+from backend.blocks.apollo.organization import SearchOrganizationsBlock
+from backend.blocks.apollo.people import SearchPeopleBlock
from backend.blocks.flux_kontext import AIImageEditorBlock, FluxKontextModelName
from backend.blocks.ideogram import IdeogramModelBlock
from backend.blocks.jina.embeddings import JinaEmbeddingBlock
@@ -24,6 +26,7 @@ from backend.data.cost import BlockCost, BlockCostType
from backend.integrations.credentials_store import (
aiml_api_credentials,
anthropic_credentials,
+ apollo_credentials,
did_credentials,
groq_credentials,
ideogram_credentials,
@@ -345,4 +348,28 @@ BLOCK_COSTS: dict[Type[Block], list[BlockCost]] = {
)
],
SmartDecisionMakerBlock: LLM_COST,
+ SearchOrganizationsBlock: [
+ BlockCost(
+ cost_amount=2,
+ cost_filter={
+ "credentials": {
+ "id": apollo_credentials.id,
+ "provider": apollo_credentials.provider,
+ "type": apollo_credentials.type,
+ }
+ },
+ )
+ ],
+ SearchPeopleBlock: [
+ BlockCost(
+ cost_amount=2,
+ cost_filter={
+ "credentials": {
+ "id": apollo_credentials.id,
+ "provider": apollo_credentials.provider,
+ "type": apollo_credentials.type,
+ }
+ },
+ )
+ ],
}
diff --git a/autogpt_platform/backend/backend/data/execution.py b/autogpt_platform/backend/backend/data/execution.py
index 757c788f2f..e97bb30452 100644
--- a/autogpt_platform/backend/backend/data/execution.py
+++ b/autogpt_platform/backend/backend/data/execution.py
@@ -50,6 +50,7 @@ from .block import (
from .db import BaseDbModel
from .includes import (
EXECUTION_RESULT_INCLUDE,
+ EXECUTION_RESULT_ORDER,
GRAPH_EXECUTION_INCLUDE_WITH_NODES,
graph_execution_include,
)
@@ -555,18 +556,18 @@ async def upsert_execution_input(
async def upsert_execution_output(
node_exec_id: str,
output_name: str,
- output_data: Any,
+ output_data: Any | None,
) -> None:
"""
Insert AgentNodeExecutionInputOutput record for as one of AgentNodeExecution.Output.
"""
- await AgentNodeExecutionInputOutput.prisma().create(
- data=AgentNodeExecutionInputOutputCreateInput(
- name=output_name,
- data=Json(output_data),
- referencedByOutputExecId=node_exec_id,
- )
+ data = AgentNodeExecutionInputOutputCreateInput(
+ name=output_name,
+ referencedByOutputExecId=node_exec_id,
)
+ if output_data is not None:
+ data["data"] = Json(output_data)
+ await AgentNodeExecutionInputOutput.prisma().create(data=data)
async def update_graph_execution_start_time(
@@ -744,6 +745,7 @@ async def get_node_executions(
executions = await AgentNodeExecution.prisma().find_many(
where=where_clause,
include=EXECUTION_RESULT_INCLUDE,
+ order=EXECUTION_RESULT_ORDER,
take=limit,
)
res = [NodeExecutionResult.from_db(execution) for execution in executions]
@@ -765,11 +767,8 @@ async def get_latest_node_execution(
{"executionStatus": ExecutionStatus.FAILED},
],
},
- order=[
- {"queuedTime": "desc"},
- {"addedTime": "desc"},
- ],
include=EXECUTION_RESULT_INCLUDE,
+ order=EXECUTION_RESULT_ORDER,
)
if not execution:
return None
diff --git a/autogpt_platform/backend/backend/data/graph.py b/autogpt_platform/backend/backend/data/graph.py
index c556ba0450..d3d3ae8a02 100644
--- a/autogpt_platform/backend/backend/data/graph.py
+++ b/autogpt_platform/backend/backend/data/graph.py
@@ -655,7 +655,10 @@ async def get_graphs(
graph_models = []
for graph in graphs:
try:
- graph_models.append(GraphModel.from_db(graph))
+ graph_model = GraphModel.from_db(graph)
+ # Trigger serialization to validate that the graph is well formed.
+ graph_model.model_dump()
+ graph_models.append(graph_model)
except Exception as e:
logger.error(f"Error processing graph {graph.id}: {e}")
continue
@@ -1082,7 +1085,7 @@ async def fix_llm_provider_credentials():
)
continue
- store.update_creds(user_id, credentials)
+ await store.update_creds(user_id, credentials)
await AgentNode.prisma().update(
where={"id": node_id},
data={"constantInput": Json(node_preset_input)},
diff --git a/autogpt_platform/backend/backend/data/includes.py b/autogpt_platform/backend/backend/data/includes.py
index d763579d91..347bb9ef91 100644
--- a/autogpt_platform/backend/backend/data/includes.py
+++ b/autogpt_platform/backend/backend/data/includes.py
@@ -14,9 +14,15 @@ AGENT_GRAPH_INCLUDE: prisma.types.AgentGraphInclude = {
"Nodes": {"include": AGENT_NODE_INCLUDE}
}
+EXECUTION_RESULT_ORDER: list[prisma.types.AgentNodeExecutionOrderByInput] = [
+ {"queuedTime": "desc"},
+ # Fallback: Incomplete execs has no queuedTime.
+ {"addedTime": "desc"},
+]
+
EXECUTION_RESULT_INCLUDE: prisma.types.AgentNodeExecutionInclude = {
- "Input": True,
- "Output": True,
+ "Input": {"order_by": {"time": "asc"}},
+ "Output": {"order_by": {"time": "asc"}},
"Node": True,
"GraphExecution": True,
}
@@ -25,17 +31,8 @@ MAX_NODE_EXECUTIONS_FETCH = 1000
GRAPH_EXECUTION_INCLUDE_WITH_NODES: prisma.types.AgentGraphExecutionInclude = {
"NodeExecutions": {
- "include": {
- "Input": True,
- "Output": True,
- "Node": True,
- "GraphExecution": True,
- },
- "order_by": [
- {"queuedTime": "desc"},
- # Fallback: Incomplete execs has no queuedTime.
- {"addedTime": "desc"},
- ],
+ "include": EXECUTION_RESULT_INCLUDE,
+ "order_by": EXECUTION_RESULT_ORDER,
"take": MAX_NODE_EXECUTIONS_FETCH, # Avoid loading excessive node executions.
}
}
diff --git a/autogpt_platform/backend/backend/data/notifications.py b/autogpt_platform/backend/backend/data/notifications.py
index d0f49b7021..f575081be7 100644
--- a/autogpt_platform/backend/backend/data/notifications.py
+++ b/autogpt_platform/backend/backend/data/notifications.py
@@ -16,10 +16,11 @@ from prisma.types import (
from pydantic import BaseModel, ConfigDict, EmailStr, Field, field_validator
from backend.server.v2.store.exceptions import DatabaseError
+from backend.util.logging import TruncatedLogger
from .db import transaction
-logger = logging.getLogger(__name__)
+logger = TruncatedLogger(logging.getLogger(__name__), prefix="[NotificationService]")
NotificationDataType_co = TypeVar(
@@ -111,7 +112,14 @@ class BaseSummaryData(BaseNotificationData):
class BaseSummaryParams(BaseModel):
- pass
+ start_date: datetime
+ end_date: datetime
+
+ @field_validator("start_date", "end_date")
+ def validate_timezone(cls, value):
+ if value.tzinfo is None:
+ raise ValueError("datetime must have timezone information")
+ return value
class DailySummaryParams(BaseSummaryParams):
diff --git a/autogpt_platform/backend/backend/data/redis.py b/autogpt_platform/backend/backend/data/redis.py
index 36410fe29c..c6225131f2 100644
--- a/autogpt_platform/backend/backend/data/redis.py
+++ b/autogpt_platform/backend/backend/data/redis.py
@@ -1,6 +1,8 @@
import logging
import os
+from functools import cache
+from autogpt_libs.utils.cache import thread_cached
from dotenv import load_dotenv
from redis import Redis
from redis.asyncio import Redis as AsyncRedis
@@ -14,16 +16,10 @@ PORT = int(os.getenv("REDIS_PORT", "6379"))
PASSWORD = os.getenv("REDIS_PASSWORD", "password")
logger = logging.getLogger(__name__)
-connection: Redis | None = None
-connection_async: AsyncRedis | None = None
@conn_retry("Redis", "Acquiring connection")
def connect() -> Redis:
- global connection
- if connection:
- return connection
-
c = Redis(
host=HOST,
port=PORT,
@@ -31,32 +27,21 @@ def connect() -> Redis:
decode_responses=True,
)
c.ping()
- connection = c
- return connection
+ return c
@conn_retry("Redis", "Releasing connection")
def disconnect():
- global connection
- if connection:
- connection.close()
- connection = None
+ get_redis().close()
-def get_redis(auto_connect: bool = True) -> Redis:
- if connection:
- return connection
- if auto_connect:
- return connect()
- raise RuntimeError("Redis connection is not established")
+@cache
+def get_redis() -> Redis:
+ return connect()
@conn_retry("AsyncRedis", "Acquiring connection")
async def connect_async() -> AsyncRedis:
- global connection_async
- if connection_async:
- return connection_async
-
c = AsyncRedis(
host=HOST,
port=PORT,
@@ -64,21 +49,15 @@ async def connect_async() -> AsyncRedis:
decode_responses=True,
)
await c.ping()
- connection_async = c
- return connection_async
+ return c
@conn_retry("AsyncRedis", "Releasing connection")
async def disconnect_async():
- global connection_async
- if connection_async:
- await connection_async.close()
- connection_async = None
+ c = await get_redis_async()
+ await c.close()
-async def get_redis_async(auto_connect: bool = True) -> AsyncRedis:
- if connection_async:
- return connection_async
- if auto_connect:
- return await connect_async()
- raise RuntimeError("AsyncRedis connection is not established")
+@thread_cached
+async def get_redis_async() -> AsyncRedis:
+ return await connect_async()
diff --git a/autogpt_platform/backend/backend/executor/__init__.py b/autogpt_platform/backend/backend/executor/__init__.py
index a92302a62e..92d8b5dc58 100644
--- a/autogpt_platform/backend/backend/executor/__init__.py
+++ b/autogpt_platform/backend/backend/executor/__init__.py
@@ -1,10 +1,11 @@
-from .database import DatabaseManager, DatabaseManagerClient
+from .database import DatabaseManager, DatabaseManagerAsyncClient, DatabaseManagerClient
from .manager import ExecutionManager
from .scheduler import Scheduler
__all__ = [
"DatabaseManager",
"DatabaseManagerClient",
+ "DatabaseManagerAsyncClient",
"ExecutionManager",
"Scheduler",
]
diff --git a/autogpt_platform/backend/backend/executor/database.py b/autogpt_platform/backend/backend/executor/database.py
index e1b4c9c776..81440f3555 100644
--- a/autogpt_platform/backend/backend/executor/database.py
+++ b/autogpt_platform/backend/backend/executor/database.py
@@ -192,3 +192,26 @@ class DatabaseManagerClient(AppServiceClient):
get_user_notification_oldest_message_in_batch = _(
d.get_user_notification_oldest_message_in_batch
)
+
+
+class DatabaseManagerAsyncClient(AppServiceClient):
+ d = DatabaseManager
+
+ @classmethod
+ def get_service_type(cls):
+ return DatabaseManager
+
+ create_graph_execution = d.create_graph_execution
+ get_latest_node_execution = d.get_latest_node_execution
+ get_graph = d.get_graph
+ get_node = d.get_node
+ get_node_execution = d.get_node_execution
+ get_node_executions = d.get_node_executions
+ get_user_integrations = d.get_user_integrations
+ upsert_execution_input = d.upsert_execution_input
+ upsert_execution_output = d.upsert_execution_output
+ update_graph_execution_stats = d.update_graph_execution_stats
+ update_node_execution_stats = d.update_node_execution_stats
+ update_node_execution_status = d.update_node_execution_status
+ update_node_execution_status_batch = d.update_node_execution_status_batch
+ update_user_integrations = d.update_user_integrations
diff --git a/autogpt_platform/backend/backend/executor/manager.py b/autogpt_platform/backend/backend/executor/manager.py
index d4bf006473..1736539230 100644
--- a/autogpt_platform/backend/backend/executor/manager.py
+++ b/autogpt_platform/backend/backend/executor/manager.py
@@ -1,20 +1,18 @@
-import atexit
+import asyncio
import logging
import multiprocessing
import os
-import signal
import sys
import threading
import time
from collections import defaultdict
-from concurrent.futures import Future, ProcessPoolExecutor
-from contextlib import contextmanager
-from multiprocessing.pool import Pool
-from typing import TYPE_CHECKING, Optional, TypeVar, cast
+from concurrent.futures import CancelledError, Future, ProcessPoolExecutor
+from contextlib import asynccontextmanager
+from typing import TYPE_CHECKING, Any, Optional, TypeVar, cast
from pika.adapters.blocking_connection import BlockingChannel
from pika.spec import Basic, BasicProperties
-from redis.lock import Lock as RedisLock
+from redis.asyncio.lock import Lock as RedisLock
from backend.blocks.io import AgentOutputBlock
from backend.data.model import (
@@ -34,7 +32,7 @@ from backend.notifications.notifications import queue_notification
from backend.util.exceptions import InsufficientBalanceError
if TYPE_CHECKING:
- from backend.executor import DatabaseManagerClient
+ from backend.executor import DatabaseManagerClient, DatabaseManagerAsyncClient
from autogpt_libs.utils.cache import thread_cached
from prometheus_client import Gauge, start_http_server
@@ -66,6 +64,7 @@ from backend.executor.utils import (
NodeExecutionProgress,
block_usage_cost,
execution_usage_cost,
+ get_async_execution_event_bus,
get_execution_event_bus,
get_execution_queue,
parse_execution_output,
@@ -73,7 +72,12 @@ from backend.executor.utils import (
)
from backend.integrations.creds_manager import IntegrationCredentialsManager
from backend.util import json
-from backend.util.decorator import error_logged, time_measured
+from backend.util.decorator import (
+ async_error_logged,
+ async_time_measured,
+ error_logged,
+ time_measured,
+)
from backend.util.file import clean_exec_files
from backend.util.logging import TruncatedLogger, configure_logging
from backend.util.process import AppProcess, set_service_name
@@ -81,7 +85,8 @@ from backend.util.retry import continuous_retry, func_retry
from backend.util.service import get_service_client
from backend.util.settings import Settings
-logger = logging.getLogger(__name__)
+_logger = logging.getLogger(__name__)
+logger = TruncatedLogger(_logger, prefix="[GraphExecutor]")
settings = Settings()
active_runs_gauge = Gauge(
@@ -118,7 +123,7 @@ class LogMetadata(TruncatedLogger):
}
prefix = f"[ExecutionManager|uid:{user_id}|gid:{graph_id}|nid:{node_id}]|geid:{graph_eid}|neid:{node_eid}|{block_name}]"
super().__init__(
- logger,
+ _logger,
max_length=max_length,
prefix=prefix,
metadata=metadata,
@@ -128,7 +133,7 @@ class LogMetadata(TruncatedLogger):
T = TypeVar("T")
-def execute_node(
+async def execute_node(
node: Node,
creds_manager: IntegrationCredentialsManager,
data: NodeExecutionEntry,
@@ -205,12 +210,14 @@ def execute_node(
input_model = cast(type[BlockSchema], node_block.input_schema)
for field_name, input_type in input_model.get_credentials_fields().items():
credentials_meta = input_type(**input_data[field_name])
- credentials, creds_lock = creds_manager.acquire(user_id, credentials_meta.id)
+ credentials, creds_lock = await creds_manager.acquire(
+ user_id, credentials_meta.id
+ )
extra_exec_kwargs[field_name] = credentials
output_size = 0
try:
- for output_name, output_data in node_block.execute(
+ async for output_name, output_data in node_block.execute(
input_data, **extra_exec_kwargs
):
output_data = json.convert_pydantic_to_json(output_data)
@@ -225,9 +232,9 @@ def execute_node(
finally:
# Ensure credentials are released even if execution fails
- if creds_lock and creds_lock.locked() and creds_lock.owned():
+ if creds_lock and (await creds_lock.locked()) and (await creds_lock.owned()):
try:
- creds_lock.release()
+ await creds_lock.release()
except Exception as e:
log_metadata.error(f"Failed to release credentials lock: {e}")
@@ -240,8 +247,8 @@ def execute_node(
execution_stats.output_size = output_size
-def _enqueue_next_nodes(
- db_client: "DatabaseManagerClient",
+async def _enqueue_next_nodes(
+ db_client: "DatabaseManagerAsyncClient",
node: Node,
output: BlockData,
user_id: str,
@@ -250,10 +257,10 @@ def _enqueue_next_nodes(
log_metadata: LogMetadata,
node_credentials_input_map: Optional[dict[str, dict[str, CredentialsMetaInput]]],
) -> list[NodeExecutionEntry]:
- def add_enqueued_execution(
+ async def add_enqueued_execution(
node_exec_id: str, node_id: str, block_id: str, data: BlockInput
) -> NodeExecutionEntry:
- update_node_execution_status(
+ await async_update_node_execution_status(
db_client=db_client,
exec_id=node_exec_id,
status=ExecutionStatus.QUEUED,
@@ -269,37 +276,37 @@ def _enqueue_next_nodes(
inputs=data,
)
- def register_next_executions(node_link: Link) -> list[NodeExecutionEntry]:
+ async def register_next_executions(node_link: Link) -> list[NodeExecutionEntry]:
try:
- return _register_next_executions(node_link)
+ return await _register_next_executions(node_link)
except Exception as e:
log_metadata.exception(f"Failed to register next executions: {e}")
return []
- def _register_next_executions(node_link: Link) -> list[NodeExecutionEntry]:
+ async def _register_next_executions(node_link: Link) -> list[NodeExecutionEntry]:
enqueued_executions = []
next_output_name = node_link.source_name
next_input_name = node_link.sink_name
next_node_id = node_link.sink_id
+ output_name, _ = output
next_data = parse_execution_output(output, next_output_name)
- if next_data is None:
+ if next_data is None and output_name != next_output_name:
return enqueued_executions
-
- next_node = db_client.get_node(next_node_id)
+ next_node = await db_client.get_node(next_node_id)
# Multiple node can register the same next node, we need this to be atomic
# To avoid same execution to be enqueued multiple times,
# Or the same input to be consumed multiple times.
- with synchronized(f"upsert_input-{next_node_id}-{graph_exec_id}"):
+ async with synchronized(f"upsert_input-{next_node_id}-{graph_exec_id}"):
# Add output data to the earliest incomplete execution, or create a new one.
- next_node_exec_id, next_node_input = db_client.upsert_execution_input(
+ next_node_exec_id, next_node_input = await db_client.upsert_execution_input(
node_id=next_node_id,
graph_exec_id=graph_exec_id,
input_name=next_input_name,
input_data=next_data,
)
- update_node_execution_status(
+ await async_update_node_execution_status(
db_client=db_client,
exec_id=next_node_exec_id,
status=ExecutionStatus.INCOMPLETE,
@@ -312,7 +319,7 @@ def _enqueue_next_nodes(
if link.is_static and link.sink_name not in next_node_input
}
if static_link_names and (
- latest_execution := db_client.get_latest_node_execution(
+ latest_execution := await db_client.get_latest_node_execution(
next_node_id, graph_exec_id
)
):
@@ -340,7 +347,7 @@ def _enqueue_next_nodes(
# Input is complete, enqueue the execution.
log_metadata.info(f"Enqueued {suffix}")
enqueued_executions.append(
- add_enqueued_execution(
+ await add_enqueued_execution(
node_exec_id=next_node_exec_id,
node_id=next_node_id,
block_id=next_node.block_id,
@@ -354,7 +361,7 @@ def _enqueue_next_nodes(
# If link is static, there could be some incomplete executions waiting for it.
# Load and complete the input missing input data, and try to re-enqueue them.
- for iexec in db_client.get_node_executions(
+ for iexec in await db_client.get_node_executions(
node_id=next_node_id,
graph_exec_id=graph_exec_id,
statuses=[ExecutionStatus.INCOMPLETE],
@@ -383,7 +390,7 @@ def _enqueue_next_nodes(
continue
log_metadata.info(f"Enqueueing static-link execution {suffix}")
enqueued_executions.append(
- add_enqueued_execution(
+ await add_enqueued_execution(
node_exec_id=iexec.node_exec_id,
node_id=next_node_id,
block_id=next_node.block_id,
@@ -395,7 +402,7 @@ def _enqueue_next_nodes(
return [
execution
for link in node.output_links
- for execution in register_next_executions(link)
+ for execution in await register_next_executions(link)
]
@@ -404,11 +411,9 @@ class Executor:
This class contains event handlers for the process pool executor events.
The main events are:
- on_node_executor_start: Initialize the process that executes the node.
- on_node_execution: Execution logic for a node.
-
on_graph_executor_start: Initialize the process that executes the graph.
on_graph_execution: Execution logic for a graph.
+ on_node_execution: Execution logic for a node.
The execution flow:
1. Graph execution request is added to the queue.
@@ -425,46 +430,11 @@ class Executor:
"""
@classmethod
- @func_retry
- def on_node_executor_start(cls):
- configure_logging()
- set_service_name("NodeExecutor")
- redis.connect()
- cls.pid = os.getpid()
- cls.db_client = get_db_client()
- cls.creds_manager = IntegrationCredentialsManager()
-
- # Set up shutdown handlers
- cls.shutdown_lock = threading.Lock()
- atexit.register(cls.on_node_executor_stop)
- signal.signal(signal.SIGTERM, lambda _, __: cls.on_node_executor_sigterm())
- signal.signal(signal.SIGINT, lambda _, __: cls.on_node_executor_sigterm())
-
- @classmethod
- def on_node_executor_stop(cls, log=logger.info):
- if not cls.shutdown_lock.acquire(blocking=False):
- return # already shutting down
-
- log(f"[on_node_executor_stop {cls.pid}] ⏳ Releasing locks...")
- cls.creds_manager.release_all_locks()
- log(f"[on_node_executor_stop {cls.pid}] ⏳ Disconnecting Redis...")
- redis.disconnect()
- log(f"[on_node_executor_stop {cls.pid}] ⏳ Disconnecting DB manager...")
- cls.db_client.close()
- log(f"[on_node_executor_stop {cls.pid}] ✅ Finished NodeExec cleanup")
- sys.exit(0)
-
- @classmethod
- def on_node_executor_sigterm(cls):
- llprint(f"[on_node_executor_sigterm {cls.pid}] ⚠️ NodeExec SIGTERM received")
- cls.on_node_executor_stop(log=llprint)
-
- @classmethod
- @error_logged
- def on_node_execution(
+ @async_error_logged
+ async def on_node_execution(
cls,
- q: ExecutionQueue[ExecutionOutputEntry],
node_exec: NodeExecutionEntry,
+ node_exec_progress: NodeExecutionProgress,
node_credentials_input_map: Optional[
dict[str, dict[str, CredentialsMetaInput]]
] = None,
@@ -477,13 +447,15 @@ class Executor:
node_id=node_exec.node_id,
block_name="-",
)
- node = cls.db_client.get_node(node_exec.node_id)
+ db_client = get_db_async_client()
+ node = await db_client.get_node(node_exec.node_id)
execution_stats = NodeExecutionStats()
- timing_info, _ = cls._on_node_execution(
- q=q,
- node_exec=node_exec,
+ timing_info, _ = await cls._on_node_execution(
node=node,
+ node_exec=node_exec,
+ node_exec_progress=node_exec_progress,
+ db_client=db_client,
log_metadata=log_metadata,
stats=execution_stats,
node_credentials_input_map=node_credentials_input_map,
@@ -493,19 +465,20 @@ class Executor:
if isinstance(execution_stats.error, Exception):
execution_stats.error = str(execution_stats.error)
- exec_update = cls.db_client.update_node_execution_stats(
+ exec_update = await db_client.update_node_execution_stats(
node_exec.node_exec_id, execution_stats
)
- send_execution_update(exec_update)
+ await send_async_execution_update(exec_update)
return execution_stats
@classmethod
- @time_measured
- def _on_node_execution(
+ @async_time_measured
+ async def _on_node_execution(
cls,
- q: ExecutionQueue[ExecutionOutputEntry],
- node_exec: NodeExecutionEntry,
node: Node,
+ node_exec: NodeExecutionEntry,
+ node_exec_progress: NodeExecutionProgress,
+ db_client: "DatabaseManagerAsyncClient",
log_metadata: LogMetadata,
stats: NodeExecutionStats | None = None,
node_credentials_input_map: Optional[
@@ -514,20 +487,20 @@ class Executor:
):
try:
log_metadata.info(f"Start node execution {node_exec.node_exec_id}")
- update_node_execution_status(
- db_client=cls.db_client,
+ await async_update_node_execution_status(
+ db_client=db_client,
exec_id=node_exec.node_exec_id,
status=ExecutionStatus.RUNNING,
)
- for output_name, output_data in execute_node(
+ async for output_name, output_data in execute_node(
node=node,
creds_manager=cls.creds_manager,
data=node_exec,
execution_stats=stats,
node_credentials_input_map=node_credentials_input_map,
):
- q.add(
+ node_exec_progress.add_output(
ExecutionOutputEntry(
node=node,
node_exec_id=node_exec.node_exec_id,
@@ -554,19 +527,19 @@ class Executor:
def on_graph_executor_start(cls):
configure_logging()
set_service_name("GraphExecutor")
-
- cls.db_client = get_db_client()
- cls.pool_size = settings.config.num_node_workers
cls.pid = os.getpid()
- cls._init_node_executor_pool()
- logger.info(f"GraphExec {cls.pid} started with {cls.pool_size} node workers")
-
- @classmethod
- def _init_node_executor_pool(cls):
- cls.executor = Pool(
- processes=cls.pool_size,
- initializer=cls.on_node_executor_start,
+ cls.creds_manager = IntegrationCredentialsManager()
+ cls.node_execution_loop = asyncio.new_event_loop()
+ cls.node_evaluation_loop = asyncio.new_event_loop()
+ cls.node_execution_thread = threading.Thread(
+ target=cls.node_execution_loop.run_forever, daemon=True
)
+ cls.node_evaluation_thread = threading.Thread(
+ target=cls.node_evaluation_loop.run_forever, daemon=True
+ )
+ cls.node_execution_thread.start()
+ cls.node_evaluation_thread.start()
+ logger.info(f"[GraphExecutor] {cls.pid} started")
@classmethod
@error_logged
@@ -581,8 +554,9 @@ class Executor:
node_eid="*",
block_name="-",
)
+ db_client = get_db_client()
- exec_meta = cls.db_client.get_graph_execution_meta(
+ exec_meta = db_client.get_graph_execution_meta(
user_id=graph_exec.user_id,
execution_id=graph_exec.graph_exec_id,
)
@@ -596,9 +570,7 @@ class Executor:
log_metadata.info(f"⚙️ Starting graph execution #{graph_exec.graph_exec_id}")
exec_meta.status = ExecutionStatus.RUNNING
send_execution_update(
- cls.db_client.update_graph_execution_start_time(
- graph_exec.graph_exec_id
- )
+ db_client.update_graph_execution_start_time(graph_exec.graph_exec_id)
)
elif exec_meta.status == ExecutionStatus.RUNNING:
log_metadata.info(
@@ -622,14 +594,14 @@ class Executor:
exec_stats.cputime += timing_info.cpu_time
exec_stats.error = str(error) if error else exec_stats.error
- if graph_exec_result := cls.db_client.update_graph_execution_stats(
+ if graph_exec_result := db_client.update_graph_execution_stats(
graph_exec_id=graph_exec.graph_exec_id,
status=status,
stats=exec_stats,
):
send_execution_update(graph_exec_result)
- cls._handle_agent_run_notif(graph_exec, exec_stats)
+ cls._handle_agent_run_notif(db_client, graph_exec, exec_stats)
@classmethod
def _charge_usage(
@@ -638,6 +610,7 @@ class Executor:
execution_count: int,
execution_stats: GraphExecutionStats,
):
+ db_client = get_db_client()
block = get_block(node_exec.block_id)
if not block:
logger.error(f"Block {node_exec.block_id} not found.")
@@ -647,7 +620,7 @@ class Executor:
block=block, input_data=node_exec.inputs
)
if cost > 0:
- cls.db_client.spend_credits(
+ db_client.spend_credits(
user_id=node_exec.user_id,
cost=cost,
metadata=UsageTransactionMetadata(
@@ -665,7 +638,7 @@ class Executor:
cost, usage_count = execution_usage_cost(execution_count)
if cost > 0:
- cls.db_client.spend_credits(
+ db_client.spend_credits(
user_id=node_exec.user_id,
cost=cost,
metadata=UsageTransactionMetadata(
@@ -695,18 +668,11 @@ class Executor:
ExecutionStatus: The final status of the graph execution.
Exception | None: The error that occurred during the execution, if any.
"""
- execution_status = ExecutionStatus.RUNNING
- error = None
- finished = False
+ execution_status: ExecutionStatus = ExecutionStatus.RUNNING
+ error: Exception | None = None
+ db_client = get_db_client()
- def drain_output_queue():
- while output := output_queue.get_or_none():
- log_metadata.debug(
- f"Received output for {output.node.id} - {output.node_exec_id}: {output.data}"
- )
- running_executions[output.node.id].add_output(output)
-
- def drain_done_task(node_exec_id: str, result: object):
+ def on_done_task(node_exec_id: str, result: object):
if not isinstance(result, NodeExecutionStats):
log_metadata.error(f"Unexpected result #{node_exec_id}: {type(result)}")
return
@@ -718,49 +684,40 @@ class Executor:
if (err := result.error) and isinstance(err, Exception):
execution_stats.node_error_count += 1
update_node_execution_status(
- db_client=cls.db_client,
+ db_client=db_client,
exec_id=node_exec_id,
status=ExecutionStatus.FAILED,
)
else:
update_node_execution_status(
- db_client=cls.db_client,
+ db_client=db_client,
exec_id=node_exec_id,
status=ExecutionStatus.COMPLETED,
)
- if _graph_exec := cls.db_client.update_graph_execution_stats(
+ if _graph_exec := db_client.update_graph_execution_stats(
graph_exec_id=graph_exec.graph_exec_id,
status=execution_status,
stats=execution_stats,
):
send_execution_update(_graph_exec)
else:
- logger.error(
- "Callback for "
- f"finished node execution #{node_exec_id} "
- "could not update execution stats "
+ log_metadata.error(
+ "Callback for finished node execution "
+ f"#{node_exec_id} could not update execution stats "
f"for graph execution #{graph_exec.graph_exec_id}; "
f"triggered while graph exec status = {execution_status}"
)
- def cancel_handler():
- nonlocal execution_status
-
- while not cancel.is_set():
- cancel.wait(1)
- if finished:
- return
- execution_status = ExecutionStatus.TERMINATED
- cls.executor.terminate()
- log_metadata.info(f"Terminated graph execution {graph_exec.graph_exec_id}")
- cls._init_node_executor_pool()
-
- cancel_thread = threading.Thread(target=cancel_handler)
- cancel_thread.start()
+ # State holders ----------------------------------------------------
+ running_node_execution: dict[str, NodeExecutionProgress] = defaultdict(
+ lambda: NodeExecutionProgress(on_done_task=on_done_task)
+ )
+ running_node_evaluation: dict[str, Future] = {}
+ execution_queue = ExecutionQueue[NodeExecutionEntry]()
try:
- if cls.db_client.get_credits(graph_exec.user_id) <= 0:
+ if db_client.get_credits(graph_exec.user_id) <= 0:
raise InsufficientBalanceError(
user_id=graph_exec.user_id,
message="You have no credits left to run an agent.",
@@ -768,21 +725,18 @@ class Executor:
amount=1,
)
- output_queue = ExecutionQueue[ExecutionOutputEntry]()
- execution_queue = ExecutionQueue[NodeExecutionEntry]()
- for node_exec in cls.db_client.get_node_executions(
+ # ------------------------------------------------------------
+ # Pre‑populate queue ---------------------------------------
+ # ------------------------------------------------------------
+ for node_exec in db_client.get_node_executions(
graph_exec.graph_exec_id,
statuses=[ExecutionStatus.RUNNING, ExecutionStatus.QUEUED],
):
execution_queue.add(node_exec.to_node_execution_entry())
- running_executions: dict[str, NodeExecutionProgress] = defaultdict(
- lambda: NodeExecutionProgress(
- drain_output_queue=drain_output_queue,
- drain_done_task=drain_done_task,
- )
- )
-
+ # ------------------------------------------------------------
+ # Main dispatch / polling loop -----------------------------
+ # ------------------------------------------------------------
while not execution_queue.empty():
if cancel.is_set():
execution_status = ExecutionStatus.TERMINATED
@@ -795,6 +749,7 @@ class Executor:
f"for node {queued_node_exec.node_id}",
)
+ # Charge usage (may raise) ------------------------------
try:
cls._charge_usage(
node_exec=queued_node_exec,
@@ -803,19 +758,20 @@ class Executor:
)
except InsufficientBalanceError as error:
node_exec_id = queued_node_exec.node_exec_id
- cls.db_client.upsert_execution_output(
+ db_client.upsert_execution_output(
node_exec_id=node_exec_id,
output_name="error",
output_data=str(error),
)
update_node_execution_status(
- db_client=cls.db_client,
+ db_client=db_client,
exec_id=node_exec_id,
status=ExecutionStatus.FAILED,
)
execution_status = ExecutionStatus.FAILED
cls._handle_low_balance_notif(
+ db_client,
graph_exec.user_id,
graph_exec.graph_id,
execution_stats,
@@ -823,7 +779,7 @@ class Executor:
)
raise
- # Add credentials input overrides
+ # Add credential overrides -----------------------------
node_id = queued_node_exec.node_id
if (node_creds_map := graph_exec.node_credentials_input_map) and (
node_field_creds_map := node_creds_map.get(node_id)
@@ -835,72 +791,120 @@ class Executor:
}
)
- # Initiate node execution
- running_executions[queued_node_exec.node_id].add_task(
- queued_node_exec.node_exec_id,
- cls.executor.apply_async(
- cls.on_node_execution,
- (output_queue, queued_node_exec, node_creds_map),
+ # Kick off async node execution -------------------------
+ node_execution_task = asyncio.run_coroutine_threadsafe(
+ cls.on_node_execution(
+ node_exec=queued_node_exec,
+ node_exec_progress=running_node_execution[node_id],
+ node_credentials_input_map=node_creds_map,
),
+ cls.node_execution_loop,
+ )
+ running_node_execution[node_id].add_task(
+ node_exec_id=queued_node_exec.node_exec_id,
+ task=node_execution_task,
)
- # Avoid terminating graph execution when some nodes are still running.
- while execution_queue.empty() and running_executions:
- log_metadata.debug(
- f"Queue empty; running nodes: {list(running_executions.keys())}"
- )
-
- # Register next node executions from running_executions.
- for node_id, execution in list(running_executions.items()):
+ # Poll until queue refills or all inflight work done ----
+ while execution_queue.empty() and (
+ running_node_execution or running_node_evaluation
+ ):
+ # --------------------------------------------------
+ # Handle inflight evaluations ---------------------
+ # --------------------------------------------------
+ node_output_found = False
+ for node_id, inflight_exec in list(running_node_execution.items()):
if cancel.is_set():
execution_status = ExecutionStatus.TERMINATED
return execution_stats, execution_status, error
- log_metadata.debug(f"Waiting on execution of node {node_id}")
- while output := execution.pop_output():
- cls._process_node_output(
- output=output,
- node_id=node_id,
- graph_exec=graph_exec,
- log_metadata=log_metadata,
- node_creds_map=node_creds_map,
- execution_queue=execution_queue,
+ # node evaluation future -----------------
+ if inflight_eval := running_node_evaluation.get(node_id):
+ try:
+ inflight_eval.result()
+ running_node_evaluation.pop(node_id)
+ except TimeoutError:
+ continue
+
+ # node execution future ---------------------------
+ if inflight_exec.is_done():
+ running_node_execution.pop(node_id)
+ continue
+
+ if output := inflight_exec.pop_output():
+ node_output_found = True
+ running_node_evaluation[node_id] = (
+ asyncio.run_coroutine_threadsafe(
+ cls._process_node_output(
+ output=output,
+ node_id=node_id,
+ graph_exec=graph_exec,
+ log_metadata=log_metadata,
+ node_creds_map=node_creds_map,
+ execution_queue=execution_queue,
+ ),
+ cls.node_evaluation_loop,
+ )
)
- if not execution_queue.empty():
- break # Prioritize executing next nodes than enqueuing outputs
-
- if execution.is_done():
- running_executions.pop(node_id)
-
- if not execution_queue.empty():
- continue # Make sure each not is checked once
-
- if execution_queue.empty() and running_executions:
- log_metadata.debug(
- "No more nodes to execute, waiting for outputs..."
- )
+ if (
+ not node_output_found
+ and execution_queue.empty()
+ and (running_node_execution or running_node_evaluation)
+ ):
+ # There is nothing to execute, and no output to process, let's relax for a while.
time.sleep(0.1)
- log_metadata.info(f"Finished graph execution {graph_exec.graph_exec_id}")
+ # loop done --------------------------------------------------
execution_status = ExecutionStatus.COMPLETED
+ return execution_stats, execution_status, error
- except Exception as e:
- error = e
+ except CancelledError as exc:
+ execution_status = ExecutionStatus.TERMINATED
+ error = exc
+ log_metadata.exception(
+ f"Cancelled graph execution {graph_exec.graph_exec_id}: {error}"
+ )
+ except Exception as exc:
+ execution_status = ExecutionStatus.FAILED
+ error = exc
log_metadata.exception(
f"Failed graph execution {graph_exec.graph_exec_id}: {error}"
)
- execution_status = ExecutionStatus.FAILED
-
finally:
- if not cancel.is_set():
- finished = True
- cancel.set()
- cancel_thread.join()
+ for node_id, inflight_exec in running_node_execution.items():
+ if inflight_exec.is_done():
+ continue
+ log_metadata.info(f"Stopping node execution {node_id}")
+ inflight_exec.stop()
+
+ for node_id, inflight_eval in running_node_evaluation.items():
+ if inflight_eval.done():
+ continue
+ log_metadata.info(f"Stopping node evaluation {node_id}")
+ inflight_eval.cancel()
+
+ if execution_status in [ExecutionStatus.TERMINATED, ExecutionStatus.FAILED]:
+ inflight_executions = db_client.get_node_executions(
+ graph_exec.graph_exec_id,
+ statuses=[
+ ExecutionStatus.QUEUED,
+ ExecutionStatus.RUNNING,
+ ],
+ )
+ db_client.update_node_execution_status_batch(
+ [node_exec.node_exec_id for node_exec in inflight_executions],
+ status=execution_status,
+ stats={"error": str(error)} if error else None,
+ )
+ for node_exec in inflight_executions:
+ node_exec.status = execution_status
+ send_execution_update(node_exec)
+
clean_exec_files(graph_exec.graph_exec_id)
return execution_stats, execution_status, error
@classmethod
- def _process_node_output(
+ async def _process_node_output(
cls,
output: ExecutionOutputEntry,
node_id: str,
@@ -919,19 +923,21 @@ class Executor:
node_creds_map: Optional map of node credentials
execution_queue: Queue to add next executions to
"""
+ db_client = get_db_async_client()
+
try:
name, data = output.data
- cls.db_client.upsert_execution_output(
+ await db_client.upsert_execution_output(
node_exec_id=output.node_exec_id,
output_name=name,
output_data=data,
)
- if exec_update := cls.db_client.get_node_execution(output.node_exec_id):
- send_execution_update(exec_update)
+ if exec_update := await db_client.get_node_execution(output.node_exec_id):
+ await send_async_execution_update(exec_update)
log_metadata.debug(f"Enqueue nodes for {node_id}: {output}")
- for next_execution in _enqueue_next_nodes(
- db_client=cls.db_client,
+ for next_execution in await _enqueue_next_nodes(
+ db_client=db_client,
node=output.node,
output=output.data,
user_id=graph_exec.user_id,
@@ -943,13 +949,13 @@ class Executor:
execution_queue.add(next_execution)
except Exception as e:
log_metadata.exception(f"Failed to process node output: {e}")
- cls.db_client.upsert_execution_output(
+ await db_client.upsert_execution_output(
node_exec_id=output.node_exec_id,
output_name="error",
output_data=str(e),
)
- update_node_execution_status(
- db_client=cls.db_client,
+ await async_update_node_execution_status(
+ db_client=db_client,
exec_id=output.node_exec_id,
status=ExecutionStatus.FAILED,
)
@@ -957,13 +963,14 @@ class Executor:
@classmethod
def _handle_agent_run_notif(
cls,
+ db_client: "DatabaseManagerClient",
graph_exec: GraphExecutionEntry,
exec_stats: GraphExecutionStats,
):
- metadata = cls.db_client.get_graph_metadata(
+ metadata = db_client.get_graph_metadata(
graph_exec.graph_id, graph_exec.graph_version
)
- outputs = cls.db_client.get_node_executions(
+ outputs = db_client.get_node_executions(
graph_exec.graph_exec_id,
block_ids=[AgentOutputBlock().id],
)
@@ -994,13 +1001,14 @@ class Executor:
@classmethod
def _handle_low_balance_notif(
cls,
+ db_client: "DatabaseManagerClient",
user_id: str,
graph_id: str,
exec_stats: GraphExecutionStats,
e: InsufficientBalanceError,
):
shortfall = e.balance - e.amount
- metadata = cls.db_client.get_graph_metadata(graph_id)
+ metadata = db_client.get_graph_metadata(graph_id)
base_url = (
settings.config.frontend_base_url or settings.config.platform_base_url
)
@@ -1046,9 +1054,6 @@ class ExecutionManager(AppProcess):
initializer=Executor.on_graph_executor_start,
)
- logger.info(f"[{self.service_name}] ⏳ Connecting to Redis...")
- redis.connect()
-
threading.Thread(
target=lambda: self._consume_execution_cancel(),
daemon=True,
@@ -1162,19 +1167,21 @@ class ExecutionManager(AppProcess):
self.active_graph_runs.pop(graph_exec_id, None)
active_runs_gauge.set(len(self.active_graph_runs))
utilization_gauge.set(len(self.active_graph_runs) / self.pool_size)
- if f.exception():
+ if exec_error := f.exception():
logger.error(
- f"[{self.service_name}] Execution for {graph_exec_id} failed: {f.exception()}"
+ f"[{self.service_name}] Execution for {graph_exec_id} failed: {exec_error}"
)
channel.connection.add_callback_threadsafe(
- lambda: channel.basic_nack(delivery_tag, requeue=False)
+ lambda: channel.basic_nack(delivery_tag, requeue=True)
)
else:
channel.connection.add_callback_threadsafe(
lambda: channel.basic_ack(delivery_tag)
)
- except Exception as e:
- logger.error(f"[{self.service_name}] Error acknowledging message: {e}")
+ except BaseException as e:
+ logger.exception(
+ f"[{self.service_name}] Error acknowledging message: {e}"
+ )
future.add_done_callback(_on_run_done)
@@ -1209,7 +1216,27 @@ def get_db_client() -> "DatabaseManagerClient":
from backend.executor import DatabaseManagerClient
# Disable health check for the service client to avoid breaking process initializer.
- return get_service_client(DatabaseManagerClient, health_check=False)
+ return get_service_client(
+ DatabaseManagerClient, health_check=False, request_retry=True
+ )
+
+
+@thread_cached
+def get_db_async_client() -> "DatabaseManagerAsyncClient":
+ from backend.executor import DatabaseManagerAsyncClient
+
+ # Disable health check for the service client to avoid breaking process initializer.
+ return get_service_client(
+ DatabaseManagerAsyncClient, health_check=False, request_retry=True
+ )
+
+
+async def send_async_execution_update(
+ entry: GraphExecution | NodeExecutionResult | None,
+) -> None:
+ if entry is None:
+ return
+ await get_async_execution_event_bus().publish(entry)
def send_execution_update(entry: GraphExecution | NodeExecutionResult | None):
@@ -1218,29 +1245,46 @@ def send_execution_update(entry: GraphExecution | NodeExecutionResult | None):
return get_execution_event_bus().publish(entry)
+async def async_update_node_execution_status(
+ db_client: "DatabaseManagerAsyncClient",
+ exec_id: str,
+ status: ExecutionStatus,
+ execution_data: BlockInput | None = None,
+ stats: dict[str, Any] | None = None,
+) -> NodeExecutionResult:
+ """Sets status and fetches+broadcasts the latest state of the node execution"""
+ exec_update = await db_client.update_node_execution_status(
+ exec_id, status, execution_data, stats
+ )
+ await send_async_execution_update(exec_update)
+ return exec_update
+
+
def update_node_execution_status(
db_client: "DatabaseManagerClient",
exec_id: str,
status: ExecutionStatus,
execution_data: BlockInput | None = None,
+ stats: dict[str, Any] | None = None,
) -> NodeExecutionResult:
"""Sets status and fetches+broadcasts the latest state of the node execution"""
exec_update = db_client.update_node_execution_status(
- exec_id, status, execution_data
+ exec_id, status, execution_data, stats
)
send_execution_update(exec_update)
return exec_update
-@contextmanager
-def synchronized(key: str, timeout: int = 60):
- lock: RedisLock = redis.get_redis().lock(f"lock:{key}", timeout=timeout)
+@asynccontextmanager
+async def synchronized(key: str, timeout: int = 60):
+ r = await redis.get_redis_async()
+ lock: RedisLock = r.lock(f"lock:{key}", timeout=timeout)
try:
- lock.acquire()
+ await lock.acquire()
yield
finally:
- if lock.locked() and lock.owned():
- lock.release()
+ if await lock.locked() and await lock.owned():
+ await lock.release()
def increment_execution_count(user_id: str) -> int:
diff --git a/autogpt_platform/backend/backend/executor/scheduler.py b/autogpt_platform/backend/backend/executor/scheduler.py
index 6b9008d4cc..0c25e58f94 100644
--- a/autogpt_platform/backend/backend/executor/scheduler.py
+++ b/autogpt_platform/backend/backend/executor/scheduler.py
@@ -1,3 +1,4 @@
+import asyncio
import logging
import os
from datetime import datetime, timedelta, timezone
@@ -71,15 +72,25 @@ def get_notification_client():
return get_service_client(NotificationManagerClient)
+@thread_cached
+def get_event_loop():
+ return asyncio.new_event_loop()
+
+
def execute_graph(**kwargs):
+ get_event_loop().run_until_complete(_execute_graph(**kwargs))
+
+
+async def _execute_graph(**kwargs):
args = GraphExecutionJobArgs(**kwargs)
try:
log(f"Executing recurring job for graph #{args.graph_id}")
- execution_utils.add_graph_execution(
+ await execution_utils.add_graph_execution(
graph_id=args.graph_id,
inputs=args.input_data,
user_id=args.user_id,
graph_version=args.graph_version,
+ use_db_query=False,
)
except Exception as e:
logger.exception(f"Error executing graph {args.graph_id}: {e}")
@@ -104,11 +115,18 @@ def report_late_executions() -> str:
num_late_executions = len(late_executions)
num_users = len(set([r.user_id for r in late_executions]))
+
+ late_execution_details = [
+ f"* `Execution ID: {exec.id}, Graph ID: {exec.graph_id}v{exec.graph_version}, User ID: {exec.user_id}, Created At: {exec.started_at.isoformat()}`"
+ for exec in late_executions
+ ]
+
error = LateExecutionException(
f"Late executions detected: {num_late_executions} late executions from {num_users} users "
f"in the last {config.execution_late_notification_checkrange_secs} seconds. "
f"Graph has been queued for more than {config.execution_late_notification_threshold_secs} seconds. "
- "Please check the executor status."
+ "Please check the executor status. Details:\n"
+ + "\n".join(late_execution_details)
)
msg = str(error)
sentry_capture_error(error)
diff --git a/autogpt_platform/backend/backend/executor/utils.py b/autogpt_platform/backend/backend/executor/utils.py
index 2129632c2a..4ef18d509f 100644
--- a/autogpt_platform/backend/backend/executor/utils.py
+++ b/autogpt_platform/backend/backend/executor/utils.py
@@ -1,6 +1,7 @@
+import asyncio
import logging
from collections import defaultdict
-from multiprocessing.pool import AsyncResult
+from concurrent.futures import Future
from typing import TYPE_CHECKING, Any, Callable, Optional, cast
from autogpt_libs.utils.cache import thread_cached
@@ -23,6 +24,7 @@ from backend.data.execution import (
GraphExecutionWithNodes,
RedisExecutionEventBus,
create_graph_execution,
+ get_node_executions,
update_graph_execution_stats,
update_node_execution_status_batch,
)
@@ -37,17 +39,18 @@ from backend.data.rabbitmq import (
SyncRabbitMQ,
)
from backend.util.exceptions import NotFoundError
+from backend.util.logging import TruncatedLogger
from backend.util.mock import MockObject
from backend.util.service import get_service_client
from backend.util.settings import Config
from backend.util.type import convert
if TYPE_CHECKING:
- from backend.executor import DatabaseManagerClient
+ from backend.executor import DatabaseManagerAsyncClient, DatabaseManagerClient
from backend.integrations.credentials_store import IntegrationCredentialsStore
config = Config()
-logger = logging.getLogger(__name__)
+logger = TruncatedLogger(logging.getLogger(__name__), prefix="[GraphExecutorUtil]")
# ============ Resource Helpers ============ #
@@ -90,6 +93,13 @@ def get_db_client() -> "DatabaseManagerClient":
return get_service_client(DatabaseManagerClient)
+@thread_cached
+def get_db_async_client() -> "DatabaseManagerAsyncClient":
+ from backend.executor import DatabaseManagerAsyncClient
+
+ return get_service_client(DatabaseManagerAsyncClient)
+
+
# ============ Execution Cost Helpers ============ #
@@ -392,12 +402,6 @@ def validate_exec(
return None, f"Block for {node.block_id} not found."
schema = node_block.input_schema
- # Convert non-matching data types to the expected input schema.
- for name, data_type in schema.__annotations__.items():
- value = data.get(name)
- if (value is not None) and (type(value) is not data_type):
- data[name] = convert(value, data_type)
-
# Input data (without default values) should contain all required fields.
error_prefix = f"Input data missing or mismatch for `{node_block.name}`:"
if missing_links := schema.get_missing_links(data, node.input_links):
@@ -409,6 +413,12 @@ def validate_exec(
if resolve_input:
data = merge_execution_input(data)
+ # Convert non-matching data types to the expected input schema.
+ for name, data_type in schema.__annotations__.items():
+ value = data.get(name)
+ if (value is not None) and (type(value) is not data_type):
+ data[name] = convert(value, data_type)
+
# Input data post-merge should contain all required fields from the schema.
if missing_input := schema.get_missing_input(data):
return None, f"{error_prefix} missing input {missing_input}"
@@ -422,7 +432,7 @@ def validate_exec(
return data, node_block.name
-def _validate_node_input_credentials(
+async def _validate_node_input_credentials(
graph: GraphModel,
user_id: str,
node_credentials_input_map: Optional[
@@ -459,7 +469,7 @@ def _validate_node_input_credentials(
)
# Fetch the corresponding Credentials and perform sanity checks
- credentials = get_integration_credentials_store().get_creds_by_id(
+ credentials = await get_integration_credentials_store().get_creds_by_id(
user_id, credentials_meta.id
)
if not credentials:
@@ -516,7 +526,7 @@ def make_node_credentials_input_map(
return result
-def construct_node_execution_input(
+async def construct_node_execution_input(
graph: GraphModel,
user_id: str,
graph_inputs: BlockInput,
@@ -541,7 +551,7 @@ def construct_node_execution_input(
the corresponding input data for that node.
"""
graph.validate_graph(for_run=True)
- _validate_node_input_credentials(graph, user_id, node_credentials_input_map)
+ await _validate_node_input_credentials(graph, user_id, node_credentials_input_map)
nodes_input = []
for node in graph.starting_nodes:
@@ -642,13 +652,92 @@ def create_execution_queue_config() -> RabbitMQConfig:
)
-async def add_graph_execution_async(
+async def stop_graph_execution(
+ graph_exec_id: str,
+ use_db_query: bool = True,
+):
+ """
+ Mechanism:
+ 1. Set the cancel event
+ 2. Graph executor's cancel handler thread detects the event, terminates workers,
+ reinitializes worker pool, and returns.
+ 3. Update execution statuses in DB and set `error` outputs to `"TERMINATED"`.
+ """
+ queue_client = await get_async_execution_queue()
+ await queue_client.publish_message(
+ routing_key="",
+ message=CancelExecutionEvent(graph_exec_id=graph_exec_id).model_dump_json(),
+ exchange=GRAPH_EXECUTION_CANCEL_EXCHANGE,
+ )
+
+ # Update the status of the graph execution
+ if use_db_query:
+ graph_execution = await update_graph_execution_stats(
+ graph_exec_id,
+ ExecutionStatus.TERMINATED,
+ )
+ else:
+ graph_execution = await get_db_async_client().update_graph_execution_stats(
+ graph_exec_id,
+ ExecutionStatus.TERMINATED,
+ )
+
+ if graph_execution:
+ await get_async_execution_event_bus().publish(graph_execution)
+ else:
+ raise NotFoundError(
+ f"Graph execution #{graph_exec_id} not found for termination."
+ )
+
+ # Update the status of the node executions
+ if use_db_query:
+ node_executions = await get_node_executions(
+ graph_exec_id=graph_exec_id,
+ statuses=[
+ ExecutionStatus.QUEUED,
+ ExecutionStatus.RUNNING,
+ ExecutionStatus.INCOMPLETE,
+ ],
+ )
+ await update_node_execution_status_batch(
+ [v.node_exec_id for v in node_executions],
+ ExecutionStatus.TERMINATED,
+ )
+ else:
+ node_executions = await get_db_async_client().get_node_executions(
+ graph_exec_id=graph_exec_id,
+ statuses=[
+ ExecutionStatus.QUEUED,
+ ExecutionStatus.RUNNING,
+ ExecutionStatus.INCOMPLETE,
+ ],
+ )
+ await get_db_async_client().update_node_execution_status_batch(
+ [v.node_exec_id for v in node_executions],
+ ExecutionStatus.TERMINATED,
+ )
+
+ await asyncio.gather(
+ *[
+ get_async_execution_event_bus().publish(
+ v.model_copy(update={"status": ExecutionStatus.TERMINATED})
+ )
+ for v in node_executions
+ ]
+ )
+
+
+async def add_graph_execution(
graph_id: str,
user_id: str,
inputs: BlockInput,
preset_id: Optional[str] = None,
graph_version: Optional[int] = None,
graph_credentials_inputs: Optional[dict[str, CredentialsMetaInput]] = None,
+ node_credentials_input_map: Optional[
+ dict[str, dict[str, CredentialsMetaInput]]
+ ] = None,
+ use_db_query: bool = True,
) -> GraphExecutionWithNodes:
"""
Adds a graph execution to the queue and returns the execution entry.
@@ -661,38 +750,63 @@ async def add_graph_execution_async(
graph_version: The version of the graph to execute.
graph_credentials_inputs: Credentials inputs to use in the execution.
Keys should map to the keys generated by `GraphModel.aggregate_credentials_inputs`.
+ node_credentials_input_map: Credentials inputs to use in the execution, mapped to specific nodes.
Returns:
GraphExecutionEntry: The entry for the graph execution.
Raises:
ValueError: If the graph is not found or if there are validation errors.
""" # noqa
- graph: GraphModel | None = await get_graph(
- graph_id=graph_id,
- user_id=user_id,
- version=graph_version,
- include_subgraphs=True,
- )
+ if use_db_query:
+ graph: GraphModel | None = await get_graph(
+ graph_id=graph_id,
+ user_id=user_id,
+ version=graph_version,
+ include_subgraphs=True,
+ )
+ else:
+ graph: GraphModel | None = await get_db_async_client().get_graph(
+ graph_id=graph_id,
+ user_id=user_id,
+ version=graph_version,
+ include_subgraphs=True,
+ )
+
if not graph:
raise NotFoundError(f"Graph #{graph_id} not found.")
- node_credentials_input_map = (
+ node_credentials_input_map = node_credentials_input_map or (
make_node_credentials_input_map(graph, graph_credentials_inputs)
if graph_credentials_inputs
else None
)
- graph_exec = await create_graph_execution(
- user_id=user_id,
- graph_id=graph_id,
- graph_version=graph.version,
- starting_nodes_input=construct_node_execution_input(
- graph=graph,
+ if use_db_query:
+ graph_exec = await create_graph_execution(
user_id=user_id,
- graph_inputs=inputs,
- node_credentials_input_map=node_credentials_input_map,
- ),
- preset_id=preset_id,
- )
+ graph_id=graph_id,
+ graph_version=graph.version,
+ starting_nodes_input=await construct_node_execution_input(
+ graph=graph,
+ user_id=user_id,
+ graph_inputs=inputs,
+ node_credentials_input_map=node_credentials_input_map,
+ ),
+ preset_id=preset_id,
+ )
+ else:
+ graph_exec = await get_db_async_client().create_graph_execution(
+ user_id=user_id,
+ graph_id=graph_id,
+ graph_version=graph.version,
+ starting_nodes_input=await construct_node_execution_input(
+ graph=graph,
+ user_id=user_id,
+ graph_inputs=inputs,
+ node_credentials_input_map=node_credentials_input_map,
+ ),
+ preset_id=preset_id,
+ )
+
try:
queue = await get_async_execution_queue()
graph_exec_entry = graph_exec.to_graph_execution_entry()
@@ -711,101 +825,27 @@ async def add_graph_execution_async(
except Exception as e:
logger.error(f"Unable to publish graph #{graph_id} exec #{graph_exec.id}: {e}")
- await update_node_execution_status_batch(
- [node_exec.node_exec_id for node_exec in graph_exec.node_executions],
- ExecutionStatus.FAILED,
- )
- await update_graph_execution_stats(
- graph_exec_id=graph_exec.id,
- status=ExecutionStatus.FAILED,
- stats=GraphExecutionStats(error=str(e)),
- )
- raise
+ if use_db_query:
+ await update_node_execution_status_batch(
+ [node_exec.node_exec_id for node_exec in graph_exec.node_executions],
+ ExecutionStatus.FAILED,
+ )
+ await update_graph_execution_stats(
+ graph_exec_id=graph_exec.id,
+ status=ExecutionStatus.FAILED,
+ stats=GraphExecutionStats(error=str(e)),
+ )
+ else:
+ await get_db_async_client().update_node_execution_status_batch(
+ [node_exec.node_exec_id for node_exec in graph_exec.node_executions],
+ ExecutionStatus.FAILED,
+ )
+ await get_db_async_client().update_graph_execution_stats(
+ graph_exec_id=graph_exec.id,
+ status=ExecutionStatus.FAILED,
+ stats=GraphExecutionStats(error=str(e)),
+ )
-
-def add_graph_execution(
- graph_id: str,
- user_id: str,
- inputs: BlockInput,
- preset_id: Optional[str] = None,
- graph_version: Optional[int] = None,
- graph_credentials_inputs: Optional[dict[str, CredentialsMetaInput]] = None,
- node_credentials_input_map: Optional[
- dict[str, dict[str, CredentialsMetaInput]]
- ] = None,
-) -> GraphExecutionWithNodes:
- """
- Adds a graph execution to the queue and returns the execution entry.
-
- Args:
- graph_id: The ID of the graph to execute.
- user_id: The ID of the user executing the graph.
- inputs: The input data for the graph execution.
- preset_id: The ID of the preset to use.
- graph_version: The version of the graph to execute.
- graph_credentials_inputs: Credentials inputs to use in the execution.
- Keys should map to the keys generated by `GraphModel.aggregate_credentials_inputs`.
- node_credentials_input_map: Credentials inputs to use in the execution, mapped to specific nodes.
- Returns:
- GraphExecutionEntry: The entry for the graph execution.
- Raises:
- ValueError: If the graph is not found or if there are validation errors.
- """
- db = get_db_client()
- graph: GraphModel | None = db.get_graph(
- graph_id=graph_id,
- user_id=user_id,
- version=graph_version,
- include_subgraphs=True,
- )
- if not graph:
- raise NotFoundError(f"Graph #{graph_id} not found.")
-
- node_credentials_input_map = node_credentials_input_map or (
- make_node_credentials_input_map(graph, graph_credentials_inputs)
- if graph_credentials_inputs
- else None
- )
-
- graph_exec = db.create_graph_execution(
- user_id=user_id,
- graph_id=graph_id,
- graph_version=graph.version,
- starting_nodes_input=construct_node_execution_input(
- graph=graph,
- user_id=user_id,
- graph_inputs=inputs,
- node_credentials_input_map=node_credentials_input_map,
- ),
- preset_id=preset_id,
- )
- try:
- queue = get_execution_queue()
- graph_exec_entry = graph_exec.to_graph_execution_entry()
- if node_credentials_input_map:
- graph_exec_entry.node_credentials_input_map = node_credentials_input_map
- queue.publish_message(
- routing_key=GRAPH_EXECUTION_ROUTING_KEY,
- message=graph_exec_entry.model_dump_json(),
- exchange=GRAPH_EXECUTION_EXCHANGE,
- )
-
- bus = get_execution_event_bus()
- bus.publish(graph_exec)
-
- return graph_exec
- except Exception as e:
- logger.error(f"Unable to publish graph #{graph_id} exec #{graph_exec.id}: {e}")
-
- db.update_node_execution_status_batch(
- [node_exec.node_exec_id for node_exec in graph_exec.node_executions],
- ExecutionStatus.FAILED,
- )
- db.update_graph_execution_stats(
- graph_exec_id=graph_exec.id,
- status=ExecutionStatus.FAILED,
- stats=GraphExecutionStats(error=str(e)),
- )
raise
@@ -821,15 +861,13 @@ class ExecutionOutputEntry(BaseModel):
class NodeExecutionProgress:
def __init__(
self,
- drain_output_queue: Callable[[], None],
- drain_done_task: Callable[[str, object], None],
+ on_done_task: Callable[[str, object], None],
):
self.output: dict[str, list[ExecutionOutputEntry]] = defaultdict(list)
- self.tasks: dict[str, AsyncResult] = {}
- self.drain_output_queue = drain_output_queue
- self.drain_done_task = drain_done_task
+ self.tasks: dict[str, Future] = {}
+ self.on_done_task = on_done_task
- def add_task(self, node_exec_id: str, task: AsyncResult):
+ def add_task(self, node_exec_id: str, task: Future):
self.tasks[node_exec_id] = task
def add_output(self, output: ExecutionOutputEntry):
@@ -859,23 +897,46 @@ class NodeExecutionProgress:
if wait_time <= 0:
return False
- self.tasks[exec_id].wait(wait_time)
+ try:
+ self.tasks[exec_id].result(wait_time)
+ except TimeoutError:
+ print(
+ ">>>>>>> -- Timeout, after waiting for",
+ wait_time,
+ "seconds for node_id",
+ exec_id,
+ )
+ pass
+
return self.is_done(0)
+ def stop(self) -> list[str]:
+ """
+ Stops all tasks and clears the output.
+ This is useful for cleaning up when the execution is cancelled or terminated.
+ Returns a list of execution IDs that were stopped.
+ """
+ cancelled_ids = []
+ for task_id, task in self.tasks.items():
+ if task.done():
+ continue
+ task.cancel()
+ cancelled_ids.append(task_id)
+ return cancelled_ids
+
def _pop_done_task(self, exec_id: str) -> bool:
task = self.tasks.get(exec_id)
if not task:
return True
- if not task.ready():
+ if not task.done():
return False
- self.drain_output_queue()
if self.output[exec_id]:
return False
if task := self.tasks.pop(exec_id):
- self.drain_done_task(exec_id, task.get())
+ self.on_done_task(exec_id, task.result())
return True
diff --git a/autogpt_platform/backend/backend/integrations/credentials_store.py b/autogpt_platform/backend/backend/integrations/credentials_store.py
index 847b20fa6c..a86cc28e92 100644
--- a/autogpt_platform/backend/backend/integrations/credentials_store.py
+++ b/autogpt_platform/backend/backend/integrations/credentials_store.py
@@ -6,11 +6,13 @@ from typing import TYPE_CHECKING, Optional
from pydantic import SecretStr
+from backend.data.redis import get_redis_async
+
if TYPE_CHECKING:
- from backend.executor.database import DatabaseManagerClient
+ from backend.executor.database import DatabaseManagerAsyncClient
from autogpt_libs.utils.cache import thread_cached
-from autogpt_libs.utils.synchronize import RedisKeyedMutex
+from autogpt_libs.utils.synchronize import AsyncRedisKeyedMutex
from backend.data.model import (
APIKeyCredentials,
@@ -220,31 +222,36 @@ DEFAULT_CREDENTIALS = [
class IntegrationCredentialsStore:
def __init__(self):
- from backend.data.redis import get_redis
+ self._locks = None
- self.locks = RedisKeyedMutex(get_redis())
+ async def locks(self) -> AsyncRedisKeyedMutex:
+ if self._locks:
+ return self._locks
+
+ self._locks = AsyncRedisKeyedMutex(await get_redis_async())
+ return self._locks
@property
@thread_cached
- def db_manager(self) -> "DatabaseManagerClient":
- from backend.executor.database import DatabaseManagerClient
+ def db_manager(self) -> "DatabaseManagerAsyncClient":
+ from backend.executor.database import DatabaseManagerAsyncClient
from backend.util.service import get_service_client
- return get_service_client(DatabaseManagerClient)
+ return get_service_client(DatabaseManagerAsyncClient)
- def add_creds(self, user_id: str, credentials: Credentials) -> None:
- with self.locked_user_integrations(user_id):
- if self.get_creds_by_id(user_id, credentials.id):
+ async def add_creds(self, user_id: str, credentials: Credentials) -> None:
+ async with await self.locked_user_integrations(user_id):
+ if await self.get_creds_by_id(user_id, credentials.id):
raise ValueError(
f"Can not re-create existing credentials #{credentials.id} "
f"for user #{user_id}"
)
- self._set_user_integration_creds(
- user_id, [*self.get_all_creds(user_id), credentials]
+ await self._set_user_integration_creds(
+ user_id, [*(await self.get_all_creds(user_id)), credentials]
)
- def get_all_creds(self, user_id: str) -> list[Credentials]:
- users_credentials = self._get_user_integrations(user_id).credentials
+ async def get_all_creds(self, user_id: str) -> list[Credentials]:
+ users_credentials = (await self._get_user_integrations(user_id)).credentials
all_credentials = users_credentials
# These will always be added
all_credentials.append(ollama_credentials)
@@ -294,21 +301,25 @@ class IntegrationCredentialsStore:
all_credentials.append(google_maps_credentials)
return all_credentials
- def get_creds_by_id(self, user_id: str, credentials_id: str) -> Credentials | None:
- all_credentials = self.get_all_creds(user_id)
+ async def get_creds_by_id(
+ self, user_id: str, credentials_id: str
+ ) -> Credentials | None:
+ all_credentials = await self.get_all_creds(user_id)
return next((c for c in all_credentials if c.id == credentials_id), None)
- def get_creds_by_provider(self, user_id: str, provider: str) -> list[Credentials]:
- credentials = self.get_all_creds(user_id)
+ async def get_creds_by_provider(
+ self, user_id: str, provider: str
+ ) -> list[Credentials]:
+ credentials = await self.get_all_creds(user_id)
return [c for c in credentials if c.provider == provider]
- def get_authorized_providers(self, user_id: str) -> list[str]:
- credentials = self.get_all_creds(user_id)
+ async def get_authorized_providers(self, user_id: str) -> list[str]:
+ credentials = await self.get_all_creds(user_id)
return list(set(c.provider for c in credentials))
- def update_creds(self, user_id: str, updated: Credentials) -> None:
- with self.locked_user_integrations(user_id):
- current = self.get_creds_by_id(user_id, updated.id)
+ async def update_creds(self, user_id: str, updated: Credentials) -> None:
+ async with await self.locked_user_integrations(user_id):
+ current = await self.get_creds_by_id(user_id, updated.id)
if not current:
raise ValueError(
f"Credentials with ID {updated.id} "
@@ -336,18 +347,18 @@ class IntegrationCredentialsStore:
# Update the credentials
updated_credentials_list = [
updated if c.id == updated.id else c
- for c in self.get_all_creds(user_id)
+ for c in await self.get_all_creds(user_id)
]
- self._set_user_integration_creds(user_id, updated_credentials_list)
+ await self._set_user_integration_creds(user_id, updated_credentials_list)
- def delete_creds_by_id(self, user_id: str, credentials_id: str) -> None:
- with self.locked_user_integrations(user_id):
+ async def delete_creds_by_id(self, user_id: str, credentials_id: str) -> None:
+ async with await self.locked_user_integrations(user_id):
filtered_credentials = [
- c for c in self.get_all_creds(user_id) if c.id != credentials_id
+ c for c in await self.get_all_creds(user_id) if c.id != credentials_id
]
- self._set_user_integration_creds(user_id, filtered_credentials)
+ await self._set_user_integration_creds(user_id, filtered_credentials)
- def store_state_token(
+ async def store_state_token(
self, user_id: str, provider: str, scopes: list[str], use_pkce: bool = False
) -> tuple[str, str]:
token = secrets.token_urlsafe(32)
@@ -363,14 +374,14 @@ class IntegrationCredentialsStore:
scopes=scopes,
)
- with self.locked_user_integrations(user_id):
+ async with await self.locked_user_integrations(user_id):
- user_integrations = self._get_user_integrations(user_id)
+ user_integrations = await self._get_user_integrations(user_id)
oauth_states = user_integrations.oauth_states
oauth_states.append(state)
user_integrations.oauth_states = oauth_states
- self.db_manager.update_user_integrations(
+ await self.db_manager.update_user_integrations(
user_id=user_id, data=user_integrations
)
@@ -386,11 +397,11 @@ class IntegrationCredentialsStore:
code_challenge = base64.urlsafe_b64encode(sha256_hash).decode("utf-8")
return code_challenge.replace("=", ""), code_verifier
- def verify_state_token(
+ async def verify_state_token(
self, user_id: str, token: str, provider: str
) -> Optional[OAuthState]:
- with self.locked_user_integrations(user_id):
- user_integrations = self._get_user_integrations(user_id)
+ async with await self.locked_user_integrations(user_id):
+ user_integrations = await self._get_user_integrations(user_id)
oauth_states = user_integrations.oauth_states
now = datetime.now(timezone.utc)
@@ -398,7 +409,7 @@ class IntegrationCredentialsStore:
(
state
for state in oauth_states
- if state.token == token
+ if secrets.compare_digest(state.token, token)
and state.provider == provider
and state.expires_at > now.timestamp()
),
@@ -409,26 +420,26 @@ class IntegrationCredentialsStore:
# Remove the used state
oauth_states.remove(valid_state)
user_integrations.oauth_states = oauth_states
- self.db_manager.update_user_integrations(user_id, user_integrations)
+ await self.db_manager.update_user_integrations(
+ user_id, user_integrations
+ )
return valid_state
return None
- def _set_user_integration_creds(
+ async def _set_user_integration_creds(
self, user_id: str, credentials: list[Credentials]
) -> None:
- integrations = self._get_user_integrations(user_id)
+ integrations = await self._get_user_integrations(user_id)
# Remove default credentials from the list
credentials = [c for c in credentials if c not in DEFAULT_CREDENTIALS]
integrations.credentials = credentials
- self.db_manager.update_user_integrations(user_id, integrations)
+ await self.db_manager.update_user_integrations(user_id, integrations)
- def _get_user_integrations(self, user_id: str) -> UserIntegrations:
- integrations: UserIntegrations = self.db_manager.get_user_integrations(
- user_id=user_id
- )
- return integrations
+ async def _get_user_integrations(self, user_id: str) -> UserIntegrations:
+ return await self.db_manager.get_user_integrations(user_id=user_id)
- def locked_user_integrations(self, user_id: str):
+ async def locked_user_integrations(self, user_id: str):
key = (f"user:{user_id}", "integrations")
- return self.locks.locked(key)
+ locks = await self.locks()
+ return locks.locked(key)
diff --git a/autogpt_platform/backend/backend/integrations/creds_manager.py b/autogpt_platform/backend/backend/integrations/creds_manager.py
index eb5e132503..bacc3a53e9 100644
--- a/autogpt_platform/backend/backend/integrations/creds_manager.py
+++ b/autogpt_platform/backend/backend/integrations/creds_manager.py
@@ -1,13 +1,13 @@
import logging
-from contextlib import contextmanager
+from contextlib import asynccontextmanager
from datetime import datetime
-from typing import TYPE_CHECKING, Callable
+from typing import TYPE_CHECKING, Any, Callable, Coroutine
-from autogpt_libs.utils.synchronize import RedisKeyedMutex
-from redis.lock import Lock as RedisLock
+from autogpt_libs.utils.synchronize import AsyncRedisKeyedMutex
+from redis.asyncio.lock import Lock as AsyncRedisLock
-from backend.data import redis
from backend.data.model import Credentials, OAuth2Credentials
+from backend.data.redis import get_redis_async
from backend.integrations.credentials_store import IntegrationCredentialsStore
from backend.integrations.oauth import HANDLERS_BY_NAME
from backend.integrations.providers import ProviderName
@@ -54,20 +54,26 @@ class IntegrationCredentialsManager:
"""
def __init__(self):
- redis_conn = redis.get_redis()
- self._locks = RedisKeyedMutex(redis_conn)
self.store = IntegrationCredentialsStore()
+ self._locks = None
- def create(self, user_id: str, credentials: Credentials) -> None:
- return self.store.add_creds(user_id, credentials)
+ async def locks(self) -> AsyncRedisKeyedMutex:
+ if self._locks:
+ return self._locks
- def exists(self, user_id: str, credentials_id: str) -> bool:
- return self.store.get_creds_by_id(user_id, credentials_id) is not None
+ self._locks = AsyncRedisKeyedMutex(await get_redis_async())
+ return self._locks
- def get(
+ async def create(self, user_id: str, credentials: Credentials) -> None:
+ return await self.store.add_creds(user_id, credentials)
+
+ async def exists(self, user_id: str, credentials_id: str) -> bool:
+ return (await self.store.get_creds_by_id(user_id, credentials_id)) is not None
+
+ async def get(
self, user_id: str, credentials_id: str, lock: bool = True
) -> Credentials | None:
- credentials = self.store.get_creds_by_id(user_id, credentials_id)
+ credentials = await self.store.get_creds_by_id(user_id, credentials_id)
if not credentials:
return None
@@ -78,15 +84,15 @@ class IntegrationCredentialsManager:
f"{datetime.fromtimestamp(credentials.access_token_expires_at)}; "
f"current time is {datetime.now()}"
)
- credentials = self.refresh_if_needed(user_id, credentials, lock)
+ credentials = await self.refresh_if_needed(user_id, credentials, lock)
else:
logger.debug(f"Credentials #{credentials.id} never expire")
return credentials
- def acquire(
+ async def acquire(
self, user_id: str, credentials_id: str
- ) -> tuple[Credentials, RedisLock]:
+ ) -> tuple[Credentials, AsyncRedisLock]:
"""
⚠️ WARNING: this locks credentials system-wide and blocks both acquiring
and updating them elsewhere until the lock is released.
@@ -94,23 +100,25 @@ class IntegrationCredentialsManager:
"""
# Use a low-priority (!time_sensitive) locking queue on top of the general lock
# to allow priority access for refreshing/updating the tokens.
- with self._locked(user_id, credentials_id, "!time_sensitive"):
- lock = self._acquire_lock(user_id, credentials_id)
- credentials = self.get(user_id, credentials_id, lock=False)
+ async with self._locked(user_id, credentials_id, "!time_sensitive"):
+ lock = await self._acquire_lock(user_id, credentials_id)
+ credentials = await self.get(user_id, credentials_id, lock=False)
if not credentials:
raise ValueError(
f"Credentials #{credentials_id} for user #{user_id} not found"
)
return credentials, lock
- def cached_getter(self, user_id: str) -> Callable[[str], "Credentials | None"]:
+ def cached_getter(
+ self, user_id: str
+ ) -> Callable[[str], "Coroutine[Any, Any, Credentials | None]"]:
all_credentials = None
- def get_credentials(creds_id: str) -> "Credentials | None":
+ async def get_credentials(creds_id: str) -> "Credentials | None":
nonlocal all_credentials
if not all_credentials:
# Fetch credentials on first necessity
- all_credentials = self.store.get_all_creds(user_id)
+ all_credentials = await self.store.get_all_creds(user_id)
credential = next((c for c in all_credentials if c.id == creds_id), None)
if not credential:
@@ -120,15 +128,15 @@ class IntegrationCredentialsManager:
return credential
# Credential is OAuth2 credential and has expiration timestamp
- return self.refresh_if_needed(user_id, credential)
+ return await self.refresh_if_needed(user_id, credential)
return get_credentials
- def refresh_if_needed(
+ async def refresh_if_needed(
self, user_id: str, credentials: OAuth2Credentials, lock: bool = True
) -> OAuth2Credentials:
- with self._locked(user_id, credentials.id, "refresh"):
- oauth_handler = _get_provider_oauth_handler(credentials.provider)
+ async with self._locked(user_id, credentials.id, "refresh"):
+ oauth_handler = await _get_provider_oauth_handler(credentials.provider)
if oauth_handler.needs_refresh(credentials):
logger.debug(
f"Refreshing '{credentials.provider}' "
@@ -137,50 +145,53 @@ class IntegrationCredentialsManager:
_lock = None
if lock:
# Wait until the credentials are no longer in use anywhere
- _lock = self._acquire_lock(user_id, credentials.id)
+ _lock = await self._acquire_lock(user_id, credentials.id)
- fresh_credentials = oauth_handler.refresh_tokens(credentials)
- self.store.update_creds(user_id, fresh_credentials)
- if _lock and _lock.locked() and _lock.owned():
- _lock.release()
+ fresh_credentials = await oauth_handler.refresh_tokens(credentials)
+ await self.store.update_creds(user_id, fresh_credentials)
+ if _lock and (await _lock.locked()) and (await _lock.owned()):
+ await _lock.release()
credentials = fresh_credentials
return credentials
- def update(self, user_id: str, updated: Credentials) -> None:
- with self._locked(user_id, updated.id):
- self.store.update_creds(user_id, updated)
+ async def update(self, user_id: str, updated: Credentials) -> None:
+ async with self._locked(user_id, updated.id):
+ await self.store.update_creds(user_id, updated)
- def delete(self, user_id: str, credentials_id: str) -> None:
- with self._locked(user_id, credentials_id):
- self.store.delete_creds_by_id(user_id, credentials_id)
+ async def delete(self, user_id: str, credentials_id: str) -> None:
+ async with self._locked(user_id, credentials_id):
+ await self.store.delete_creds_by_id(user_id, credentials_id)
# -- Locking utilities -- #
- def _acquire_lock(self, user_id: str, credentials_id: str, *args: str) -> RedisLock:
+ async def _acquire_lock(
+ self, user_id: str, credentials_id: str, *args: str
+ ) -> AsyncRedisLock:
key = (
f"user:{user_id}",
f"credentials:{credentials_id}",
*args,
)
- return self._locks.acquire(key)
+ locks = await self.locks()
+ return await locks.acquire(key)
- @contextmanager
- def _locked(self, user_id: str, credentials_id: str, *args: str):
- lock = self._acquire_lock(user_id, credentials_id, *args)
+ @asynccontextmanager
+ async def _locked(self, user_id: str, credentials_id: str, *args: str):
+ lock = await self._acquire_lock(user_id, credentials_id, *args)
try:
yield
finally:
- if lock.locked() and lock.owned():
- lock.release()
+ if (await lock.locked()) and (await lock.owned()):
+ await lock.release()
- def release_all_locks(self):
+ async def release_all_locks(self):
"""Call this on process termination to ensure all locks are released"""
- self._locks.release_all_locks()
- self.store.locks.release_all_locks()
+ await (await self.locks()).release_all_locks()
+ await (await self.store.locks()).release_all_locks()
-def _get_provider_oauth_handler(provider_name_str: str) -> "BaseOAuthHandler":
+async def _get_provider_oauth_handler(provider_name_str: str) -> "BaseOAuthHandler":
provider_name = ProviderName(provider_name_str)
if provider_name not in HANDLERS_BY_NAME:
raise KeyError(f"Unknown provider '{provider_name}'")
diff --git a/autogpt_platform/backend/backend/integrations/oauth/base.py b/autogpt_platform/backend/backend/integrations/oauth/base.py
index fc6c68c161..b8d08582b2 100644
--- a/autogpt_platform/backend/backend/integrations/oauth/base.py
+++ b/autogpt_platform/backend/backend/integrations/oauth/base.py
@@ -32,7 +32,7 @@ class BaseOAuthHandler(ABC):
@abstractmethod
# --8<-- [start:BaseOAuthHandler4]
- def exchange_code_for_tokens(
+ async def exchange_code_for_tokens(
self, code: str, scopes: list[str], code_verifier: Optional[str]
) -> OAuth2Credentials:
# --8<-- [end:BaseOAuthHandler4]
@@ -41,31 +41,33 @@ class BaseOAuthHandler(ABC):
@abstractmethod
# --8<-- [start:BaseOAuthHandler5]
- def _refresh_tokens(self, credentials: OAuth2Credentials) -> OAuth2Credentials:
+ async def _refresh_tokens(
+ self, credentials: OAuth2Credentials
+ ) -> OAuth2Credentials:
# --8<-- [end:BaseOAuthHandler5]
"""Implements the token refresh mechanism"""
...
@abstractmethod
# --8<-- [start:BaseOAuthHandler6]
- def revoke_tokens(self, credentials: OAuth2Credentials) -> bool:
+ async def revoke_tokens(self, credentials: OAuth2Credentials) -> bool:
# --8<-- [end:BaseOAuthHandler6]
"""Revokes the given token at provider,
returns False provider does not support it"""
...
- def refresh_tokens(self, credentials: OAuth2Credentials) -> OAuth2Credentials:
+ async def refresh_tokens(self, credentials: OAuth2Credentials) -> OAuth2Credentials:
if credentials.provider != self.PROVIDER_NAME:
raise ValueError(
f"{self.__class__.__name__} can not refresh tokens "
f"for other provider '{credentials.provider}'"
)
- return self._refresh_tokens(credentials)
+ return await self._refresh_tokens(credentials)
- def get_access_token(self, credentials: OAuth2Credentials) -> str:
+ async def get_access_token(self, credentials: OAuth2Credentials) -> str:
"""Returns a valid access token, refreshing it first if needed"""
if self.needs_refresh(credentials):
- credentials = self.refresh_tokens(credentials)
+ credentials = await self.refresh_tokens(credentials)
return credentials.access_token.get_secret_value()
def needs_refresh(self, credentials: OAuth2Credentials) -> bool:
diff --git a/autogpt_platform/backend/backend/integrations/oauth/github.py b/autogpt_platform/backend/backend/integrations/oauth/github.py
index e6b3db37b4..ebec116660 100644
--- a/autogpt_platform/backend/backend/integrations/oauth/github.py
+++ b/autogpt_platform/backend/backend/integrations/oauth/github.py
@@ -4,7 +4,7 @@ from urllib.parse import urlencode
from backend.data.model import OAuth2Credentials
from backend.integrations.providers import ProviderName
-from backend.util.request import requests
+from backend.util.request import Requests
from .base import BaseOAuthHandler
@@ -45,12 +45,14 @@ class GitHubOAuthHandler(BaseOAuthHandler):
}
return f"{self.auth_base_url}?{urlencode(params)}"
- def exchange_code_for_tokens(
+ async def exchange_code_for_tokens(
self, code: str, scopes: list[str], code_verifier: Optional[str]
) -> OAuth2Credentials:
- return self._request_tokens({"code": code, "redirect_uri": self.redirect_uri})
+ return await self._request_tokens(
+ {"code": code, "redirect_uri": self.redirect_uri}
+ )
- def revoke_tokens(self, credentials: OAuth2Credentials) -> bool:
+ async def revoke_tokens(self, credentials: OAuth2Credentials) -> bool:
if not credentials.access_token:
raise ValueError("No access token to revoke")
@@ -59,7 +61,7 @@ class GitHubOAuthHandler(BaseOAuthHandler):
"X-GitHub-Api-Version": "2022-11-28",
}
- requests.delete(
+ await Requests().delete(
url=self.revoke_url.format(client_id=self.client_id),
auth=(self.client_id, self.client_secret),
headers=headers,
@@ -67,18 +69,20 @@ class GitHubOAuthHandler(BaseOAuthHandler):
)
return True
- def _refresh_tokens(self, credentials: OAuth2Credentials) -> OAuth2Credentials:
+ async def _refresh_tokens(
+ self, credentials: OAuth2Credentials
+ ) -> OAuth2Credentials:
if not credentials.refresh_token:
return credentials
- return self._request_tokens(
+ return await self._request_tokens(
{
"refresh_token": credentials.refresh_token.get_secret_value(),
"grant_type": "refresh_token",
}
)
- def _request_tokens(
+ async def _request_tokens(
self,
params: dict[str, str],
current_credentials: Optional[OAuth2Credentials] = None,
@@ -89,10 +93,12 @@ class GitHubOAuthHandler(BaseOAuthHandler):
**params,
}
headers = {"Accept": "application/json"}
- response = requests.post(self.token_url, data=request_body, headers=headers)
+ response = await Requests().post(
+ self.token_url, data=request_body, headers=headers
+ )
token_data: dict = response.json()
- username = self._request_username(token_data["access_token"])
+ username = await self._request_username(token_data["access_token"])
now = int(time.time())
new_credentials = OAuth2Credentials(
@@ -124,7 +130,7 @@ class GitHubOAuthHandler(BaseOAuthHandler):
new_credentials.id = current_credentials.id
return new_credentials
- def _request_username(self, access_token: str) -> str | None:
+ async def _request_username(self, access_token: str) -> str | None:
url = "https://api.github.com/user"
headers = {
"Accept": "application/vnd.github+json",
@@ -132,13 +138,14 @@ class GitHubOAuthHandler(BaseOAuthHandler):
"X-GitHub-Api-Version": "2022-11-28",
}
- response = requests.get(url, headers=headers)
+ response = await Requests().get(url, headers=headers)
if not response.ok:
return None
# Get the login (username)
- return response.json().get("login")
+ resp = response.json()
+ return resp.get("login")
# --8<-- [end:GithubOAuthHandlerExample]
diff --git a/autogpt_platform/backend/backend/integrations/oauth/google.py b/autogpt_platform/backend/backend/integrations/oauth/google.py
index 310eb5ae73..bba2bc71c5 100644
--- a/autogpt_platform/backend/backend/integrations/oauth/google.py
+++ b/autogpt_platform/backend/backend/integrations/oauth/google.py
@@ -54,7 +54,7 @@ class GoogleOAuthHandler(BaseOAuthHandler):
)
return authorization_url
- def exchange_code_for_tokens(
+ async def exchange_code_for_tokens(
self, code: str, scopes: list[str], code_verifier: Optional[str]
) -> OAuth2Credentials:
logger.debug(f"Exchanging code for tokens with scopes: {scopes}")
@@ -76,7 +76,7 @@ class GoogleOAuthHandler(BaseOAuthHandler):
logger.debug(f"Scopes granted by Google: {granted_scopes}")
google_creds = flow.credentials
- logger.debug(f"Received credentials: {google_creds}")
+ logger.debug("Received credentials")
logger.debug("Requesting user email")
username = self._request_email(google_creds)
@@ -106,7 +106,7 @@ class GoogleOAuthHandler(BaseOAuthHandler):
return credentials
- def revoke_tokens(self, credentials: OAuth2Credentials) -> bool:
+ async def revoke_tokens(self, credentials: OAuth2Credentials) -> bool:
session = AuthorizedSession(credentials)
session.post(
self.revoke_uri,
@@ -127,7 +127,9 @@ class GoogleOAuthHandler(BaseOAuthHandler):
return None
return response.json()["email"]
- def _refresh_tokens(self, credentials: OAuth2Credentials) -> OAuth2Credentials:
+ async def _refresh_tokens(
+ self, credentials: OAuth2Credentials
+ ) -> OAuth2Credentials:
# Google credentials should ALWAYS have a refresh token
assert credentials.refresh_token
diff --git a/autogpt_platform/backend/backend/integrations/oauth/linear.py b/autogpt_platform/backend/backend/integrations/oauth/linear.py
index fd9d379c1e..09e3c6d537 100644
--- a/autogpt_platform/backend/backend/integrations/oauth/linear.py
+++ b/autogpt_platform/backend/backend/integrations/oauth/linear.py
@@ -7,7 +7,7 @@ from pydantic import SecretStr
from backend.blocks.linear._api import LinearAPIException
from backend.data.model import APIKeyCredentials, OAuth2Credentials
from backend.integrations.providers import ProviderName
-from backend.util.request import requests
+from backend.util.request import Requests
from .base import BaseOAuthHandler
@@ -40,12 +40,14 @@ class LinearOAuthHandler(BaseOAuthHandler):
}
return f"{self.auth_base_url}?{urlencode(params)}"
- def exchange_code_for_tokens(
+ async def exchange_code_for_tokens(
self, code: str, scopes: list[str], code_verifier: Optional[str]
) -> OAuth2Credentials:
- return self._request_tokens({"code": code, "redirect_uri": self.redirect_uri})
+ return await self._request_tokens(
+ {"code": code, "redirect_uri": self.redirect_uri}
+ )
- def revoke_tokens(self, credentials: OAuth2Credentials) -> bool:
+ async def revoke_tokens(self, credentials: OAuth2Credentials) -> bool:
if not credentials.access_token:
raise ValueError("No access token to revoke")
@@ -53,7 +55,7 @@ class LinearOAuthHandler(BaseOAuthHandler):
"Authorization": f"Bearer {credentials.access_token.get_secret_value()}"
}
- response = requests.post(self.revoke_url, headers=headers)
+ response = await Requests().post(self.revoke_url, headers=headers)
if not response.ok:
try:
error_data = response.json()
@@ -61,26 +63,28 @@ class LinearOAuthHandler(BaseOAuthHandler):
except json.JSONDecodeError:
error_message = response.text
raise LinearAPIException(
- f"Failed to revoke Linear tokens ({response.status_code}): {error_message}",
- response.status_code,
+ f"Failed to revoke Linear tokens ({response.status}): {error_message}",
+ response.status,
)
return True # Linear doesn't return JSON on successful revoke
- def _refresh_tokens(self, credentials: OAuth2Credentials) -> OAuth2Credentials:
+ async def _refresh_tokens(
+ self, credentials: OAuth2Credentials
+ ) -> OAuth2Credentials:
if not credentials.refresh_token:
raise ValueError(
"No refresh token available."
) # Linear uses non-expiring tokens
- return self._request_tokens(
+ return await self._request_tokens(
{
"refresh_token": credentials.refresh_token.get_secret_value(),
"grant_type": "refresh_token",
}
)
- def _request_tokens(
+ async def _request_tokens(
self,
params: dict[str, str],
current_credentials: Optional[OAuth2Credentials] = None,
@@ -95,18 +99,19 @@ class LinearOAuthHandler(BaseOAuthHandler):
headers = {
"Content-Type": "application/x-www-form-urlencoded"
} # Correct header for token request
- response = requests.post(self.token_url, data=request_body, headers=headers)
+ response = await Requests().post(
+ self.token_url, data=request_body, headers=headers
+ )
if not response.ok:
try:
error_data = response.json()
error_message = error_data.get("error", "Unknown error")
-
except json.JSONDecodeError:
error_message = response.text
raise LinearAPIException(
- f"Failed to fetch Linear tokens ({response.status_code}): {error_message}",
- response.status_code,
+ f"Failed to fetch Linear tokens ({response.status}): {error_message}",
+ response.status,
)
token_data = response.json()
@@ -132,13 +137,11 @@ class LinearOAuthHandler(BaseOAuthHandler):
new_credentials.id = current_credentials.id
return new_credentials
- def _request_username(self, access_token: str) -> Optional[str]:
-
+ async def _request_username(self, access_token: str) -> Optional[str]:
# Use the LinearClient to fetch user details using GraphQL
from backend.blocks.linear._api import LinearClient
try:
-
linear_client = LinearClient(
APIKeyCredentials(
api_key=SecretStr(access_token),
@@ -156,10 +159,9 @@ class LinearOAuthHandler(BaseOAuthHandler):
}
"""
- response = linear_client.query(query)
+ response = await linear_client.query(query)
return response["viewer"]["name"]
except Exception as e: # Handle any errors
-
print(f"Error fetching username: {e}")
return None
diff --git a/autogpt_platform/backend/backend/integrations/oauth/notion.py b/autogpt_platform/backend/backend/integrations/oauth/notion.py
index 3cd3249fef..67fc5bcc25 100644
--- a/autogpt_platform/backend/backend/integrations/oauth/notion.py
+++ b/autogpt_platform/backend/backend/integrations/oauth/notion.py
@@ -4,7 +4,7 @@ from urllib.parse import urlencode
from backend.data.model import OAuth2Credentials
from backend.integrations.providers import ProviderName
-from backend.util.request import requests
+from backend.util.request import Requests
from .base import BaseOAuthHandler
@@ -39,7 +39,7 @@ class NotionOAuthHandler(BaseOAuthHandler):
}
return f"{self.auth_base_url}?{urlencode(params)}"
- def exchange_code_for_tokens(
+ async def exchange_code_for_tokens(
self, code: str, scopes: list[str], code_verifier: Optional[str]
) -> OAuth2Credentials:
request_body = {
@@ -52,7 +52,9 @@ class NotionOAuthHandler(BaseOAuthHandler):
"Authorization": f"Basic {auth_str}",
"Accept": "application/json",
}
- response = requests.post(self.token_url, json=request_body, headers=headers)
+ response = await Requests().post(
+ self.token_url, json=request_body, headers=headers
+ )
token_data = response.json()
# Email is only available for non-bot users
email = (
@@ -80,11 +82,13 @@ class NotionOAuthHandler(BaseOAuthHandler):
},
)
- def revoke_tokens(self, credentials: OAuth2Credentials) -> bool:
+ async def revoke_tokens(self, credentials: OAuth2Credentials) -> bool:
# Notion doesn't support token revocation
return False
- def _refresh_tokens(self, credentials: OAuth2Credentials) -> OAuth2Credentials:
+ async def _refresh_tokens(
+ self, credentials: OAuth2Credentials
+ ) -> OAuth2Credentials:
# Notion doesn't support token refresh
return credentials
diff --git a/autogpt_platform/backend/backend/integrations/oauth/todoist.py b/autogpt_platform/backend/backend/integrations/oauth/todoist.py
index 543a7de84b..66d34f95e8 100644
--- a/autogpt_platform/backend/backend/integrations/oauth/todoist.py
+++ b/autogpt_platform/backend/backend/integrations/oauth/todoist.py
@@ -1,10 +1,9 @@
import urllib.parse
from typing import ClassVar, Optional
-import requests
-
from backend.data.model import OAuth2Credentials, ProviderName
from backend.integrations.oauth.base import BaseOAuthHandler
+from backend.util.request import Requests
class TodoistOAuthHandler(BaseOAuthHandler):
@@ -36,7 +35,7 @@ class TodoistOAuthHandler(BaseOAuthHandler):
return f"{self.AUTHORIZE_URL}?{urllib.parse.urlencode(params)}"
- def exchange_code_for_tokens(
+ async def exchange_code_for_tokens(
self, code: str, scopes: list[str], code_verifier: Optional[str]
) -> OAuth2Credentials:
"""Exchange authorization code for access tokens"""
@@ -48,17 +47,14 @@ class TodoistOAuthHandler(BaseOAuthHandler):
"redirect_uri": self.redirect_uri,
}
- response = requests.post(self.TOKEN_URL, data=data)
- response.raise_for_status()
-
+ response = await Requests().post(self.TOKEN_URL, data=data)
tokens = response.json()
- response = requests.post(
+ response = await Requests().post(
"https://api.todoist.com/sync/v9/sync",
headers={"Authorization": f"Bearer {tokens['access_token']}"},
data={"sync_token": "*", "resource_types": '["user"]'},
)
- response.raise_for_status()
user_info = response.json()
user_email = user_info["user"].get("email")
@@ -73,9 +69,11 @@ class TodoistOAuthHandler(BaseOAuthHandler):
scopes=scopes,
)
- def _refresh_tokens(self, credentials: OAuth2Credentials) -> OAuth2Credentials:
+ async def _refresh_tokens(
+ self, credentials: OAuth2Credentials
+ ) -> OAuth2Credentials:
# Todoist does not support token refresh
return credentials
- def revoke_tokens(self, credentials: OAuth2Credentials) -> bool:
+ async def revoke_tokens(self, credentials: OAuth2Credentials) -> bool:
return False
diff --git a/autogpt_platform/backend/backend/integrations/oauth/twitter.py b/autogpt_platform/backend/backend/integrations/oauth/twitter.py
index 519ccd354e..486c14a210 100644
--- a/autogpt_platform/backend/backend/integrations/oauth/twitter.py
+++ b/autogpt_platform/backend/backend/integrations/oauth/twitter.py
@@ -2,10 +2,9 @@ import time
import urllib.parse
from typing import ClassVar, Optional
-import requests
-
from backend.data.model import OAuth2Credentials, ProviderName
from backend.integrations.oauth.base import BaseOAuthHandler
+from backend.util.request import Requests
class TwitterOAuthHandler(BaseOAuthHandler):
@@ -62,7 +61,7 @@ class TwitterOAuthHandler(BaseOAuthHandler):
return f"{self.AUTHORIZE_URL}?{urllib.parse.urlencode(params)}"
- def exchange_code_for_tokens(
+ async def exchange_code_for_tokens(
self, code: str, scopes: list[str], code_verifier: Optional[str]
) -> OAuth2Credentials:
"""Exchange authorization code for access tokens"""
@@ -78,12 +77,12 @@ class TwitterOAuthHandler(BaseOAuthHandler):
auth = (self.client_id, self.client_secret)
- response = requests.post(self.TOKEN_URL, headers=headers, data=data, auth=auth)
- response.raise_for_status()
-
+ response = await Requests().post(
+ self.TOKEN_URL, headers=headers, data=data, auth=auth
+ )
tokens = response.json()
- username = self._get_username(tokens["access_token"])
+ username = await self._get_username(tokens["access_token"])
return OAuth2Credentials(
provider=self.PROVIDER_NAME,
@@ -96,20 +95,21 @@ class TwitterOAuthHandler(BaseOAuthHandler):
scopes=scopes,
)
- def _get_username(self, access_token: str) -> str:
+ async def _get_username(self, access_token: str) -> str:
"""Get the username from the access token"""
headers = {"Authorization": f"Bearer {access_token}"}
params = {"user.fields": "username"}
- response = requests.get(
+ response = await Requests().get(
f"{self.USERNAME_URL}?{urllib.parse.urlencode(params)}", headers=headers
)
- response.raise_for_status()
return response.json()["data"]["username"]
- def _refresh_tokens(self, credentials: OAuth2Credentials) -> OAuth2Credentials:
+ 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")
@@ -122,18 +122,19 @@ class TwitterOAuthHandler(BaseOAuthHandler):
auth = (self.client_id, self.client_secret)
- response = requests.post(self.TOKEN_URL, headers=header, data=data, auth=auth)
+ response = await Requests().post(
+ self.TOKEN_URL, headers=header, data=data, auth=auth
+ )
- try:
- response.raise_for_status()
- except requests.exceptions.HTTPError as e:
- print("HTTP Error:", e)
- print("Response Content:", response.text)
- raise
+ if not response.ok:
+ error_text = response.text
+ print("HTTP Error:", response.status)
+ print("Response Content:", error_text)
+ raise ValueError(f"HTTP Error: {response.status} - {error_text}")
tokens = response.json()
- username = self._get_username(tokens["access_token"])
+ username = await self._get_username(tokens["access_token"])
return OAuth2Credentials(
id=credentials.id,
@@ -147,7 +148,7 @@ class TwitterOAuthHandler(BaseOAuthHandler):
refresh_token_expires_at=None,
)
- def revoke_tokens(self, credentials: OAuth2Credentials) -> bool:
+ async def revoke_tokens(self, credentials: OAuth2Credentials) -> bool:
"""Revoke the access token"""
header = {"Content-Type": "application/x-www-form-urlencoded"}
@@ -159,13 +160,14 @@ class TwitterOAuthHandler(BaseOAuthHandler):
auth = (self.client_id, self.client_secret)
- response = requests.post(self.REVOKE_URL, headers=header, data=data, auth=auth)
+ response = await Requests().post(
+ self.REVOKE_URL, headers=header, data=data, auth=auth
+ )
- try:
- response.raise_for_status()
- except requests.exceptions.HTTPError as e:
- print("HTTP Error:", e)
- print("Response Content:", response.text)
- raise
+ if not response.ok:
+ error_text = response.text
+ print("HTTP Error:", response.status)
+ print("Response Content:", error_text)
+ raise ValueError(f"HTTP Error: {response.status} - {error_text}")
- return response.status_code == 200
+ return response.ok
diff --git a/autogpt_platform/backend/backend/integrations/webhooks/github.py b/autogpt_platform/backend/backend/integrations/webhooks/github.py
index 6a39192045..5d2977cacc 100644
--- a/autogpt_platform/backend/backend/integrations/webhooks/github.py
+++ b/autogpt_platform/backend/backend/integrations/webhooks/github.py
@@ -2,13 +2,13 @@ import hashlib
import hmac
import logging
-import requests
from fastapi import HTTPException, Request
from strenum import StrEnum
from backend.data import integrations
from backend.data.model import Credentials
from backend.integrations.providers import ProviderName
+from backend.util.request import Requests, Response
from ._base import BaseWebhooksManager
@@ -73,9 +73,9 @@ class GithubWebhooksManager(BaseWebhooksManager):
repo, github_hook_id = webhook.resource, webhook.provider_webhook_id
ping_url = f"{self.GITHUB_API_URL}/repos/{repo}/hooks/{github_hook_id}/pings"
- response = requests.post(ping_url, headers=headers)
+ response = await Requests().post(ping_url, headers=headers)
- if response.status_code != 204:
+ if response.status != 204:
error_msg = extract_github_error_msg(response)
raise ValueError(f"Failed to ping GitHub webhook: {error_msg}")
@@ -110,13 +110,13 @@ class GithubWebhooksManager(BaseWebhooksManager):
},
}
- response = requests.post(
+ response = await Requests().post(
f"{self.GITHUB_API_URL}/repos/{resource}/hooks",
headers=headers,
json=webhook_data,
)
- if response.status_code != 201:
+ if response.status != 201:
error_msg = extract_github_error_msg(response)
if "not found" in error_msg.lower():
error_msg = (
@@ -126,8 +126,9 @@ class GithubWebhooksManager(BaseWebhooksManager):
)
raise ValueError(f"Failed to create GitHub webhook: {error_msg}")
- webhook_id = response.json()["id"]
- config = response.json()["config"]
+ resp = response.json()
+ webhook_id = resp["id"]
+ config = resp["config"]
return str(webhook_id), config
@@ -153,9 +154,9 @@ class GithubWebhooksManager(BaseWebhooksManager):
f"Unsupported webhook type '{webhook.webhook_type}'"
)
- response = requests.delete(delete_url, headers=headers)
+ response = await Requests().delete(delete_url, headers=headers)
- if response.status_code not in [204, 404]:
+ if response.status not in [204, 404]:
# 204 means successful deletion, 404 means the webhook was already deleted
error_msg = extract_github_error_msg(response)
raise ValueError(f"Failed to delete GitHub webhook: {error_msg}")
@@ -166,7 +167,7 @@ class GithubWebhooksManager(BaseWebhooksManager):
# --8<-- [end:GithubWebhooksManager]
-def extract_github_error_msg(response: requests.Response) -> str:
+def extract_github_error_msg(response: Response) -> str:
error_msgs = []
resp = response.json()
if resp.get("message"):
diff --git a/autogpt_platform/backend/backend/integrations/webhooks/graph_lifecycle_hooks.py b/autogpt_platform/backend/backend/integrations/webhooks/graph_lifecycle_hooks.py
index 898c6772bb..01e7b3a49e 100644
--- a/autogpt_platform/backend/backend/integrations/webhooks/graph_lifecycle_hooks.py
+++ b/autogpt_platform/backend/backend/integrations/webhooks/graph_lifecycle_hooks.py
@@ -37,7 +37,7 @@ async def on_graph_activate(graph: "GraphModel", user_id: str):
)
)
and (creds_meta := new_node.input_default.get(creds_field_name))
- and not (node_credentials := get_credentials(creds_meta["id"]))
+ and not (node_credentials := await get_credentials(creds_meta["id"]))
):
raise ValueError(
f"Node #{new_node.id} input '{creds_field_name}' updated with "
@@ -74,7 +74,7 @@ async def on_graph_deactivate(graph: "GraphModel", user_id: str):
)
)
and (creds_meta := node.input_default.get(creds_field_name))
- and not (node_credentials := get_credentials(creds_meta["id"]))
+ and not (node_credentials := await get_credentials(creds_meta["id"]))
):
logger.error(
f"Node #{node.id} input '{creds_field_name}' referenced non-existent "
diff --git a/autogpt_platform/backend/backend/integrations/webhooks/slant3d.py b/autogpt_platform/backend/backend/integrations/webhooks/slant3d.py
index 189ab72083..bc0337d4c5 100644
--- a/autogpt_platform/backend/backend/integrations/webhooks/slant3d.py
+++ b/autogpt_platform/backend/backend/integrations/webhooks/slant3d.py
@@ -1,12 +1,12 @@
import logging
-import requests
from fastapi import Request
from backend.data import integrations
from backend.data.model import APIKeyCredentials, Credentials
from backend.integrations.providers import ProviderName
from backend.integrations.webhooks._base import BaseWebhooksManager
+from backend.util.request import Requests
logger = logging.getLogger(__name__)
@@ -39,7 +39,7 @@ class Slant3DWebhooksManager(BaseWebhooksManager):
# Slant3D's API doesn't use events list, just register for all order updates
payload = {"endPoint": ingress_url}
- response = requests.post(
+ response = await Requests().post(
f"{self.BASE_URL}/customer/webhookSubscribe", headers=headers, json=payload
)
diff --git a/autogpt_platform/backend/backend/notifications/notifications.py b/autogpt_platform/backend/backend/notifications/notifications.py
index 808a8cb699..dbbd8fe075 100644
--- a/autogpt_platform/backend/backend/notifications/notifications.py
+++ b/autogpt_platform/backend/backend/notifications/notifications.py
@@ -1,6 +1,6 @@
+import asyncio
import logging
-import time
-from concurrent.futures import ThreadPoolExecutor
+from concurrent.futures import ProcessPoolExecutor
from datetime import datetime, timedelta, timezone
from typing import Callable
@@ -39,9 +39,11 @@ from backend.data.user import generate_unsubscribe_link
from backend.notifications.email import EmailSender
from backend.util.logging import TruncatedLogger
from backend.util.metrics import discord_send_alert
+from backend.util.retry import continuous_retry
from backend.util.service import (
AppService,
AppServiceClient,
+ endpoint_to_sync,
expose,
get_service_client,
)
@@ -55,7 +57,7 @@ NOTIFICATION_EXCHANGE = Exchange(name="notifications", type=ExchangeType.TOPIC)
DEAD_LETTER_EXCHANGE = Exchange(name="dead_letter", type=ExchangeType.TOPIC)
EXCHANGES = [NOTIFICATION_EXCHANGE, DEAD_LETTER_EXCHANGE]
-background_executor = ThreadPoolExecutor(max_workers=2)
+background_executor = ProcessPoolExecutor(max_workers=2)
def create_notification_config() -> RabbitMQConfig:
@@ -231,9 +233,9 @@ class NotificationManager(AppService):
@expose
def queue_weekly_summary(self):
- background_executor.submit(self._queue_weekly_summary)
+ background_executor.submit(lambda: asyncio.run(self._queue_weekly_summary()))
- def _queue_weekly_summary(self):
+ async def _queue_weekly_summary(self):
"""Process weekly summary for specified notification types"""
try:
logger.info("Processing weekly summary queuing operation")
@@ -245,8 +247,7 @@ class NotificationManager(AppService):
start_time=start_time.isoformat(),
)
for user in users:
-
- self._queue_scheduled_notification(
+ await self._queue_scheduled_notification(
SummaryParamsEventModel(
user_id=user,
type=NotificationType.WEEKLY_SUMMARY,
@@ -387,10 +388,10 @@ class NotificationManager(AppService):
}
@expose
- def discord_system_alert(self, content: str):
- discord_send_alert(content)
+ async def discord_system_alert(self, content: str):
+ await discord_send_alert(content)
- def _queue_scheduled_notification(self, event: SummaryParamsEventModel):
+ async def _queue_scheduled_notification(self, event: SummaryParamsEventModel):
"""Queue a scheduled notification - exposed method for other services to call"""
try:
logger.debug(f"Received Request to queue scheduled notification {event=}")
@@ -399,12 +400,10 @@ class NotificationManager(AppService):
routing_key = get_routing_key(event.type)
# Publish to RabbitMQ
- self.run_and_wait(
- self.rabbit.publish_message(
- routing_key=routing_key,
- message=event.model_dump_json(),
- exchange=next(ex for ex in EXCHANGES if ex.name == exchange),
- )
+ await self.rabbit.publish_message(
+ routing_key=routing_key,
+ message=event.model_dump_json(),
+ exchange=next(ex for ex in EXCHANGES if ex.name == exchange),
)
except Exception as e:
@@ -695,7 +694,7 @@ class NotificationManager(AppService):
logger.exception(f"Error processing notification for summary queue: {e}")
return False
- def _run_queue(
+ async def _run_queue(
self,
queue: aio_pika.abc.AbstractQueue,
process_func: Callable[[str], bool],
@@ -704,12 +703,12 @@ class NotificationManager(AppService):
message: aio_pika.abc.AbstractMessage | None = None
try:
# This parameter "no_ack" is named like shit, think of it as "auto_ack"
- message = self.run_and_wait(queue.get(timeout=1.0, no_ack=False))
+ message = await queue.get(timeout=1.0, no_ack=False)
result = process_func(message.body.decode())
if result:
- self.run_and_wait(message.ack())
+ await message.ack()
else:
- self.run_and_wait(message.reject(requeue=False))
+ await message.reject(requeue=False)
except QueueEmpty:
logger.debug(f"Queue {error_queue_name} empty")
@@ -720,61 +719,58 @@ class NotificationManager(AppService):
logger.error(
f"Error in notification service loop, message rejected {e}"
)
- self.run_and_wait(message.reject(requeue=False))
+ await message.reject(requeue=False)
else:
logger.exception(
f"Error in notification service loop, message unable to be rejected, and will have to be manually removed to free space in the queue: {e=}"
)
+ @continuous_retry()
def run_service(self):
+ self.run_and_wait(self._run_service())
+
+ async def _run_service(self):
logger.info(f"[{self.service_name}] ⏳ Configuring RabbitMQ...")
self.rabbitmq_service = rabbitmq.AsyncRabbitMQ(self.rabbitmq_config)
- self.run_and_wait(self.rabbitmq_service.connect())
+ await self.rabbitmq_service.connect()
logger.info(f"[{self.service_name}] Started notification service")
# Set up queue consumers
- channel = self.run_and_wait(self.rabbit.get_channel())
+ channel = await self.rabbit.get_channel()
- immediate_queue = self.run_and_wait(
- channel.get_queue("immediate_notifications")
- )
- batch_queue = self.run_and_wait(channel.get_queue("batch_notifications"))
+ immediate_queue = await channel.get_queue("immediate_notifications")
+ batch_queue = await channel.get_queue("batch_notifications")
- admin_queue = self.run_and_wait(channel.get_queue("admin_notifications"))
+ admin_queue = await channel.get_queue("admin_notifications")
- summary_queue = self.run_and_wait(channel.get_queue("summary_notifications"))
+ summary_queue = await channel.get_queue("summary_notifications")
while self.running:
try:
- self._run_queue(
+ await self._run_queue(
queue=immediate_queue,
process_func=self._process_immediate,
error_queue_name="immediate_notifications",
)
- self._run_queue(
+ await self._run_queue(
queue=admin_queue,
process_func=self._process_admin_message,
error_queue_name="admin_notifications",
)
- self._run_queue(
+ await self._run_queue(
queue=batch_queue,
process_func=self._process_batch,
error_queue_name="batch_notifications",
)
-
- self._run_queue(
+ await self._run_queue(
queue=summary_queue,
process_func=self._process_summary,
error_queue_name="summary_notifications",
)
-
- time.sleep(0.1)
-
+ await asyncio.sleep(0.1)
except QueueEmpty as e:
logger.debug(f"Queue empty: {e}")
- except Exception as e:
- logger.error(f"Error in notification service loop: {e}")
def cleanup(self):
"""Cleanup service resources"""
@@ -791,4 +787,4 @@ class NotificationManagerClient(AppServiceClient):
process_existing_batches = NotificationManager.process_existing_batches
queue_weekly_summary = NotificationManager.queue_weekly_summary
- discord_system_alert = NotificationManager.discord_system_alert
+ discord_system_alert = endpoint_to_sync(NotificationManager.discord_system_alert)
diff --git a/autogpt_platform/backend/backend/server/external/api.py b/autogpt_platform/backend/backend/server/external/api.py
index 3236766fdd..8ed15c1385 100644
--- a/autogpt_platform/backend/backend/server/external/api.py
+++ b/autogpt_platform/backend/backend/server/external/api.py
@@ -1,5 +1,7 @@
from fastapi import FastAPI
+from backend.server.middleware.security import SecurityHeadersMiddleware
+
from .routes.v1 import v1_router
external_app = FastAPI(
@@ -8,4 +10,6 @@ external_app = FastAPI(
docs_url="/docs",
version="1.0",
)
+
+external_app.add_middleware(SecurityHeadersMiddleware)
external_app.include_router(v1_router, prefix="/v1")
diff --git a/autogpt_platform/backend/backend/server/external/routes/v1.py b/autogpt_platform/backend/backend/server/external/routes/v1.py
index 15fe8dc7ee..baf77c0e75 100644
--- a/autogpt_platform/backend/backend/server/external/routes/v1.py
+++ b/autogpt_platform/backend/backend/server/external/routes/v1.py
@@ -12,7 +12,7 @@ from backend.data import graph as graph_db
from backend.data.api_key import APIKey
from backend.data.block import BlockInput, CompletedBlockOutput
from backend.data.execution import NodeExecutionResult
-from backend.executor.utils import add_graph_execution_async
+from backend.executor.utils import add_graph_execution
from backend.server.external.middleware import require_permission
from backend.util.settings import Settings
@@ -71,7 +71,7 @@ def get_graph_blocks() -> Sequence[dict[Any, Any]]:
tags=["blocks"],
dependencies=[Depends(require_permission(APIKeyPermission.EXECUTE_BLOCK))],
)
-def execute_graph_block(
+async def execute_graph_block(
block_id: str,
data: BlockInput,
api_key: APIKey = Depends(require_permission(APIKeyPermission.EXECUTE_BLOCK)),
@@ -81,7 +81,7 @@ def execute_graph_block(
raise HTTPException(status_code=404, detail=f"Block #{block_id} not found.")
output = defaultdict(list)
- for name, data in obj.execute(data):
+ async for name, data in obj.execute(data):
output[name].append(data)
return output
@@ -97,7 +97,7 @@ async def execute_graph(
api_key: APIKey = Depends(require_permission(APIKeyPermission.EXECUTE_GRAPH)),
) -> dict[str, Any]:
try:
- graph_exec = await add_graph_execution_async(
+ graph_exec = await add_graph_execution(
graph_id=graph_id,
user_id=api_key.user_id,
inputs=node_input,
diff --git a/autogpt_platform/backend/backend/server/integrations/router.py b/autogpt_platform/backend/backend/server/integrations/router.py
index 4739bd8417..26f33eba37 100644
--- a/autogpt_platform/backend/backend/server/integrations/router.py
+++ b/autogpt_platform/backend/backend/server/integrations/router.py
@@ -15,7 +15,7 @@ from backend.data.integrations import (
wait_for_webhook_event,
)
from backend.data.model import Credentials, CredentialsType, OAuth2Credentials
-from backend.executor.utils import add_graph_execution_async
+from backend.executor.utils import add_graph_execution
from backend.integrations.creds_manager import IntegrationCredentialsManager
from backend.integrations.oauth import HANDLERS_BY_NAME
from backend.integrations.providers import ProviderName
@@ -41,7 +41,7 @@ class LoginResponse(BaseModel):
@router.get("/{provider}/login")
-def login(
+async def login(
provider: Annotated[
ProviderName, Path(title="The provider to initiate an OAuth flow for")
],
@@ -56,7 +56,7 @@ def login(
requested_scopes = scopes.split(",") if scopes else []
# Generate and store a secure random state token along with the scopes
- state_token, code_challenge = creds_manager.store.store_state_token(
+ state_token, code_challenge = await creds_manager.store.store_state_token(
user_id, provider, requested_scopes
)
login_url = handler.get_login_url(
@@ -76,7 +76,7 @@ class CredentialsMetaResponse(BaseModel):
@router.post("/{provider}/callback")
-def callback(
+async def callback(
provider: Annotated[
ProviderName, Path(title="The target provider for this OAuth exchange")
],
@@ -89,7 +89,9 @@ def callback(
handler = _get_provider_oauth_handler(request, provider)
# Verify the state token
- valid_state = creds_manager.store.verify_state_token(user_id, state_token, provider)
+ valid_state = await creds_manager.store.verify_state_token(
+ user_id, state_token, provider
+ )
if not valid_state:
logger.warning(f"Invalid or expired state token for user {user_id}")
@@ -100,7 +102,7 @@ def callback(
scopes = handler.handle_default_scopes(scopes)
- credentials = handler.exchange_code_for_tokens(
+ credentials = await handler.exchange_code_for_tokens(
code, scopes, valid_state.code_verifier
)
@@ -134,7 +136,7 @@ def callback(
)
# TODO: Allow specifying `title` to set on `credentials`
- creds_manager.create(user_id, credentials)
+ await creds_manager.create(user_id, credentials)
logger.debug(
f"Successfully processed OAuth callback for user {user_id} "
@@ -151,10 +153,10 @@ def callback(
@router.get("/credentials")
-def list_credentials(
+async def list_credentials(
user_id: Annotated[str, Depends(get_user_id)],
) -> list[CredentialsMetaResponse]:
- credentials = creds_manager.store.get_all_creds(user_id)
+ credentials = await creds_manager.store.get_all_creds(user_id)
return [
CredentialsMetaResponse(
id=cred.id,
@@ -169,13 +171,13 @@ def list_credentials(
@router.get("/{provider}/credentials")
-def list_credentials_by_provider(
+async def list_credentials_by_provider(
provider: Annotated[
ProviderName, Path(title="The provider to list credentials for")
],
user_id: Annotated[str, Depends(get_user_id)],
) -> list[CredentialsMetaResponse]:
- credentials = creds_manager.store.get_creds_by_provider(user_id, provider)
+ credentials = await creds_manager.store.get_creds_by_provider(user_id, provider)
return [
CredentialsMetaResponse(
id=cred.id,
@@ -190,14 +192,14 @@ def list_credentials_by_provider(
@router.get("/{provider}/credentials/{cred_id}")
-def get_credential(
+async def get_credential(
provider: Annotated[
ProviderName, Path(title="The provider to retrieve credentials for")
],
cred_id: Annotated[str, Path(title="The ID of the credentials to retrieve")],
user_id: Annotated[str, Depends(get_user_id)],
) -> Credentials:
- credential = creds_manager.get(user_id, cred_id)
+ credential = await creds_manager.get(user_id, cred_id)
if not credential:
raise HTTPException(status_code=404, detail="Credentials not found")
if credential.provider != provider:
@@ -208,7 +210,7 @@ def get_credential(
@router.post("/{provider}/credentials", status_code=201)
-def create_credentials(
+async def create_credentials(
user_id: Annotated[str, Depends(get_user_id)],
provider: Annotated[
ProviderName, Path(title="The provider to create credentials for")
@@ -217,7 +219,7 @@ def create_credentials(
) -> Credentials:
credentials.provider = provider
try:
- creds_manager.create(user_id, credentials)
+ await creds_manager.create(user_id, credentials)
except Exception as e:
raise HTTPException(
status_code=500, detail=f"Failed to store credentials: {str(e)}"
@@ -252,7 +254,7 @@ async def delete_credentials(
bool, Query(title="Whether to proceed if any linked webhooks are still in use")
] = False,
) -> CredentialsDeletionResponse | CredentialsDeletionNeedsConfirmationResponse:
- creds = creds_manager.store.get_creds_by_id(user_id, cred_id)
+ creds = await creds_manager.store.get_creds_by_id(user_id, cred_id)
if not creds:
raise HTTPException(status_code=404, detail="Credentials not found")
if creds.provider != provider:
@@ -265,12 +267,12 @@ async def delete_credentials(
except NeedConfirmation as e:
return CredentialsDeletionNeedsConfirmationResponse(message=str(e))
- creds_manager.delete(user_id, cred_id)
+ await creds_manager.delete(user_id, cred_id)
tokens_revoked = None
if isinstance(creds, OAuth2Credentials):
handler = _get_provider_oauth_handler(request, provider)
- tokens_revoked = handler.revoke_tokens(creds)
+ tokens_revoked = await handler.revoke_tokens(creds)
return CredentialsDeletionResponse(revoked=tokens_revoked)
@@ -329,7 +331,7 @@ async def webhook_ingress_generic(
continue
logger.debug(f"Executing graph #{node.graph_id} node #{node.id}")
executions.append(
- add_graph_execution_async(
+ add_graph_execution(
user_id=webhook.user_id,
graph_id=node.graph_id,
graph_version=node.graph_version,
@@ -348,7 +350,7 @@ async def webhook_ping(
webhook_manager = get_webhook_manager(webhook.provider)
credentials = (
- creds_manager.get(user_id, webhook.credentials_id)
+ await creds_manager.get(user_id, webhook.credentials_id)
if webhook.credentials_id
else None
)
diff --git a/autogpt_platform/backend/backend/server/middleware/security.py b/autogpt_platform/backend/backend/server/middleware/security.py
new file mode 100644
index 0000000000..e6e23467ca
--- /dev/null
+++ b/autogpt_platform/backend/backend/server/middleware/security.py
@@ -0,0 +1,93 @@
+import re
+from typing import Set
+
+from fastapi import Request, Response
+from starlette.middleware.base import BaseHTTPMiddleware
+from starlette.types import ASGIApp
+
+
+class SecurityHeadersMiddleware(BaseHTTPMiddleware):
+ """
+ Middleware to add security headers to responses, with cache control
+ disabled by default for all endpoints except those explicitly allowed.
+ """
+
+ CACHEABLE_PATHS: Set[str] = {
+ # Static assets
+ "/static",
+ "/_next/static",
+ "/assets",
+ "/images",
+ "/css",
+ "/js",
+ "/fonts",
+ # Public API endpoints
+ "/api/health",
+ "/api/v1/health",
+ "/api/status",
+ # Public store/marketplace pages (read-only)
+ "/api/store/agents",
+ "/api/v1/store/agents",
+ "/api/store/categories",
+ "/api/v1/store/categories",
+ "/api/store/featured",
+ "/api/v1/store/featured",
+ # Public graph templates (read-only, no user data)
+ "/api/graphs/templates",
+ "/api/v1/graphs/templates",
+ # Documentation endpoints
+ "/api/docs",
+ "/api/v1/docs",
+ "/docs",
+ "/swagger",
+ "/openapi.json",
+ # Favicon and manifest
+ "/favicon.ico",
+ "/manifest.json",
+ "/robots.txt",
+ "/sitemap.xml",
+ }
+
+ def __init__(self, app: ASGIApp):
+ super().__init__(app)
+ # Compile regex patterns for wildcard matching
+ self.cacheable_patterns = [
+ re.compile(pattern.replace("*", "[^/]+"))
+ for pattern in self.CACHEABLE_PATHS
+ if "*" in pattern
+ ]
+ self.exact_paths = {path for path in self.CACHEABLE_PATHS if "*" not in path}
+
+ def is_cacheable_path(self, path: str) -> bool:
+ """Check if the given path is allowed to be cached."""
+ # Check exact matches first
+ for cacheable_path in self.exact_paths:
+ if path.startswith(cacheable_path):
+ return True
+
+ # Check pattern matches
+ for pattern in self.cacheable_patterns:
+ if pattern.match(path):
+ return True
+
+ return False
+
+ async def dispatch(self, request: Request, call_next):
+ response: Response = await call_next(request)
+
+ # Add general security headers
+ response.headers["X-Content-Type-Options"] = "nosniff"
+ response.headers["X-Frame-Options"] = "DENY"
+ response.headers["X-XSS-Protection"] = "1; mode=block"
+ response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
+
+ # Default: Disable caching for all endpoints
+ # Only allow caching for explicitly permitted paths
+ if not self.is_cacheable_path(request.url.path):
+ response.headers["Cache-Control"] = (
+ "no-store, no-cache, must-revalidate, private"
+ )
+ response.headers["Pragma"] = "no-cache"
+ response.headers["Expires"] = "0"
+
+ return response
diff --git a/autogpt_platform/backend/backend/server/middleware/security_test.py b/autogpt_platform/backend/backend/server/middleware/security_test.py
new file mode 100644
index 0000000000..462e5b27ed
--- /dev/null
+++ b/autogpt_platform/backend/backend/server/middleware/security_test.py
@@ -0,0 +1,143 @@
+import pytest
+from fastapi import FastAPI
+from fastapi.testclient import TestClient
+from starlette.applications import Starlette
+
+from backend.server.middleware.security import SecurityHeadersMiddleware
+
+
+@pytest.fixture
+def app():
+ """Create a test FastAPI app with security middleware."""
+ app = FastAPI()
+ app.add_middleware(SecurityHeadersMiddleware)
+
+ @app.get("/api/auth/user")
+ def get_user():
+ return {"user": "test"}
+
+ @app.get("/api/v1/integrations/oauth/google")
+ def oauth_endpoint():
+ return {"oauth": "data"}
+
+ @app.get("/api/graphs/123/execute")
+ def execute_graph():
+ return {"execution": "data"}
+
+ @app.get("/api/integrations/credentials")
+ def get_credentials():
+ return {"credentials": "sensitive"}
+
+ @app.get("/api/store/agents")
+ def store_agents():
+ return {"agents": "public list"}
+
+ @app.get("/api/health")
+ def health_check():
+ return {"status": "ok"}
+
+ @app.get("/static/logo.png")
+ def static_file():
+ return {"static": "content"}
+
+ return app
+
+
+@pytest.fixture
+def client(app):
+ """Create a test client."""
+ return TestClient(app)
+
+
+def test_non_cacheable_endpoints_have_cache_control_headers(client):
+ """Test that non-cacheable endpoints (most endpoints) have proper cache control headers."""
+ non_cacheable_endpoints = [
+ "/api/auth/user",
+ "/api/v1/integrations/oauth/google",
+ "/api/graphs/123/execute",
+ "/api/integrations/credentials",
+ ]
+
+ for endpoint in non_cacheable_endpoints:
+ response = client.get(endpoint)
+
+ # Check cache control headers are present (default behavior)
+ assert (
+ response.headers["Cache-Control"]
+ == "no-store, no-cache, must-revalidate, private"
+ )
+ assert response.headers["Pragma"] == "no-cache"
+ assert response.headers["Expires"] == "0"
+
+ # Check general security headers
+ assert response.headers["X-Content-Type-Options"] == "nosniff"
+ assert response.headers["X-Frame-Options"] == "DENY"
+ assert response.headers["X-XSS-Protection"] == "1; mode=block"
+ assert response.headers["Referrer-Policy"] == "strict-origin-when-cross-origin"
+
+
+def test_cacheable_endpoints_dont_have_cache_control_headers(client):
+ """Test that explicitly cacheable endpoints don't have restrictive cache control headers."""
+ cacheable_endpoints = [
+ "/api/store/agents",
+ "/api/health",
+ "/static/logo.png",
+ ]
+
+ for endpoint in cacheable_endpoints:
+ response = client.get(endpoint)
+
+ # Should NOT have restrictive cache control headers
+ assert (
+ "Cache-Control" not in response.headers
+ or "no-store" not in response.headers.get("Cache-Control", "")
+ )
+ assert (
+ "Pragma" not in response.headers
+ or response.headers.get("Pragma") != "no-cache"
+ )
+ assert (
+ "Expires" not in response.headers or response.headers.get("Expires") != "0"
+ )
+
+ # Should still have general security headers
+ assert response.headers["X-Content-Type-Options"] == "nosniff"
+ assert response.headers["X-Frame-Options"] == "DENY"
+ assert response.headers["X-XSS-Protection"] == "1; mode=block"
+ assert response.headers["Referrer-Policy"] == "strict-origin-when-cross-origin"
+
+
+def test_is_cacheable_path_detection():
+ """Test the path detection logic."""
+ middleware = SecurityHeadersMiddleware(Starlette())
+
+ # Test cacheable paths (allow list)
+ assert middleware.is_cacheable_path("/api/health")
+ assert middleware.is_cacheable_path("/api/v1/health")
+ assert middleware.is_cacheable_path("/static/image.png")
+ assert middleware.is_cacheable_path("/api/store/agents")
+ assert middleware.is_cacheable_path("/docs")
+ assert middleware.is_cacheable_path("/favicon.ico")
+
+ # Test non-cacheable paths (everything else)
+ assert not middleware.is_cacheable_path("/api/auth/user")
+ assert not middleware.is_cacheable_path("/api/v1/integrations/oauth/callback")
+ assert not middleware.is_cacheable_path("/api/integrations/credentials/123")
+ assert not middleware.is_cacheable_path("/api/graphs/abc123/execute")
+ assert not middleware.is_cacheable_path("/api/store/xyz/submissions")
+
+
+def test_path_prefix_matching():
+ """Test that path prefix matching works correctly."""
+ middleware = SecurityHeadersMiddleware(Starlette())
+
+ # Test that paths starting with cacheable prefixes are cacheable
+ assert middleware.is_cacheable_path("/static/css/style.css")
+ assert middleware.is_cacheable_path("/static/js/app.js")
+ assert middleware.is_cacheable_path("/assets/images/logo.png")
+ assert middleware.is_cacheable_path("/_next/static/chunks/main.js")
+
+ # Test that other API paths are not cacheable by default
+ assert not middleware.is_cacheable_path("/api/users/profile")
+ assert not middleware.is_cacheable_path("/api/v1/private/data")
+ assert not middleware.is_cacheable_path("/api/billing/subscription")
diff --git a/autogpt_platform/backend/backend/server/rest_api.py b/autogpt_platform/backend/backend/server/rest_api.py
index 9214c00ab2..f18bd932f3 100644
--- a/autogpt_platform/backend/backend/server/rest_api.py
+++ b/autogpt_platform/backend/backend/server/rest_api.py
@@ -1,5 +1,6 @@
import contextlib
import logging
+from enum import Enum
from typing import Any, Optional
import autogpt_libs.auth.models
@@ -14,6 +15,7 @@ from autogpt_libs.feature_flag.client import (
)
from autogpt_libs.logging.utils import generate_uvicorn_config
from fastapi.exceptions import RequestValidationError
+from fastapi.routing import APIRoute
import backend.data.block
import backend.data.db
@@ -36,6 +38,7 @@ from backend.blocks.llm import LlmModel
from backend.data.model import Credentials
from backend.integrations.providers import ProviderName
from backend.server.external.api import external_app
+from backend.server.middleware.security import SecurityHeadersMiddleware
settings = backend.util.settings.Settings()
logger = logging.getLogger(__name__)
@@ -67,6 +70,33 @@ async def lifespan_context(app: fastapi.FastAPI):
await backend.data.db.disconnect()
+def custom_generate_unique_id(route: APIRoute):
+ """Generate clean operation IDs for OpenAPI spec following the format:
+ {method}{tag}{summary}
+ """
+ if not route.tags or not route.methods:
+ return f"{route.name}"
+
+ method = list(route.methods)[0].lower()
+ first_tag = route.tags[0]
+ if isinstance(first_tag, Enum):
+ tag_str = first_tag.name
+ else:
+ tag_str = str(first_tag)
+
+ tag = "".join(word.capitalize() for word in tag_str.split("_")) # v1/v2
+
+ summary = (
+ route.summary if route.summary else route.name
+ ) # need to be unique, a different version could have the same summary
+ summary = "".join(word.capitalize() for word in str(summary).split("_"))
+
+ if tag:
+ return f"{method}{tag}{summary}"
+ else:
+ return f"{method}{summary}"
+
+
docs_url = (
"/docs"
if settings.config.app_env == backend.util.settings.AppEnvironment.LOCAL
@@ -82,8 +112,11 @@ app = fastapi.FastAPI(
version="0.1",
lifespan=lifespan_context,
docs_url=docs_url,
+ generate_unique_id_function=custom_generate_unique_id,
)
+app.add_middleware(SecurityHeadersMiddleware)
+
def handle_internal_http_error(status_code: int = 500, log_error: bool = True):
def handler(request: fastapi.Request, exc: Exception):
@@ -158,10 +191,12 @@ app.include_router(
backend.server.v2.library.routes.router, tags=["v2"], prefix="/api/library"
)
app.include_router(
- backend.server.v2.otto.routes.router, tags=["v2"], prefix="/api/otto"
+ backend.server.v2.otto.routes.router, tags=["v2", "otto"], prefix="/api/otto"
)
app.include_router(
- backend.server.v2.turnstile.routes.router, tags=["v2"], prefix="/api/turnstile"
+ backend.server.v2.turnstile.routes.router,
+ tags=["v2", "turnstile"],
+ prefix="/api/turnstile",
)
app.include_router(
@@ -320,14 +355,14 @@ class AgentServer(backend.util.service.AppProcess):
)
@staticmethod
- def test_create_credentials(
+ async def test_create_credentials(
user_id: str,
provider: ProviderName,
credentials: Credentials,
) -> Credentials:
from backend.server.integrations.router import create_credentials
- return create_credentials(
+ return await create_credentials(
user_id=user_id, provider=provider, credentials=credentials
)
diff --git a/autogpt_platform/backend/backend/server/routers/postmark/postmark.py b/autogpt_platform/backend/backend/server/routers/postmark/postmark.py
index ae744bfc10..b83b77dc12 100644
--- a/autogpt_platform/backend/backend/server/routers/postmark/postmark.py
+++ b/autogpt_platform/backend/backend/server/routers/postmark/postmark.py
@@ -34,13 +34,13 @@ router = APIRouter()
logger = logging.getLogger(__name__)
-@router.post("/unsubscribe")
+@router.post("/unsubscribe", summary="One Click Email Unsubscribe")
async def unsubscribe_via_one_click(token: Annotated[str, Query()]):
- logger.info(f"Received unsubscribe request from One Click Unsubscribe: {token}")
+ logger.info("Received unsubscribe request from One Click Unsubscribe")
try:
await unsubscribe_user_by_token(token)
except Exception as e:
- logger.exception("Unsubscribe token %s failed: %s", token, e)
+ logger.exception("Unsubscribe failed: %s", e)
raise HTTPException(
status_code=500,
detail={"message": str(e), "hint": "Verify Postmark token settings."},
@@ -48,7 +48,11 @@ async def unsubscribe_via_one_click(token: Annotated[str, Query()]):
return JSONResponse(status_code=200, content={"status": "ok"})
-@router.post("/", dependencies=[Depends(postmark_validator.get_dependency())])
+@router.post(
+ "/",
+ dependencies=[Depends(postmark_validator.get_dependency())],
+ summary="Handle Postmark Email Webhooks",
+)
async def postmark_webhook_handler(
webhook: Annotated[
PostmarkWebhook,
diff --git a/autogpt_platform/backend/backend/server/routers/v1.py b/autogpt_platform/backend/backend/server/routers/v1.py
index d9d39e4666..e177d22d34 100644
--- a/autogpt_platform/backend/backend/server/routers/v1.py
+++ b/autogpt_platform/backend/backend/server/routers/v1.py
@@ -50,7 +50,6 @@ from backend.data.onboarding import (
onboarding_enabled,
update_user_onboarding,
)
-from backend.data.rabbitmq import AsyncRabbitMQ
from backend.data.user import (
get_or_create_user,
get_user_notification_preference,
@@ -59,7 +58,6 @@ from backend.data.user import (
)
from backend.executor import scheduler
from backend.executor import utils as execution_utils
-from backend.executor.utils import create_execution_queue_config
from backend.integrations.webhooks.graph_lifecycle_hooks import (
on_graph_activate,
on_graph_deactivate,
@@ -83,13 +81,6 @@ def execution_scheduler_client() -> scheduler.SchedulerClient:
return get_service_client(scheduler.SchedulerClient, health_check=False)
-@thread_cached
-async def execution_queue_client() -> AsyncRabbitMQ:
- client = AsyncRabbitMQ(create_execution_queue_config())
- await client.connect()
- return client
-
-
@thread_cached
def execution_event_bus() -> AsyncRedisExecutionEventBus:
return AsyncRedisExecutionEventBus()
@@ -122,14 +113,22 @@ v1_router.include_router(
########################################################
-@v1_router.post("/auth/user", tags=["auth"], dependencies=[Depends(auth_middleware)])
+@v1_router.post(
+ "/auth/user",
+ summary="Get or create user",
+ tags=["auth"],
+ dependencies=[Depends(auth_middleware)],
+)
async def get_or_create_user_route(user_data: dict = Depends(auth_middleware)):
user = await get_or_create_user(user_data)
return user.model_dump()
@v1_router.post(
- "/auth/user/email", tags=["auth"], dependencies=[Depends(auth_middleware)]
+ "/auth/user/email",
+ summary="Update user email",
+ tags=["auth"],
+ dependencies=[Depends(auth_middleware)],
)
async def update_user_email_route(
user_id: Annotated[str, Depends(get_user_id)], email: str = Body(...)
@@ -141,6 +140,7 @@ async def update_user_email_route(
@v1_router.get(
"/auth/user/preferences",
+ summary="Get notification preferences",
tags=["auth"],
dependencies=[Depends(auth_middleware)],
)
@@ -153,6 +153,7 @@ async def get_preferences(
@v1_router.post(
"/auth/user/preferences",
+ summary="Update notification preferences",
tags=["auth"],
dependencies=[Depends(auth_middleware)],
)
@@ -170,14 +171,20 @@ async def update_preferences(
@v1_router.get(
- "/onboarding", tags=["onboarding"], dependencies=[Depends(auth_middleware)]
+ "/onboarding",
+ summary="Get onboarding status",
+ tags=["onboarding"],
+ dependencies=[Depends(auth_middleware)],
)
async def get_onboarding(user_id: Annotated[str, Depends(get_user_id)]):
return await get_user_onboarding(user_id)
@v1_router.patch(
- "/onboarding", tags=["onboarding"], dependencies=[Depends(auth_middleware)]
+ "/onboarding",
+ summary="Update onboarding progress",
+ tags=["onboarding"],
+ dependencies=[Depends(auth_middleware)],
)
async def update_onboarding(
user_id: Annotated[str, Depends(get_user_id)], data: UserOnboardingUpdate
@@ -187,6 +194,7 @@ async def update_onboarding(
@v1_router.get(
"/onboarding/agents",
+ summary="Get recommended agents",
tags=["onboarding"],
dependencies=[Depends(auth_middleware)],
)
@@ -198,6 +206,7 @@ async def get_onboarding_agents(
@v1_router.get(
"/onboarding/enabled",
+ summary="Check onboarding enabled",
tags=["onboarding", "public"],
dependencies=[Depends(auth_middleware)],
)
@@ -210,7 +219,12 @@ async def is_onboarding_enabled():
########################################################
-@v1_router.get(path="/blocks", tags=["blocks"], dependencies=[Depends(auth_middleware)])
+@v1_router.get(
+ path="/blocks",
+ summary="List available blocks",
+ tags=["blocks"],
+ dependencies=[Depends(auth_middleware)],
+)
def get_graph_blocks() -> Sequence[dict[Any, Any]]:
blocks = [block() for block in get_blocks().values()]
costs = get_block_costs()
@@ -221,16 +235,17 @@ def get_graph_blocks() -> Sequence[dict[Any, Any]]:
@v1_router.post(
path="/blocks/{block_id}/execute",
+ summary="Execute graph block",
tags=["blocks"],
dependencies=[Depends(auth_middleware)],
)
-def execute_graph_block(block_id: str, data: BlockInput) -> CompletedBlockOutput:
+async def execute_graph_block(block_id: str, data: BlockInput) -> CompletedBlockOutput:
obj = get_block(block_id)
if not obj:
raise HTTPException(status_code=404, detail=f"Block #{block_id} not found.")
output = defaultdict(list)
- for name, data in obj.execute(data):
+ async for name, data in obj.execute(data):
output[name].append(data)
return output
@@ -240,7 +255,12 @@ def execute_graph_block(block_id: str, data: BlockInput) -> CompletedBlockOutput
########################################################
-@v1_router.get(path="/credits", dependencies=[Depends(auth_middleware)])
+@v1_router.get(
+ path="/credits",
+ tags=["credits"],
+ summary="Get user credits",
+ dependencies=[Depends(auth_middleware)],
+)
async def get_user_credits(
user_id: Annotated[str, Depends(get_user_id)],
) -> dict[str, int]:
@@ -248,7 +268,10 @@ async def get_user_credits(
@v1_router.post(
- path="/credits", tags=["credits"], dependencies=[Depends(auth_middleware)]
+ path="/credits",
+ summary="Request credit top up",
+ tags=["credits"],
+ dependencies=[Depends(auth_middleware)],
)
async def request_top_up(
request: RequestTopUp, user_id: Annotated[str, Depends(get_user_id)]
@@ -261,6 +284,7 @@ async def request_top_up(
@v1_router.post(
path="/credits/{transaction_key}/refund",
+ summary="Refund credit transaction",
tags=["credits"],
dependencies=[Depends(auth_middleware)],
)
@@ -273,7 +297,10 @@ async def refund_top_up(
@v1_router.patch(
- path="/credits", tags=["credits"], dependencies=[Depends(auth_middleware)]
+ path="/credits",
+ summary="Fulfill checkout session",
+ tags=["credits"],
+ dependencies=[Depends(auth_middleware)],
)
async def fulfill_checkout(user_id: Annotated[str, Depends(get_user_id)]):
await _user_credit_model.fulfill_checkout(user_id=user_id)
@@ -282,6 +309,7 @@ async def fulfill_checkout(user_id: Annotated[str, Depends(get_user_id)]):
@v1_router.post(
path="/credits/auto-top-up",
+ summary="Configure auto top up",
tags=["credits"],
dependencies=[Depends(auth_middleware)],
)
@@ -310,6 +338,7 @@ async def configure_user_auto_top_up(
@v1_router.get(
path="/credits/auto-top-up",
+ summary="Get auto top up",
tags=["credits"],
dependencies=[Depends(auth_middleware)],
)
@@ -319,7 +348,9 @@ async def get_user_auto_top_up(
return await get_auto_top_up(user_id)
-@v1_router.post(path="/credits/stripe_webhook", tags=["credits"])
+@v1_router.post(
+ path="/credits/stripe_webhook", summary="Handle Stripe webhooks", tags=["credits"]
+)
async def stripe_webhook(request: Request):
# Get the raw request body
payload = await request.body()
@@ -354,14 +385,24 @@ async def stripe_webhook(request: Request):
return Response(status_code=200)
-@v1_router.get(path="/credits/manage", dependencies=[Depends(auth_middleware)])
+@v1_router.get(
+ path="/credits/manage",
+ tags=["credits"],
+ summary="Manage payment methods",
+ dependencies=[Depends(auth_middleware)],
+)
async def manage_payment_method(
user_id: Annotated[str, Depends(get_user_id)],
) -> dict[str, str]:
return {"url": await _user_credit_model.create_billing_portal_session(user_id)}
-@v1_router.get(path="/credits/transactions", dependencies=[Depends(auth_middleware)])
+@v1_router.get(
+ path="/credits/transactions",
+ tags=["credits"],
+ summary="Get credit history",
+ dependencies=[Depends(auth_middleware)],
+)
async def get_credit_history(
user_id: Annotated[str, Depends(get_user_id)],
transaction_time: datetime | None = None,
@@ -379,7 +420,12 @@ async def get_credit_history(
)
-@v1_router.get(path="/credits/refunds", dependencies=[Depends(auth_middleware)])
+@v1_router.get(
+ path="/credits/refunds",
+ tags=["credits"],
+ summary="Get refund requests",
+ dependencies=[Depends(auth_middleware)],
+)
async def get_refund_requests(
user_id: Annotated[str, Depends(get_user_id)],
) -> list[RefundRequest]:
@@ -395,7 +441,12 @@ class DeleteGraphResponse(TypedDict):
version_counts: int
-@v1_router.get(path="/graphs", tags=["graphs"], dependencies=[Depends(auth_middleware)])
+@v1_router.get(
+ path="/graphs",
+ summary="List user graphs",
+ tags=["graphs"],
+ dependencies=[Depends(auth_middleware)],
+)
async def get_graphs(
user_id: Annotated[str, Depends(get_user_id)],
) -> Sequence[graph_db.GraphModel]:
@@ -403,10 +454,14 @@ async def get_graphs(
@v1_router.get(
- path="/graphs/{graph_id}", tags=["graphs"], dependencies=[Depends(auth_middleware)]
+ path="/graphs/{graph_id}",
+ summary="Get specific graph",
+ tags=["graphs"],
+ dependencies=[Depends(auth_middleware)],
)
@v1_router.get(
path="/graphs/{graph_id}/versions/{version}",
+ summary="Get graph version",
tags=["graphs"],
dependencies=[Depends(auth_middleware)],
)
@@ -430,6 +485,7 @@ async def get_graph(
@v1_router.get(
path="/graphs/{graph_id}/versions",
+ summary="Get all graph versions",
tags=["graphs"],
dependencies=[Depends(auth_middleware)],
)
@@ -443,7 +499,10 @@ async def get_graph_all_versions(
@v1_router.post(
- path="/graphs", tags=["graphs"], dependencies=[Depends(auth_middleware)]
+ path="/graphs",
+ summary="Create new graph",
+ tags=["graphs"],
+ dependencies=[Depends(auth_middleware)],
)
async def create_new_graph(
create_graph: CreateGraph,
@@ -466,7 +525,10 @@ async def create_new_graph(
@v1_router.delete(
- path="/graphs/{graph_id}", tags=["graphs"], dependencies=[Depends(auth_middleware)]
+ path="/graphs/{graph_id}",
+ summary="Delete graph permanently",
+ tags=["graphs"],
+ dependencies=[Depends(auth_middleware)],
)
async def delete_graph(
graph_id: str, user_id: Annotated[str, Depends(get_user_id)]
@@ -478,7 +540,10 @@ async def delete_graph(
@v1_router.put(
- path="/graphs/{graph_id}", tags=["graphs"], dependencies=[Depends(auth_middleware)]
+ path="/graphs/{graph_id}",
+ summary="Update graph version",
+ tags=["graphs"],
+ dependencies=[Depends(auth_middleware)],
)
async def update_graph(
graph_id: str,
@@ -524,6 +589,7 @@ async def update_graph(
@v1_router.put(
path="/graphs/{graph_id}/versions/active",
+ summary="Set active graph version",
tags=["graphs"],
dependencies=[Depends(auth_middleware)],
)
@@ -562,6 +628,7 @@ async def set_graph_active_version(
@v1_router.post(
path="/graphs/{graph_id}/execute/{graph_version}",
+ summary="Execute graph agent",
tags=["graphs"],
dependencies=[Depends(auth_middleware)],
)
@@ -582,7 +649,7 @@ async def execute_graph(
detail="Insufficient balance to execute the agent. Please top up your account.",
)
- graph_exec = await execution_utils.add_graph_execution_async(
+ graph_exec = await execution_utils.add_graph_execution(
graph_id=graph_id,
user_id=user_id,
inputs=inputs,
@@ -595,18 +662,19 @@ async def execute_graph(
@v1_router.post(
path="/graphs/{graph_id}/executions/{graph_exec_id}/stop",
+ summary="Stop graph execution",
tags=["graphs"],
dependencies=[Depends(auth_middleware)],
)
async def stop_graph_run(
- graph_exec_id: str, user_id: Annotated[str, Depends(get_user_id)]
+ graph_id: str, graph_exec_id: str, user_id: Annotated[str, Depends(get_user_id)]
) -> execution_db.GraphExecution:
if not await execution_db.get_graph_execution_meta(
user_id=user_id, execution_id=graph_exec_id
):
raise HTTPException(404, detail=f"Agent execution #{graph_exec_id} not found")
- await _cancel_execution(graph_exec_id)
+ await execution_utils.stop_graph_execution(graph_exec_id)
# Retrieve & return canceled graph execution in its final state
result = await execution_db.get_graph_execution(
@@ -620,54 +688,9 @@ async def stop_graph_run(
return result
-async def _cancel_execution(graph_exec_id: str):
- """
- Mechanism:
- 1. Set the cancel event
- 2. Graph executor's cancel handler thread detects the event, terminates workers,
- reinitializes worker pool, and returns.
- 3. Update execution statuses in DB and set `error` outputs to `"TERMINATED"`.
- """
- queue_client = await execution_queue_client()
- await queue_client.publish_message(
- routing_key="",
- message=execution_utils.CancelExecutionEvent(
- graph_exec_id=graph_exec_id
- ).model_dump_json(),
- exchange=execution_utils.GRAPH_EXECUTION_CANCEL_EXCHANGE,
- )
-
- # Update the status of the graph execution
- graph_execution = await execution_db.update_graph_execution_stats(
- graph_exec_id,
- execution_db.ExecutionStatus.TERMINATED,
- )
- if graph_execution:
- await execution_event_bus().publish(graph_execution)
-
- # Update the status of the node executions
- node_execs = [
- node_exec.model_copy(update={"status": execution_db.ExecutionStatus.TERMINATED})
- for node_exec in await execution_db.get_node_executions(
- graph_exec_id=graph_exec_id,
- statuses=[
- execution_db.ExecutionStatus.QUEUED,
- execution_db.ExecutionStatus.RUNNING,
- execution_db.ExecutionStatus.INCOMPLETE,
- ],
- )
- ]
- await execution_db.update_node_execution_status_batch(
- [node_exec.node_exec_id for node_exec in node_execs],
- execution_db.ExecutionStatus.TERMINATED,
- )
- await asyncio.gather(
- *[execution_event_bus().publish(node_exec) for node_exec in node_execs]
- )
-
-
@v1_router.get(
path="/executions",
+ summary="Get all executions",
tags=["graphs"],
dependencies=[Depends(auth_middleware)],
)
@@ -679,6 +702,7 @@ async def get_graphs_executions(
@v1_router.get(
path="/graphs/{graph_id}/executions",
+ summary="Get graph executions",
tags=["graphs"],
dependencies=[Depends(auth_middleware)],
)
@@ -691,6 +715,7 @@ async def get_graph_executions(
@v1_router.get(
path="/graphs/{graph_id}/executions/{graph_exec_id}",
+ summary="Get execution details",
tags=["graphs"],
dependencies=[Depends(auth_middleware)],
)
@@ -720,6 +745,7 @@ async def get_graph_execution(
@v1_router.delete(
path="/executions/{graph_exec_id}",
+ summary="Delete graph execution",
tags=["graphs"],
dependencies=[Depends(auth_middleware)],
status_code=HTTP_204_NO_CONTENT,
@@ -747,6 +773,7 @@ class ScheduleCreationRequest(pydantic.BaseModel):
@v1_router.post(
path="/schedules",
+ summary="Create execution schedule",
tags=["schedules"],
dependencies=[Depends(auth_middleware)],
)
@@ -774,6 +801,7 @@ async def create_schedule(
@v1_router.delete(
path="/schedules/{schedule_id}",
+ summary="Delete execution schedule",
tags=["schedules"],
dependencies=[Depends(auth_middleware)],
)
@@ -787,6 +815,7 @@ async def delete_schedule(
@v1_router.get(
path="/schedules",
+ summary="List execution schedules",
tags=["schedules"],
dependencies=[Depends(auth_middleware)],
)
@@ -807,6 +836,7 @@ async def get_execution_schedules(
@v1_router.post(
"/api-keys",
+ summary="Create new API key",
response_model=CreateAPIKeyResponse,
tags=["api-keys"],
dependencies=[Depends(auth_middleware)],
@@ -837,6 +867,7 @@ async def create_api_key(
@v1_router.get(
"/api-keys",
+ summary="List user API keys",
response_model=list[APIKeyWithoutHash] | dict[str, str],
tags=["api-keys"],
dependencies=[Depends(auth_middleware)],
@@ -857,6 +888,7 @@ async def get_api_keys(
@v1_router.get(
"/api-keys/{key_id}",
+ summary="Get specific API key",
response_model=APIKeyWithoutHash,
tags=["api-keys"],
dependencies=[Depends(auth_middleware)],
@@ -880,6 +912,7 @@ async def get_api_key(
@v1_router.delete(
"/api-keys/{key_id}",
+ summary="Revoke API key",
response_model=APIKeyWithoutHash,
tags=["api-keys"],
dependencies=[Depends(auth_middleware)],
@@ -908,6 +941,7 @@ async def delete_api_key(
@v1_router.post(
"/api-keys/{key_id}/suspend",
+ summary="Suspend API key",
response_model=APIKeyWithoutHash,
tags=["api-keys"],
dependencies=[Depends(auth_middleware)],
@@ -933,6 +967,7 @@ async def suspend_key(
@v1_router.put(
"/api-keys/{key_id}/permissions",
+ summary="Update key permissions",
response_model=APIKeyWithoutHash,
tags=["api-keys"],
dependencies=[Depends(auth_middleware)],
diff --git a/autogpt_platform/backend/backend/server/routers/v1_test.py b/autogpt_platform/backend/backend/server/routers/v1_test.py
index 17c06b5778..cddee98273 100644
--- a/autogpt_platform/backend/backend/server/routers/v1_test.py
+++ b/autogpt_platform/backend/backend/server/routers/v1_test.py
@@ -137,10 +137,12 @@ def test_execute_graph_block(
"""Test execute block endpoint"""
# Mock block
mock_block = Mock()
- mock_block.execute.return_value = [
- ("output1", {"data": "result1"}),
- ("output2", {"data": "result2"}),
- ]
+
+ async def mock_execute(*args, **kwargs):
+ yield "output1", {"data": "result1"}
+ yield "output2", {"data": "result2"}
+
+ mock_block.execute = mock_execute
mocker.patch(
"backend.server.routers.v1.get_block",
diff --git a/autogpt_platform/backend/backend/server/v2/admin/credit_admin_routes.py b/autogpt_platform/backend/backend/server/v2/admin/credit_admin_routes.py
index f19d8b45f0..009c541432 100644
--- a/autogpt_platform/backend/backend/server/v2/admin/credit_admin_routes.py
+++ b/autogpt_platform/backend/backend/server/v2/admin/credit_admin_routes.py
@@ -22,7 +22,9 @@ router = APIRouter(
)
-@router.post("/add_credits", response_model=AddUserCreditsResponse)
+@router.post(
+ "/add_credits", response_model=AddUserCreditsResponse, summary="Add Credits to User"
+)
async def add_user_credits(
user_id: typing.Annotated[str, Body()],
amount: typing.Annotated[int, Body()],
@@ -49,6 +51,7 @@ async def add_user_credits(
@router.get(
"/users_history",
response_model=UserHistoryResponse,
+ summary="Get All Users History",
)
async def admin_get_all_user_history(
admin_user: typing.Annotated[
diff --git a/autogpt_platform/backend/backend/server/v2/admin/store_admin_routes.py b/autogpt_platform/backend/backend/server/v2/admin/store_admin_routes.py
index e59b0c4805..88f69360a4 100644
--- a/autogpt_platform/backend/backend/server/v2/admin/store_admin_routes.py
+++ b/autogpt_platform/backend/backend/server/v2/admin/store_admin_routes.py
@@ -19,6 +19,7 @@ router = fastapi.APIRouter(prefix="/admin", tags=["store", "admin"])
@router.get(
"/listings",
+ summary="Get Admin Listings History",
response_model=backend.server.v2.store.model.StoreListingsWithVersionsResponse,
dependencies=[fastapi.Depends(autogpt_libs.auth.depends.requires_admin_user)],
)
@@ -63,6 +64,7 @@ async def get_admin_listings_with_versions(
@router.post(
"/submissions/{store_listing_version_id}/review",
+ summary="Review Store Submission",
response_model=backend.server.v2.store.model.StoreSubmission,
dependencies=[fastapi.Depends(autogpt_libs.auth.depends.requires_admin_user)],
)
@@ -104,6 +106,7 @@ async def review_submission(
@router.get(
"/submissions/download/{store_listing_version_id}",
+ summary="Admin Download Agent File",
tags=["store", "admin"],
dependencies=[fastapi.Depends(autogpt_libs.auth.depends.requires_admin_user)],
)
diff --git a/autogpt_platform/backend/backend/server/v2/library/db.py b/autogpt_platform/backend/backend/server/v2/library/db.py
index 15d479e588..b0f8f7a755 100644
--- a/autogpt_platform/backend/backend/server/v2/library/db.py
+++ b/autogpt_platform/backend/backend/server/v2/library/db.py
@@ -466,15 +466,15 @@ async def add_store_agent_to_library(
# Create LibraryAgent entry
added_agent = await prisma.models.LibraryAgent.prisma().create(
- data=prisma.types.LibraryAgentCreateInput(
- userId=user_id,
- AgentGraph={
+ data={
+ "User": {"connect": {"id": user_id}},
+ "AgentGraph": {
"connect": {
"graphVersionId": {"id": graph.id, "version": graph.version}
}
},
- isCreatedByUser=False,
- ),
+ "isCreatedByUser": False,
+ },
include=library_agent_include(user_id),
)
logger.debug(
diff --git a/autogpt_platform/backend/backend/server/v2/library/routes/agents.py b/autogpt_platform/backend/backend/server/v2/library/routes/agents.py
index 9a0b19b56b..54a0cd235f 100644
--- a/autogpt_platform/backend/backend/server/v2/library/routes/agents.py
+++ b/autogpt_platform/backend/backend/server/v2/library/routes/agents.py
@@ -20,6 +20,7 @@ router = APIRouter(
@router.get(
"",
+ summary="List Library Agents",
responses={
500: {"description": "Server error", "content": {"application/json": {}}},
},
@@ -77,7 +78,7 @@ async def list_library_agents(
) from e
-@router.get("/{library_agent_id}")
+@router.get("/{library_agent_id}", summary="Get Library Agent")
async def get_library_agent(
library_agent_id: str,
user_id: str = Depends(autogpt_auth_lib.depends.get_user_id),
@@ -87,6 +88,7 @@ async def get_library_agent(
@router.get(
"/marketplace/{store_listing_version_id}",
+ summary="Get Agent By Store ID",
tags=["store, library"],
response_model=library_model.LibraryAgent | None,
)
@@ -118,6 +120,7 @@ async def get_library_agent_by_store_listing_version_id(
@router.post(
"",
+ summary="Add Marketplace Agent",
status_code=status.HTTP_201_CREATED,
responses={
201: {"description": "Agent added successfully"},
@@ -180,6 +183,7 @@ async def add_marketplace_agent_to_library(
@router.put(
"/{library_agent_id}",
+ summary="Update Library Agent",
status_code=status.HTTP_204_NO_CONTENT,
responses={
204: {"description": "Agent updated successfully"},
@@ -232,7 +236,7 @@ async def update_library_agent(
) from e
-@router.post("/{library_agent_id}/fork")
+@router.post("/{library_agent_id}/fork", summary="Fork Library Agent")
async def fork_library_agent(
library_agent_id: str,
user_id: str = Depends(autogpt_auth_lib.depends.get_user_id),
diff --git a/autogpt_platform/backend/backend/server/v2/library/routes/presets.py b/autogpt_platform/backend/backend/server/v2/library/routes/presets.py
index 504f46e088..23fc80d23e 100644
--- a/autogpt_platform/backend/backend/server/v2/library/routes/presets.py
+++ b/autogpt_platform/backend/backend/server/v2/library/routes/presets.py
@@ -6,12 +6,14 @@ from fastapi import APIRouter, Body, Depends, HTTPException, Query, status
import backend.server.v2.library.db as db
import backend.server.v2.library.model as models
-from backend.executor.utils import add_graph_execution_async
+from backend.executor.utils import add_graph_execution
from backend.util.exceptions import NotFoundError
logger = logging.getLogger(__name__)
-router = APIRouter()
+router = APIRouter(
+ tags=["presets"],
+)
@router.get(
@@ -245,7 +247,7 @@ async def execute_preset(
# Merge input overrides with preset inputs
merged_node_input = preset.inputs | node_input
- execution = await add_graph_execution_async(
+ execution = await add_graph_execution(
graph_id=graph_id,
user_id=user_id,
inputs=merged_node_input,
diff --git a/autogpt_platform/backend/backend/server/v2/otto/routes.py b/autogpt_platform/backend/backend/server/v2/otto/routes.py
index d2574e35ca..0e2231f4bc 100644
--- a/autogpt_platform/backend/backend/server/v2/otto/routes.py
+++ b/autogpt_platform/backend/backend/server/v2/otto/routes.py
@@ -14,7 +14,10 @@ router = APIRouter()
@router.post(
- "/ask", response_model=ApiResponse, dependencies=[Depends(auth_middleware)]
+ "/ask",
+ response_model=ApiResponse,
+ dependencies=[Depends(auth_middleware)],
+ summary="Proxy Otto Chat Request",
)
async def proxy_otto_request(
request: ChatRequest, user_id: str = Depends(get_user_id)
diff --git a/autogpt_platform/backend/backend/server/v2/store/image_gen.py b/autogpt_platform/backend/backend/server/v2/store/image_gen.py
index ed1db82244..b75536d3cd 100644
--- a/autogpt_platform/backend/backend/server/v2/store/image_gen.py
+++ b/autogpt_platform/backend/backend/server/v2/store/image_gen.py
@@ -1,4 +1,3 @@
-import asyncio
import io
import logging
from enum import Enum
@@ -20,7 +19,7 @@ from backend.blocks.ideogram import (
from backend.data.graph import Graph
from backend.data.model import CredentialsMetaInput, ProviderName
from backend.integrations.credentials_store import ideogram_credentials
-from backend.util.request import requests
+from backend.util.request import Requests
from backend.util.settings import Settings
logger = logging.getLogger(__name__)
@@ -37,12 +36,12 @@ class ImageStyle(str, Enum):
async def generate_agent_image(agent: Graph | AgentGraph) -> io.BytesIO:
if settings.config.use_agent_image_generation_v2:
- return await asyncio.to_thread(generate_agent_image_v2, graph=agent)
+ return await generate_agent_image_v2(graph=agent)
else:
return await generate_agent_image_v1(agent=agent)
-def generate_agent_image_v2(graph: Graph | AgentGraph) -> io.BytesIO:
+async def generate_agent_image_v2(graph: Graph | AgentGraph) -> io.BytesIO:
"""
Generate an image for an agent using Ideogram model.
Returns:
@@ -74,7 +73,7 @@ def generate_agent_image_v2(graph: Graph | AgentGraph) -> io.BytesIO:
]
# Run the Ideogram model block with the specified parameters
- url = IdeogramModelBlock().run_once(
+ url = await IdeogramModelBlock().run_once(
IdeogramModelBlock.Input(
credentials=CredentialsMetaInput(
id=ideogram_credentials.id,
@@ -96,7 +95,8 @@ def generate_agent_image_v2(graph: Graph | AgentGraph) -> io.BytesIO:
"result",
credentials=ideogram_credentials,
)
- return io.BytesIO(requests.get(url).content)
+ response = await Requests().get(url)
+ return io.BytesIO(response.content)
async def generate_agent_image_v1(agent: Graph | AgentGraph) -> io.BytesIO:
@@ -145,13 +145,13 @@ async def generate_agent_image_v1(agent: Graph | AgentGraph) -> io.BytesIO:
else:
# If it's a URL string, fetch the image bytes
result_url = output[0]
- response = requests.get(result_url)
+ response = await Requests().get(result_url)
image_bytes = response.content
elif isinstance(output, FileOutput):
image_bytes = output.read()
elif isinstance(output, str):
# Output is a URL
- response = requests.get(output)
+ response = await Requests().get(output)
image_bytes = response.content
else:
raise RuntimeError("Unexpected output format from the model.")
diff --git a/autogpt_platform/backend/backend/server/v2/store/routes.py b/autogpt_platform/backend/backend/server/v2/store/routes.py
index 41795f5d88..96218d52a8 100644
--- a/autogpt_platform/backend/backend/server/v2/store/routes.py
+++ b/autogpt_platform/backend/backend/server/v2/store/routes.py
@@ -29,6 +29,7 @@ router = fastapi.APIRouter()
@router.get(
"/profile",
+ summary="Get user profile",
tags=["store", "private"],
response_model=backend.server.v2.store.model.ProfileDetails,
)
@@ -61,6 +62,7 @@ async def get_profile(
@router.post(
"/profile",
+ summary="Update user profile",
tags=["store", "private"],
dependencies=[fastapi.Depends(autogpt_libs.auth.middleware.auth_middleware)],
response_model=backend.server.v2.store.model.CreatorDetails,
@@ -107,6 +109,7 @@ async def update_or_create_profile(
@router.get(
"/agents",
+ summary="List store agents",
tags=["store", "public"],
response_model=backend.server.v2.store.model.StoreAgentsResponse,
)
@@ -179,6 +182,7 @@ async def get_agents(
@router.get(
"/agents/{username}/{agent_name}",
+ summary="Get specific agent",
tags=["store", "public"],
response_model=backend.server.v2.store.model.StoreAgentDetails,
)
@@ -208,6 +212,7 @@ async def get_agent(username: str, agent_name: str):
@router.get(
"/graph/{store_listing_version_id}",
+ summary="Get agent graph",
tags=["store"],
)
async def get_graph_meta_by_store_listing_version_id(
@@ -232,6 +237,7 @@ async def get_graph_meta_by_store_listing_version_id(
@router.get(
"/agents/{store_listing_version_id}",
+ summary="Get agent by version",
tags=["store"],
response_model=backend.server.v2.store.model.StoreAgentDetails,
)
@@ -257,6 +263,7 @@ async def get_store_agent(
@router.post(
"/agents/{username}/{agent_name}/review",
+ summary="Create agent review",
tags=["store"],
dependencies=[fastapi.Depends(autogpt_libs.auth.middleware.auth_middleware)],
response_model=backend.server.v2.store.model.StoreReview,
@@ -308,6 +315,7 @@ async def create_review(
@router.get(
"/creators",
+ summary="List store creators",
tags=["store", "public"],
response_model=backend.server.v2.store.model.CreatorsResponse,
)
@@ -359,6 +367,7 @@ async def get_creators(
@router.get(
"/creator/{username}",
+ summary="Get creator details",
tags=["store", "public"],
response_model=backend.server.v2.store.model.CreatorDetails,
)
@@ -390,6 +399,7 @@ async def get_creator(
############################################
@router.get(
"/myagents",
+ summary="Get my agents",
tags=["store", "private"],
dependencies=[fastapi.Depends(autogpt_libs.auth.middleware.auth_middleware)],
response_model=backend.server.v2.store.model.MyAgentsResponse,
@@ -412,6 +422,7 @@ async def get_my_agents(
@router.delete(
"/submissions/{submission_id}",
+ summary="Delete store submission",
tags=["store", "private"],
dependencies=[fastapi.Depends(autogpt_libs.auth.middleware.auth_middleware)],
response_model=bool,
@@ -448,6 +459,7 @@ async def delete_submission(
@router.get(
"/submissions",
+ summary="List my submissions",
tags=["store", "private"],
dependencies=[fastapi.Depends(autogpt_libs.auth.middleware.auth_middleware)],
response_model=backend.server.v2.store.model.StoreSubmissionsResponse,
@@ -501,6 +513,7 @@ async def get_submissions(
@router.post(
"/submissions",
+ summary="Create store submission",
tags=["store", "private"],
dependencies=[fastapi.Depends(autogpt_libs.auth.middleware.auth_middleware)],
response_model=backend.server.v2.store.model.StoreSubmission,
@@ -548,6 +561,7 @@ async def create_submission(
@router.post(
"/submissions/media",
+ summary="Upload submission media",
tags=["store", "private"],
dependencies=[fastapi.Depends(autogpt_libs.auth.middleware.auth_middleware)],
)
@@ -585,6 +599,7 @@ async def upload_submission_media(
@router.post(
"/submissions/generate_image",
+ summary="Generate submission image",
tags=["store", "private"],
dependencies=[fastapi.Depends(autogpt_libs.auth.middleware.auth_middleware)],
)
@@ -646,6 +661,7 @@ async def generate_image(
@router.get(
"/download/agents/{store_listing_version_id}",
+ summary="Download agent file",
tags=["store", "public"],
)
async def download_agent_file(
diff --git a/autogpt_platform/backend/backend/server/v2/turnstile/routes.py b/autogpt_platform/backend/backend/server/v2/turnstile/routes.py
index d1803df584..7a4fe5bafa 100644
--- a/autogpt_platform/backend/backend/server/v2/turnstile/routes.py
+++ b/autogpt_platform/backend/backend/server/v2/turnstile/routes.py
@@ -13,7 +13,9 @@ router = APIRouter()
settings = Settings()
-@router.post("/verify", response_model=TurnstileVerifyResponse)
+@router.post(
+ "/verify", response_model=TurnstileVerifyResponse, summary="Verify Turnstile Token"
+)
async def verify_turnstile_token(
request: TurnstileVerifyRequest,
) -> TurnstileVerifyResponse:
diff --git a/autogpt_platform/backend/backend/util/decorator.py b/autogpt_platform/backend/backend/util/decorator.py
index 9047ea0b77..84f128333f 100644
--- a/autogpt_platform/backend/backend/util/decorator.py
+++ b/autogpt_platform/backend/backend/util/decorator.py
@@ -2,7 +2,7 @@ import functools
import logging
import os
import time
-from typing import Callable, ParamSpec, Tuple, TypeVar
+from typing import Any, Awaitable, Callable, Coroutine, ParamSpec, Tuple, TypeVar
from pydantic import BaseModel
@@ -32,7 +32,7 @@ logger = logging.getLogger(__name__)
def time_measured(func: Callable[P, T]) -> Callable[P, Tuple[TimingInfo, T]]:
"""
- Decorator to measure the time taken by a function to execute.
+ Decorator to measure the time taken by a synchronous function to execute.
"""
@functools.wraps(func)
@@ -50,6 +50,28 @@ def time_measured(func: Callable[P, T]) -> Callable[P, Tuple[TimingInfo, T]]:
return wrapper
+def async_time_measured(
+ func: Callable[P, Awaitable[T]],
+) -> Callable[P, Awaitable[Tuple[TimingInfo, T]]]:
+ """
+ Decorator to measure the time taken by an async function to execute.
+ """
+
+ @functools.wraps(func)
+ async def async_wrapper(*args: P.args, **kwargs: P.kwargs) -> Tuple[TimingInfo, T]:
+ start_wall_time, start_cpu_time = _start_measurement()
+ try:
+ result = await func(*args, **kwargs)
+ finally:
+ wall_duration, cpu_duration = _end_measurement(
+ start_wall_time, start_cpu_time
+ )
+ timing_info = TimingInfo(cpu_time=cpu_duration, wall_time=wall_duration)
+ return timing_info, result
+
+ return async_wrapper
+
+
def error_logged(func: Callable[P, T]) -> Callable[P, T | None]:
"""
Decorator to suppress and log any exceptions raised by a function.
@@ -65,3 +87,22 @@ def error_logged(func: Callable[P, T]) -> Callable[P, T | None]:
)
return wrapper
+
+
+def async_error_logged(
+ func: Callable[P, Coroutine[Any, Any, T]],
+) -> Callable[P, Coroutine[Any, Any, T | None]]:
+ """
+ Decorator to suppress and log any exceptions raised by an async function.
+ """
+
+ @functools.wraps(func)
+ async def wrapper(*args: P.args, **kwargs: P.kwargs) -> T | None:
+ try:
+ return await func(*args, **kwargs)
+ except Exception as e:
+ logger.exception(
+ f"Error when calling async function {func.__name__} with arguments {args} {kwargs}: {e}"
+ )
+
+ return wrapper
diff --git a/autogpt_platform/backend/backend/util/file.py b/autogpt_platform/backend/backend/util/file.py
index 5b876a3ec0..27ad4cdd19 100644
--- a/autogpt_platform/backend/backend/util/file.py
+++ b/autogpt_platform/backend/backend/util/file.py
@@ -7,7 +7,7 @@ import uuid
from pathlib import Path
from urllib.parse import urlparse
-from backend.util.request import requests
+from backend.util.request import Requests
from backend.util.type import MediaFileType
TEMP_DIR = Path(tempfile.gettempdir()).resolve()
@@ -29,7 +29,7 @@ def clean_exec_files(graph_exec_id: str, file: str = "") -> None:
shutil.rmtree(exec_path)
-def store_media_file(
+async def store_media_file(
graph_exec_id: str, file: MediaFileType, return_content: bool = False
) -> MediaFileType:
"""
@@ -114,8 +114,7 @@ def store_media_file(
target_path = _ensure_inside_base(base_path / filename, base_path)
# Download and save
- resp = requests.get(file)
- resp.raise_for_status()
+ resp = await Requests().get(file)
target_path.write_bytes(resp.content)
else:
diff --git a/autogpt_platform/backend/backend/util/logging.py b/autogpt_platform/backend/backend/util/logging.py
index 40dfb52a9f..9b6a64deac 100644
--- a/autogpt_platform/backend/backend/util/logging.py
+++ b/autogpt_platform/backend/backend/util/logging.py
@@ -61,6 +61,7 @@ class TruncatedLogger:
def _wrap(self, msg: str, **extra):
extra_msg = str(extra or "")
- if len(extra_msg) > 1000:
- extra_msg = extra_msg[:1000] + "..."
- return f"{self.prefix} {msg} {extra_msg}"
+ text = f"{self.prefix} {msg} {extra_msg}"
+ if len(text) > self.max_length:
+ text = text[: self.max_length] + "..."
+ return text
diff --git a/autogpt_platform/backend/backend/util/metrics.py b/autogpt_platform/backend/backend/util/metrics.py
index 3e1822fad0..f169887307 100644
--- a/autogpt_platform/backend/backend/util/metrics.py
+++ b/autogpt_platform/backend/backend/util/metrics.py
@@ -1,4 +1,3 @@
-import asyncio
import logging
import sentry_sdk
@@ -31,7 +30,7 @@ def sentry_capture_error(error: Exception):
sentry_sdk.flush()
-def discord_send_alert(content: str):
+async def discord_send_alert(content: str):
from backend.blocks.discord import SendDiscordMessageBlock
from backend.data.model import APIKeyCredentials, CredentialsMetaInput, ProviderName
from backend.util.settings import Settings
@@ -44,13 +43,7 @@ def discord_send_alert(content: str):
expires_at=None,
)
- try:
- loop = asyncio.get_event_loop()
- except RuntimeError:
- loop = asyncio.new_event_loop()
- asyncio.set_event_loop(loop)
-
- return SendDiscordMessageBlock().run_once(
+ return await SendDiscordMessageBlock().run_once(
SendDiscordMessageBlock.Input(
credentials=CredentialsMetaInput(
id=creds.id,
diff --git a/autogpt_platform/backend/backend/util/request.py b/autogpt_platform/backend/backend/util/request.py
index 4dfd32a12a..9a4ee81392 100644
--- a/autogpt_platform/backend/backend/util/request.py
+++ b/autogpt_platform/backend/backend/util/request.py
@@ -1,17 +1,22 @@
+import asyncio
import ipaddress
import re
import socket
import ssl
-from typing import Callable, Optional
+from io import BytesIO
+from typing import Any, Callable, Optional
from urllib.parse import ParseResult as URL
from urllib.parse import quote, urljoin, urlparse
+import aiohttp
import idna
-import requests as req
-from requests.adapters import HTTPAdapter
-from urllib3 import PoolManager
+from aiohttp import FormData, abc
+from tenacity import retry, retry_if_result, wait_exponential_jitter
-from backend.util.settings import Config
+from backend.util.json import json
+
+# Retry status codes for which we will automatically retry the request
+THROTTLE_RETRY_STATUS_CODES: set[int] = {429, 500, 502, 503, 504, 408}
# List of IP networks to block
BLOCKED_IP_NETWORKS = [
@@ -61,26 +66,61 @@ def _remove_insecure_headers(headers: dict, old_url: URL, new_url: URL) -> dict:
return headers
-class HostSSLAdapter(HTTPAdapter):
+class HostResolver(abc.AbstractResolver):
"""
- A custom adapter that connects to an IP address but still
+ A custom resolver that connects to specified IP addresses but still
sets the TLS SNI to the original host name so the cert can match.
"""
- def __init__(self, ssl_hostname, *args, **kwargs):
+ def __init__(self, ssl_hostname: str, ip_addresses: list[str]):
self.ssl_hostname = ssl_hostname
- super().__init__(*args, **kwargs)
+ self.ip_addresses = ip_addresses
+ self._default = aiohttp.AsyncResolver()
- def init_poolmanager(self, *args, **kwargs):
- self.poolmanager = PoolManager(
- *args,
- ssl_context=ssl.create_default_context(),
- server_hostname=self.ssl_hostname, # This works for urllib3>=2
- **kwargs,
- )
+ async def resolve(self, host, port=0, family=socket.AF_INET):
+ if host == self.ssl_hostname:
+ results = []
+ for ip in self.ip_addresses:
+ results.append(
+ {
+ "hostname": self.ssl_hostname,
+ "host": ip,
+ "port": port,
+ "family": family,
+ "proto": 0,
+ "flags": socket.AI_NUMERICHOST,
+ }
+ )
+ return results
+ return await self._default.resolve(host, port, family)
+
+ async def close(self):
+ await self._default.close()
-def validate_url(url: str, trusted_origins: list[str]) -> tuple[URL, bool, list[str]]:
+async def _resolve_host(hostname: str) -> list[str]:
+ """
+ Resolves the hostname to a list of IP addresses (IPv4 first, then IPv6).
+ """
+ loop = asyncio.get_running_loop()
+ try:
+ infos = await loop.getaddrinfo(hostname, None)
+ except socket.gaierror:
+ raise ValueError(f"Unable to resolve IP address for hostname {hostname}")
+
+ ip_list = [info[4][0] for info in infos]
+ ipv4 = [ip for ip in ip_list if ":" not in ip]
+ ipv6 = [ip for ip in ip_list if ":" in ip]
+ ip_addresses = ipv4 + ipv6
+
+ if not ip_addresses:
+ raise ValueError(f"No IP addresses found for {hostname}")
+ return ip_addresses
+
+
+async def validate_url(
+ url: str, trusted_origins: list[str]
+) -> tuple[URL, bool, list[str]]:
"""
Validates the URL to prevent SSRF attacks by ensuring it does not point
to a private, link-local, or otherwise blocked IP address — unless
@@ -125,7 +165,7 @@ def validate_url(url: str, trusted_origins: list[str]) -> tuple[URL, bool, list[
ip_addresses: list[str] = []
if not is_trusted:
# Resolve all IP addresses for the hostname
- ip_addresses = _resolve_host(ascii_hostname)
+ ip_addresses = await _resolve_host(ascii_hostname)
# Block any IP address that belongs to a blocked range
for ip_str in ip_addresses:
@@ -165,7 +205,9 @@ def pin_url(url: URL, ip_addresses: Optional[list[str]] = None) -> URL:
if not ip_addresses:
# Resolve all IP addresses for the hostname
- ip_addresses = _resolve_host(url.hostname)
+ # (This call is blocking; ensure to call async _resolve_host before if possible)
+ ip_addresses = []
+ # You may choose to raise or call synchronous resolve here; for simplicity, leave empty.
# Pin to the first valid IP (for SSRF defense)
pinned_ip = ip_addresses[0]
@@ -189,23 +231,58 @@ def pin_url(url: URL, ip_addresses: Optional[list[str]] = None) -> URL:
)
-def _resolve_host(hostname: str) -> list[str]:
- try:
- ip_list = [str(res[4][0]) for res in socket.getaddrinfo(hostname, None)]
- ipv4 = [ip for ip in ip_list if ":" not in ip]
- ipv6 = [ip for ip in ip_list if ":" in ip]
- ip_addresses = ipv4 + ipv6 # Prefer IPv4 over IPv6
- except socket.gaierror:
- raise ValueError(f"Unable to resolve IP address for hostname {hostname}")
+ClientResponse = aiohttp.ClientResponse
+ClientResponseError = aiohttp.ClientResponseError
- if not ip_addresses:
- raise ValueError(f"No IP addresses found for {hostname}")
- return ip_addresses
+
+class Response:
+ """
+ Buffered wrapper around aiohttp.ClientResponse that does *not* require
+ callers to manage connection or session lifetimes.
+ """
+
+ def __init__(
+ self,
+ *,
+ response: ClientResponse,
+ url: str,
+ body: bytes,
+ ):
+ self.status: int = response.status
+ self.headers = response.headers
+ self.reason: str | None = response.reason
+ self.request_info = response.request_info
+ self.url: str = url
+ self.content: bytes = body # raw bytes
+
+ def json(self, encoding: str | None = None, **kwargs) -> dict:
+ """
+ Parse the body as JSON and return the resulting Python object.
+ """
+ return json.loads(
+ self.content.decode(encoding or "utf-8", errors="replace"), **kwargs
+ )
+
+ def text(self, encoding: str | None = None) -> str:
+ """
+ Decode the body to a string. Encoding is guessed from the
+ Content-Type header if not supplied.
+ """
+ if encoding is None:
+ # Try to extract charset from headers; fall back to UTF-8
+ ctype = self.headers.get("content-type", "")
+ match = re.search(r"charset=([^\s;]+)", ctype, flags=re.I)
+ encoding = match.group(1) if match else None
+ return self.content.decode(encoding or "utf-8", errors="replace")
+
+ @property
+ def ok(self) -> bool:
+ return 200 <= self.status < 300
class Requests:
"""
- A wrapper around the requests library that validates URLs before
+ A wrapper around an aiohttp ClientSession that validates URLs before
making requests, preventing SSRF by blocking private networks and
other disallowed address spaces.
"""
@@ -216,6 +293,7 @@ class Requests:
raise_for_status: bool = True,
extra_url_validator: Callable[[URL], URL] | None = None,
extra_headers: dict[str, str] | None = None,
+ retry_max_wait: float = 300.0,
):
self.trusted_origins = []
for url in trusted_origins or []:
@@ -227,113 +305,196 @@ class Requests:
self.raise_for_status = raise_for_status
self.extra_url_validator = extra_url_validator
self.extra_headers = extra_headers
+ self.retry_max_wait = retry_max_wait
- def request(
+ async def request(
self,
- method,
- url,
- headers=None,
- allow_redirects=True,
- max_redirects=10,
- *args,
+ method: str,
+ url: str,
+ *,
+ headers: Optional[dict] = None,
+ files: list[tuple[str, tuple[str, BytesIO, str]]] | None = None,
+ data: Any | None = None,
+ json: Any | None = None,
+ allow_redirects: bool = True,
+ max_redirects: int = 10,
**kwargs,
- ) -> req.Response:
- # Validate URL and get trust status
- url, is_trusted, ip_addresses = validate_url(url, self.trusted_origins)
-
- # Apply any extra user-defined validation/transformation
- if self.extra_url_validator is not None:
- url = self.extra_url_validator(url)
-
- # Pin the URL if untrusted
- hostname = url.hostname
- original_url = url.geturl()
- if not is_trusted:
- url = pin_url(url, ip_addresses)
-
- # Merge any extra headers
- headers = dict(headers) if headers else {}
- if self.extra_headers is not None:
- headers.update(self.extra_headers)
-
- session = req.Session()
-
- # If untrusted, the hostname in the URL is replaced with the corresponding
- # IP address, and we need to override the Host header with the actual hostname.
- if url.hostname != hostname:
- headers["Host"] = hostname
-
- # If hostname was untrusted and we replaced it by (pinned it to) its IP,
- # we also need to attach a custom SNI adapter to make SSL work:
- adapter = HostSSLAdapter(ssl_hostname=hostname)
- session.mount("https://", adapter)
-
- # Perform the request with redirects disabled for manual handling
- response = session.request(
- method,
- url.geturl(),
- headers=headers,
- allow_redirects=False,
- *args,
- **kwargs,
+ ) -> Response:
+ @retry(
+ wait=wait_exponential_jitter(max=self.retry_max_wait),
+ retry=retry_if_result(lambda r: r.status in THROTTLE_RETRY_STATUS_CODES),
+ reraise=True,
)
-
- # Replace response URLs with the original host for clearer error messages
- if url.hostname != hostname:
- response.url = original_url
- if response.request is not None:
- response.request.url = original_url
-
- if self.raise_for_status:
- response.raise_for_status()
-
- # If allowed and a redirect is received, follow the redirect manually
- if allow_redirects and response.is_redirect:
- if max_redirects <= 0:
- raise Exception("Too many redirects.")
-
- location = response.headers.get("Location")
- if not location:
- return response
-
- # The base URL is the pinned_url we just used
- # so that relative redirects resolve correctly.
- redirect_url = urlparse(urljoin(url.geturl(), location))
- # Carry forward the same headers but update Host
- new_headers = _remove_insecure_headers(headers, url, redirect_url)
-
- return self.request(
- method,
- redirect_url.geturl(),
- headers=new_headers,
+ async def _make_request() -> Response:
+ return await self._request(
+ method=method,
+ url=url,
+ headers=headers,
+ files=files,
+ data=data,
+ json=json,
allow_redirects=allow_redirects,
- max_redirects=max_redirects - 1,
- *args,
+ max_redirects=max_redirects,
**kwargs,
)
- return response
+ return await _make_request()
- def get(self, url, *args, **kwargs) -> req.Response:
- return self.request("GET", url, *args, **kwargs)
+ async def _request(
+ self,
+ method: str,
+ url: str,
+ *,
+ headers: Optional[dict] = None,
+ files: list[tuple[str, tuple[str, BytesIO, str]]] | None = None,
+ data: Any | None = None,
+ json: Any | None = None,
+ allow_redirects: bool = True,
+ max_redirects: int = 10,
+ **kwargs,
+ ) -> Response:
+ if files is not None:
+ if json is not None:
+ raise ValueError(
+ "Cannot mix file uploads with JSON body; "
+ "use 'data' for extra form fields instead."
+ )
- def post(self, url, *args, **kwargs) -> req.Response:
- return self.request("POST", url, *args, **kwargs)
+ form = FormData(quote_fields=False)
+ # add normal form fields first
+ if isinstance(data, dict):
+ for k, v in data.items():
+ form.add_field(k, str(v))
+ elif data is not None:
+ raise ValueError(
+ "When uploading files, 'data' must be a dict of form fields."
+ )
- def put(self, url, *args, **kwargs) -> req.Response:
- return self.request("PUT", url, *args, **kwargs)
+ # add the file parts
+ for field_name, (filename, fh, content_type) in files:
+ form.add_field(
+ name=field_name,
+ value=fh,
+ filename=filename,
+ content_type=content_type or "application/octet-stream",
+ )
- def delete(self, url, *args, **kwargs) -> req.Response:
- return self.request("DELETE", url, *args, **kwargs)
+ data = form
- def head(self, url, *args, **kwargs) -> req.Response:
- return self.request("HEAD", url, *args, **kwargs)
+ # Validate URL and get trust status
+ parsed_url, is_trusted, ip_addresses = await validate_url(
+ url, self.trusted_origins
+ )
- def options(self, url, *args, **kwargs) -> req.Response:
- return self.request("OPTIONS", url, *args, **kwargs)
+ # Apply any extra user-defined validation/transformation
+ if self.extra_url_validator is not None:
+ parsed_url = self.extra_url_validator(parsed_url)
- def patch(self, url, *args, **kwargs) -> req.Response:
- return self.request("PATCH", url, *args, **kwargs)
+ # Pin the URL if untrusted
+ hostname = parsed_url.hostname
+ if hostname is None:
+ raise ValueError(f"Invalid URL: Unable to determine hostname of {url}")
+ original_url = parsed_url.geturl()
+ connector: Optional[aiohttp.TCPConnector] = None
+ if not is_trusted:
+ # Replace hostname with IP for connection but preserve SNI via resolver
+ resolver = HostResolver(ssl_hostname=hostname, ip_addresses=ip_addresses)
+ ssl_context = ssl.create_default_context()
+ connector = aiohttp.TCPConnector(resolver=resolver, ssl=ssl_context)
+ session_kwargs = {}
+ if connector:
+ session_kwargs["connector"] = connector
-requests = Requests(trusted_origins=Config().trust_endpoints_for_requests)
+ # Merge any extra headers
+ req_headers = dict(headers) if headers else {}
+ if self.extra_headers is not None:
+ req_headers.update(self.extra_headers)
+
+ # Override Host header if using IP connection
+ if connector:
+ req_headers["Host"] = hostname
+
+ # Override data if files are provided
+
+ async with aiohttp.ClientSession(**session_kwargs) as session:
+ # Perform the request with redirects disabled for manual handling
+ async with session.request(
+ method,
+ parsed_url.geturl(),
+ headers=req_headers,
+ allow_redirects=False,
+ data=data,
+ json=json,
+ **kwargs,
+ ) as response:
+
+ if self.raise_for_status:
+ response.raise_for_status()
+
+ # If allowed and a redirect is received, follow the redirect manually
+ if allow_redirects and response.status in (301, 302, 303, 307, 308):
+ if max_redirects <= 0:
+ raise Exception("Too many redirects.")
+
+ location = response.headers.get("Location")
+ if not location:
+ return Response(
+ response=response,
+ url=original_url,
+ body=await response.read(),
+ )
+
+ # The base URL is the pinned_url we just used
+ # so that relative redirects resolve correctly.
+ redirect_url = urlparse(urljoin(parsed_url.geturl(), location))
+ # Carry forward the same headers but update Host
+ new_headers = _remove_insecure_headers(
+ req_headers, parsed_url, redirect_url
+ )
+
+ return await self.request(
+ method,
+ redirect_url.geturl(),
+ headers=new_headers,
+ allow_redirects=allow_redirects,
+ max_redirects=max_redirects - 1,
+ files=files,
+ data=data,
+ json=json,
+ **kwargs,
+ )
+
+ # Reset response URL to original host for clarity
+ if parsed_url.hostname != hostname:
+ try:
+ response.url = original_url # type: ignore
+ except Exception:
+ pass
+
+ return Response(
+ response=response,
+ url=original_url,
+ body=await response.read(),
+ )
+
+ async def get(self, url: str, *args, **kwargs) -> Response:
+ return await self.request("GET", url, *args, **kwargs)
+
+ async def post(self, url: str, *args, **kwargs) -> Response:
+ return await self.request("POST", url, *args, **kwargs)
+
+ async def put(self, url: str, *args, **kwargs) -> Response:
+ return await self.request("PUT", url, *args, **kwargs)
+
+ async def delete(self, url: str, *args, **kwargs) -> Response:
+ return await self.request("DELETE", url, *args, **kwargs)
+
+ async def head(self, url: str, *args, **kwargs) -> Response:
+ return await self.request("HEAD", url, *args, **kwargs)
+
+ async def options(self, url: str, *args, **kwargs) -> Response:
+ return await self.request("OPTIONS", url, *args, **kwargs)
+
+ async def patch(self, url: str, *args, **kwargs) -> Response:
+ return await self.request("PATCH", url, *args, **kwargs)
diff --git a/autogpt_platform/backend/backend/util/service.py b/autogpt_platform/backend/backend/util/service.py
index 91eef36def..abcfd75dd3 100644
--- a/autogpt_platform/backend/backend/util/service.py
+++ b/autogpt_platform/backend/backend/util/service.py
@@ -24,6 +24,12 @@ import httpx
import uvicorn
from fastapi import FastAPI, Request, responses
from pydantic import BaseModel, TypeAdapter, create_model
+from tenacity import (
+ retry,
+ retry_if_exception_type,
+ stop_after_attempt,
+ wait_exponential_jitter,
+)
from backend.util.exceptions import InsufficientBalanceError
from backend.util.json import to_dict
@@ -248,9 +254,39 @@ def get_service_client(
service_client_type: Type[ASC],
call_timeout: int | None = api_call_timeout,
health_check: bool = True,
+ request_retry: bool | int = False,
) -> ASC:
+
+ def _maybe_retry(fn: Callable[..., R]) -> Callable[..., R]:
+ """Decorate *fn* with tenacity retry when enabled."""
+ nonlocal request_retry
+
+ if isinstance(request_retry, int):
+ retry_attempts = request_retry
+ request_retry = True
+ else:
+ retry_attempts = api_comm_retry
+
+ if not request_retry:
+ return fn
+
+ return retry(
+ reraise=True,
+ stop=stop_after_attempt(retry_attempts),
+ wait=wait_exponential_jitter(max=4.0),
+ retry=retry_if_exception_type(
+ (
+ httpx.ConnectError,
+ httpx.ReadTimeout,
+ httpx.WriteTimeout,
+ httpx.ConnectTimeout,
+ httpx.RemoteProtocolError,
+ )
+ ),
+ )(fn)
+
class DynamicClient:
- def __init__(self):
+ def __init__(self) -> None:
service_type = service_client_type.get_service_type()
host = service_type.get_host()
port = service_type.get_port()
@@ -271,7 +307,7 @@ def get_service_client(
)
def _handle_call_method_response(
- self, response: httpx.Response, method_name: str
+ self, *, response: httpx.Response, method_name: str
) -> Any:
try:
response.raise_for_status()
@@ -284,13 +320,15 @@ def get_service_client(
*(error.args or [str(e)])
)
- def _call_method_sync(self, method_name: str, **kwargs) -> Any:
+ @_maybe_retry
+ def _call_method_sync(self, method_name: str, **kwargs: Any) -> Any:
return self._handle_call_method_response(
method_name=method_name,
response=self.sync_client.post(method_name, json=to_dict(kwargs)),
)
- async def _call_method_async(self, method_name: str, **kwargs) -> Any:
+ @_maybe_retry
+ async def _call_method_async(self, method_name: str, **kwargs: Any) -> Any:
return self._handle_call_method_response(
method_name=method_name,
response=await self.async_client.post(
@@ -298,17 +336,19 @@ def get_service_client(
),
)
- async def aclose(self):
+ async def aclose(self) -> None:
self.sync_client.close()
await self.async_client.aclose()
- def close(self):
+ def close(self) -> None:
self.sync_client.close()
- def _get_params(self, signature: inspect.Signature, *args, **kwargs) -> dict:
+ def _get_params(
+ self, signature: inspect.Signature, *args: Any, **kwargs: Any
+ ) -> dict[str, Any]:
if args:
arg_names = list(signature.parameters.keys())
- if arg_names[0] in ("self", "cls"):
+ if arg_names and arg_names[0] in ("self", "cls"):
arg_names = arg_names[1:]
kwargs.update(dict(zip(arg_names, args)))
return kwargs
@@ -324,35 +364,34 @@ def get_service_client(
raise AttributeError(
f"Method {name} not found in {service_client_type}"
)
- else:
- name = original_func.__name__
+ rpc_name = original_func.__name__
sig = inspect.signature(original_func)
ret_ann = sig.return_annotation
- if ret_ann != inspect.Signature.empty:
- expected_return = TypeAdapter(ret_ann)
- else:
- expected_return = None
+ expected_return = (
+ None if ret_ann is inspect.Signature.empty else TypeAdapter(ret_ann)
+ )
if inspect.iscoroutinefunction(original_func):
- async def async_method(*args, **kwargs) -> Any:
+ async def async_method(*args: P.args, **kwargs: P.kwargs):
params = self._get_params(sig, *args, **kwargs)
- result = await self._call_method_async(name, **params)
+ result = await self._call_method_async(rpc_name, **params)
return self._get_return(expected_return, result)
return async_method
+
else:
- def sync_method(*args, **kwargs) -> Any:
+ def sync_method(*args: P.args, **kwargs: P.kwargs):
params = self._get_params(sig, *args, **kwargs)
- result = self._call_method_sync(name, **params)
+ result = self._call_method_sync(rpc_name, **params)
return self._get_return(expected_return, result)
return sync_method
client = cast(ASC, DynamicClient())
- if health_check:
+ if health_check and hasattr(client, "health_check"):
client.health_check()
return client
diff --git a/autogpt_platform/backend/backend/util/settings.py b/autogpt_platform/backend/backend/util/settings.py
index c349f0c804..b2691cfd18 100644
--- a/autogpt_platform/backend/backend/util/settings.py
+++ b/autogpt_platform/backend/backend/util/settings.py
@@ -59,12 +59,6 @@ class Config(UpdateTrackingModel["Config"], BaseSettings):
le=1000,
description="Maximum number of workers to use for graph execution.",
)
- num_node_workers: int = Field(
- default=5,
- ge=1,
- le=1000,
- description="Maximum number of workers to use for node execution within a single graph.",
- )
pyro_host: str = Field(
default="localhost",
description="The default hostname of the Pyro server.",
diff --git a/autogpt_platform/backend/backend/util/test.py b/autogpt_platform/backend/backend/util/test.py
index 06a1f44f63..72a39d4027 100644
--- a/autogpt_platform/backend/backend/util/test.py
+++ b/autogpt_platform/backend/backend/util/test.py
@@ -1,3 +1,4 @@
+import inspect
import logging
import time
import uuid
@@ -93,7 +94,7 @@ async def wait_execution(
assert False, "Execution did not complete in time."
-def execute_block_test(block: Block):
+async def execute_block_test(block: Block):
prefix = f"[Test-{block.name}]"
if not block.test_input or not block.test_output:
@@ -110,10 +111,25 @@ def execute_block_test(block: Block):
for mock_name, mock_obj in (block.test_mock or {}).items():
log.info(f"{prefix} mocking {mock_name}...")
- if hasattr(block, mock_name):
- setattr(block, mock_name, mock_obj)
- else:
+ # check whether the field mock_name is an async function or not
+ if not hasattr(block, mock_name):
log.info(f"{prefix} mock {mock_name} not found in block")
+ continue
+
+ fun = getattr(block, mock_name)
+ is_async = inspect.iscoroutinefunction(fun) or inspect.isasyncgenfunction(fun)
+
+ if is_async:
+
+ async def async_mock(
+ *args, _mock_name=mock_name, _mock_obj=mock_obj, **kwargs
+ ):
+ return _mock_obj(*args, **kwargs)
+
+ setattr(block, mock_name, async_mock)
+
+ else:
+ setattr(block, mock_name, mock_obj)
# Populate credentials argument(s)
extra_exec_kwargs: dict = {
@@ -141,7 +157,9 @@ def execute_block_test(block: Block):
for input_data in block.test_input:
log.info(f"{prefix} in: {input_data}")
- for output_name, output_data in block.execute(input_data, **extra_exec_kwargs):
+ async for output_name, output_data in block.execute(
+ input_data, **extra_exec_kwargs
+ ):
if output_index >= len(block.test_output):
raise ValueError(
f"{prefix} produced output more than expected {output_index} >= {len(block.test_output)}:\nOutput Expected:\t\t{block.test_output}\nFailed Output Produced:\t('{output_name}', {output_data})\nNote that this may not be the one that was unexpected, but it is the first that triggered the extra output warning"
diff --git a/autogpt_platform/backend/migrations/20250620000924_make_data_nullable/migration.sql b/autogpt_platform/backend/migrations/20250620000924_make_data_nullable/migration.sql
new file mode 100644
index 0000000000..54a29f3214
--- /dev/null
+++ b/autogpt_platform/backend/migrations/20250620000924_make_data_nullable/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "AgentNodeExecutionInputOutput" ALTER COLUMN "data" DROP NOT NULL;
diff --git a/autogpt_platform/backend/poetry.lock b/autogpt_platform/backend/poetry.lock
index 00411f1535..4ea22878d4 100644
--- a/autogpt_platform/backend/poetry.lock
+++ b/autogpt_platform/backend/poetry.lock
@@ -17,6 +17,33 @@ aiormq = ">=6.8,<6.9"
exceptiongroup = ">=1,<2"
yarl = "*"
+[[package]]
+name = "aiodns"
+version = "3.4.0"
+description = "Simple DNS resolver for asyncio"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "aiodns-3.4.0-py3-none-any.whl", hash = "sha256:4da2b25f7475343f3afbb363a2bfe46afa544f2b318acb9a945065e622f4ed24"},
+ {file = "aiodns-3.4.0.tar.gz", hash = "sha256:24b0ae58410530367f21234d0c848e4de52c1f16fbddc111726a4ab536ec1b2f"},
+]
+
+[package.dependencies]
+pycares = ">=4.0.0"
+
+[[package]]
+name = "aiofiles"
+version = "24.1.0"
+description = "File support for asyncio."
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5"},
+ {file = "aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c"},
+]
+
[[package]]
name = "aiohappyeyeballs"
version = "2.6.1"
@@ -303,13 +330,16 @@ develop = true
[package.dependencies]
colorama = "^0.4.6"
expiringdict = "^1.2.2"
+fastapi = "^0.115.12"
google-cloud-logging = "^3.12.1"
+launchdarkly-server-sdk = "^9.11.1"
pydantic = "^2.11.4"
pydantic-settings = "^2.9.1"
pyjwt = "^2.10.1"
pytest-asyncio = "^0.26.0"
pytest-mock = "^3.14.0"
supabase = "^2.15.1"
+uvicorn = "^0.34.3"
[package.source]
type = "directory"
@@ -3739,6 +3769,93 @@ files = [
[package.dependencies]
pyasn1 = ">=0.6.1,<0.7.0"
+[[package]]
+name = "pycares"
+version = "4.8.0"
+description = "Python interface for c-ares"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "pycares-4.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f40d9f4a8de398b110fdf226cdfadd86e8c7eb71d5298120ec41cf8d94b0012f"},
+ {file = "pycares-4.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:339de06fc849a51015968038d2bbed68fc24047522404af9533f32395ca80d25"},
+ {file = "pycares-4.8.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:372a236c1502b9056b0bea195c64c329603b4efa70b593a33b7ae37fbb7fad00"},
+ {file = "pycares-4.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03f66a5e143d102ccc204bd4e29edd70bed28420f707efd2116748241e30cb73"},
+ {file = "pycares-4.8.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ef50504296cd5fc58cfd6318f82e20af24fbe2c83004f6ff16259adb13afdf14"},
+ {file = "pycares-4.8.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1bc541b627c7951dd36136b18bd185c5244a0fb2af5b1492ffb8acaceec1c5b"},
+ {file = "pycares-4.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:938d188ed6bed696099be67ebdcdf121827b9432b17a9ea9e40dc35fd9d85363"},
+ {file = "pycares-4.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:327837ffdc0c7adda09c98e1263c64b2aff814eea51a423f66733c75ccd9a642"},
+ {file = "pycares-4.8.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a6b9b8d08c4508c45bd39e0c74e9e7052736f18ca1d25a289365bb9ac36e5849"},
+ {file = "pycares-4.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:feac07d5e6d2d8f031c71237c21c21b8c995b41a1eba64560e8cf1e42ac11bc6"},
+ {file = "pycares-4.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:5bcdbf37012fd2323ca9f2a1074421a9ccf277d772632f8f0ce8c46ec7564250"},
+ {file = "pycares-4.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e3ebb692cb43fcf34fe0d26f2cf9a0ea53fdfb136463845b81fad651277922db"},
+ {file = "pycares-4.8.0-cp310-cp310-win32.whl", hash = "sha256:d98447ec0efff3fa868ccc54dcc56e71faff498f8848ecec2004c3108efb4da2"},
+ {file = "pycares-4.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:1abb8f40917960ead3c2771277f0bdee1967393b0fdf68743c225b606787da68"},
+ {file = "pycares-4.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5e25db89005ddd8d9c5720293afe6d6dd92e682fc6bc7a632535b84511e2060d"},
+ {file = "pycares-4.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6f9665ef116e6ee216c396f5f927756c2164f9f3316aec7ff1a9a1e1e7ec9b2a"},
+ {file = "pycares-4.8.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54a96893133471f6889b577147adcc21a480dbe316f56730871028379c8313f3"},
+ {file = "pycares-4.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51024b3a69762bd3100d94986a29922be15e13f56f991aaefb41f5bcd3d7f0bb"},
+ {file = "pycares-4.8.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:47ff9db50c599e4d965ae3bec99cc30941c1d2b0f078ec816680b70d052dd54a"},
+ {file = "pycares-4.8.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:27ef8ff4e0f60ea6769a60d1c3d1d2aefed1d832e7bb83fc3934884e2dba5cdd"},
+ {file = "pycares-4.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63511af7a3f9663f562fbb6bfa3591a259505d976e2aba1fa2da13dde43c6ca7"},
+ {file = "pycares-4.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:73c3219b47616e6a5ad1810de96ed59721c7751f19b70ae7bf24997a8365408f"},
+ {file = "pycares-4.8.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:da42a45207c18f37be5e491c14b6d1063cfe1e46620eb661735d0cedc2b59099"},
+ {file = "pycares-4.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:8a068e898bb5dd09cd654e19cd2abf20f93d0cc59d5d955135ed48ea0f806aa1"},
+ {file = "pycares-4.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:962aed95675bb66c0b785a2fbbd1bb58ce7f009e283e4ef5aaa4a1f2dc00d217"},
+ {file = "pycares-4.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ce8b1a16c1e4517a82a0ebd7664783a327166a3764d844cf96b1fb7b9dd1e493"},
+ {file = "pycares-4.8.0-cp311-cp311-win32.whl", hash = "sha256:b3749ddbcbd216376c3b53d42d8b640b457133f1a12b0e003f3838f953037ae7"},
+ {file = "pycares-4.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:5ce8a4e1b485b2360ab666c4ea1db97f57ede345a3b566d80bfa52b17e616610"},
+ {file = "pycares-4.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3273e01a75308ed06d2492d83c7ba476e579a60a24d9f20fe178ce5e9d8d028b"},
+ {file = "pycares-4.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fcedaadea1f452911fd29935749f98d144dae758d6003b7e9b6c5d5bd47d1dff"},
+ {file = "pycares-4.8.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aae6cb33e287e06a4aabcbc57626df682c9a4fa8026207f5b498697f1c2fb562"},
+ {file = "pycares-4.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25038b930e5be82839503fb171385b2aefd6d541bc5b7da0938bdb67780467d2"},
+ {file = "pycares-4.8.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cc8499b6e7dfbe4af65f6938db710ce9acd1debf34af2cbb93b898b1e5da6a5a"},
+ {file = "pycares-4.8.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c4e1c6a68ef56a7622f6176d9946d4e51f3c853327a0123ef35a5380230c84cd"},
+ {file = "pycares-4.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7cc8c3c9114b9c84e4062d25ca9b4bddc80a65d0b074c7cb059275273382f89"},
+ {file = "pycares-4.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4404014069d3e362abf404c9932d4335bb9c07ba834cfe7d683c725b92e0f9da"},
+ {file = "pycares-4.8.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ee0a58c32ec2a352cef0e1d20335a7caf9871cd79b73be2ca2896fe70f09c9d7"},
+ {file = "pycares-4.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:35f32f52b486b8fede3cbebf088f30b01242d0321b5216887c28e80490595302"},
+ {file = "pycares-4.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:ecbb506e27a3b3a2abc001c77beeccf265475c84b98629a6b3e61bd9f2987eaa"},
+ {file = "pycares-4.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9392b2a34adbf60cb9e38f4a0d363413ecea8d835b5a475122f50f76676d59dd"},
+ {file = "pycares-4.8.0-cp312-cp312-win32.whl", hash = "sha256:f0fbefe68403ffcff19c869b8d621c88a6d2cef18d53cf0dab0fa9458a6ca712"},
+ {file = "pycares-4.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:fa8aab6085a2ddfb1b43a06ddf1b498347117bb47cd620d9b12c43383c9c2737"},
+ {file = "pycares-4.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:358a9a2c6fed59f62788e63d88669224955443048a1602016d4358e92aedb365"},
+ {file = "pycares-4.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e3e1278967fa8d4a0056be3fcc8fc551b8bad1fc7d0e5172196dccb8ddb036a"},
+ {file = "pycares-4.8.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:79befb773e370a8f97de9f16f5ea2c7e7fa0e3c6c74fbea6d332bf58164d7d06"},
+ {file = "pycares-4.8.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b00d3695db64ce98a34e632e1d53f5a1cdb25451489f227bec2a6c03ff87ee8"},
+ {file = "pycares-4.8.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:37bdc4f2ff0612d60fc4f7547e12ff02cdcaa9a9e42e827bb64d4748994719f1"},
+ {file = "pycares-4.8.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd92c44498ec7a6139888b464b28c49f7ba975933689bd67ea8d572b94188404"},
+ {file = "pycares-4.8.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2665a0d810e2bbc41e97f3c3e5ea7950f666b3aa19c5f6c99d6b018ccd2e0052"},
+ {file = "pycares-4.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45a629a6470a33478514c566bce50c63f1b17d1c5f2f964c9a6790330dc105fb"},
+ {file = "pycares-4.8.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:47bb378f1773f41cca8e31dcdf009ce4a9b8aff8a30c7267aaff9a099c407ba5"},
+ {file = "pycares-4.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fb3feae38458005cc101956e38f16eb3145fff8cd793e35cd4bdef6bf1aa2623"},
+ {file = "pycares-4.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:14bc28aeaa66b0f4331ac94455e8043c8a06b3faafd78cc49d4b677bae0d0b08"},
+ {file = "pycares-4.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:62c82b871470f2864a1febf7b96bb1d108ce9063e6d3d43727e8a46f0028a456"},
+ {file = "pycares-4.8.0-cp313-cp313-win32.whl", hash = "sha256:01afa8964c698c8f548b46d726f766aa7817b2d4386735af1f7996903d724920"},
+ {file = "pycares-4.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:22f86f81b12ab17b0a7bd0da1e27938caaed11715225c1168763af97f8bb51a7"},
+ {file = "pycares-4.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:61325d13a95255e858f42a7a1a9e482ff47ef2233f95ad9a4f308a3bd8ecf903"},
+ {file = "pycares-4.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dfec3a7d42336fa46a1e7e07f67000fd4b97860598c59a894c08f81378629e4e"},
+ {file = "pycares-4.8.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b65067e4b4f5345688817fff6be06b9b1f4ec3619b0b9ecc639bc681b73f646b"},
+ {file = "pycares-4.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0322ad94bbaa7016139b5bbdcd0de6f6feb9d146d69e03a82aaca342e06830a6"},
+ {file = "pycares-4.8.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:456c60f170c997f9a43c7afa1085fced8efb7e13ae49dd5656f998ae13c4bdb4"},
+ {file = "pycares-4.8.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57a2c4c9ce423a85b0e0227409dbaf0d478f5e0c31d9e626768e77e1e887d32f"},
+ {file = "pycares-4.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:478d9c479108b7527266864c0affe3d6e863492c9bc269217e36100c8fd89b91"},
+ {file = "pycares-4.8.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:aed56bca096990ca0aa9bbf95761fc87e02880e04b0845922b5c12ea9abe523f"},
+ {file = "pycares-4.8.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ef265a390928ee2f77f8901c2273c53293157860451ad453ce7f45dd268b72f9"},
+ {file = "pycares-4.8.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:a5f17d7a76d8335f1c90a8530c8f1e8bb22e9a1d70a96f686efaed946de1c908"},
+ {file = "pycares-4.8.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:891f981feb2ef34367378f813fc17b3d706ce95b6548eeea0c9fe7705d7e54b1"},
+ {file = "pycares-4.8.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:4102f6d9117466cc0a1f527907a1454d109cc9e8551b8074888071ef16050fe3"},
+ {file = "pycares-4.8.0-cp39-cp39-win32.whl", hash = "sha256:d6775308659652adc88c82c53eda59b5e86a154aaba5ad1e287bbb3e0be77076"},
+ {file = "pycares-4.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:8bc05462aa44788d48544cca3d2532466fed2cdc5a2f24a43a92b620a61c9d19"},
+ {file = "pycares-4.8.0.tar.gz", hash = "sha256:2fc2ebfab960f654b3e3cf08a732486950da99393a657f8b44618ad3ed2d39c1"},
+]
+
+[package.dependencies]
+cffi = ">=1.5.0"
+
+[package.extras]
+idna = ["idna (>=2.1)"]
+
[[package]]
name = "pycodestyle"
version = "2.13.0"
@@ -6252,4 +6369,4 @@ cffi = ["cffi (>=1.11)"]
[metadata]
lock-version = "2.1"
python-versions = ">=3.10,<3.13"
-content-hash = "8d59c154b4ec91c28424c552de7c85c6399efe24ab74a979bfd62275d112fbf0"
+content-hash = "6c93e51cf22c06548aa6d0e23ca8ceb4450f5e02d4142715e941aabc1a2cbd6a"
diff --git a/autogpt_platform/backend/pyproject.toml b/autogpt_platform/backend/pyproject.toml
index b54ba12b23..26c05668c0 100644
--- a/autogpt_platform/backend/pyproject.toml
+++ b/autogpt_platform/backend/pyproject.toml
@@ -10,6 +10,7 @@ packages = [{ include = "backend", format = "sdist" }]
[tool.poetry.dependencies]
python = ">=3.10,<3.13"
aio-pika = "^9.5.5"
+aiodns = "^3.1.1"
anthropic = "^0.51.0"
apscheduler = "^3.11.0"
autogpt-libs = { path = "../autogpt_libs", develop = true }
@@ -66,6 +67,7 @@ youtube-transcript-api = "^0.6.2"
zerobouncesdk = "^1.1.1"
# NOTE: please insert new dependencies in their alphabetical location
pytest-snapshot = "^0.9.0"
+aiofiles = "^24.1.0"
[tool.poetry.group.dev.dependencies]
aiohappyeyeballs = "^2.6.1"
diff --git a/autogpt_platform/backend/schema.prisma b/autogpt_platform/backend/schema.prisma
index a20a537fcb..58e724db9c 100644
--- a/autogpt_platform/backend/schema.prisma
+++ b/autogpt_platform/backend/schema.prisma
@@ -80,8 +80,8 @@ enum OnboardingStep {
}
model UserOnboarding {
- id String @id @default(uuid())
- createdAt DateTime @default(now())
+ id String @id @default(uuid())
+ createdAt DateTime @default(now())
updatedAt DateTime? @updatedAt
completedSteps OnboardingStep[] @default([])
@@ -122,7 +122,7 @@ model AgentGraph {
forkedFromId String?
forkedFromVersion Int?
- forkedFrom AgentGraph? @relation("AgentGraphForks", fields: [forkedFromId, forkedFromVersion], references: [id, version])
+ forkedFrom AgentGraph? @relation("AgentGraphForks", fields: [forkedFromId, forkedFromVersion], references: [id, version])
forks AgentGraph[] @relation("AgentGraphForks")
Nodes AgentNode[]
@@ -390,7 +390,7 @@ model AgentNodeExecutionInputOutput {
id String @id @default(uuid())
name String
- data Json
+ data Json?
time DateTime @default(now())
// Prisma requires explicit back-references.
diff --git a/autogpt_platform/backend/test/block/test_block.py b/autogpt_platform/backend/test/block/test_block.py
index 48d2616f61..3f4aedb1e9 100644
--- a/autogpt_platform/backend/test/block/test_block.py
+++ b/autogpt_platform/backend/test/block/test_block.py
@@ -7,5 +7,5 @@ from backend.util.test import execute_block_test
@pytest.mark.parametrize("block", get_blocks().values(), ids=lambda b: b.name)
-def test_available_blocks(block: Type[Block]):
- execute_block_test(block())
+async def test_available_blocks(block: Type[Block]):
+ await execute_block_test(block())
diff --git a/autogpt_platform/backend/test/executor/test_tool_use.py b/autogpt_platform/backend/test/executor/test_tool_use.py
index d93797633b..54ecfbce0a 100644
--- a/autogpt_platform/backend/test/executor/test_tool_use.py
+++ b/autogpt_platform/backend/test/executor/test_tool_use.py
@@ -22,11 +22,11 @@ async def create_graph(s: SpinTestServer, g: graph.Graph, u: User) -> graph.Grap
return await s.agent_server.test_create_graph(CreateGraph(graph=g), u.id)
-def create_credentials(s: SpinTestServer, u: User):
+async def create_credentials(s: SpinTestServer, u: User):
provider = ProviderName.OPENAI
credentials = llm.TEST_CREDENTIALS
try:
- s.agent_server.test_create_credentials(u.id, provider, credentials)
+ await s.agent_server.test_create_credentials(u.id, provider, credentials)
except Exception:
# ValueErrors is raised trying to recreate the same credentials
# so hidding the error
@@ -65,7 +65,7 @@ async def execute_graph(
async def test_graph_validation_with_tool_nodes_correct(server: SpinTestServer):
test_user = await create_test_user()
test_tool_graph = await create_graph(server, create_test_graph(), test_user)
- create_credentials(server, test_user)
+ await create_credentials(server, test_user)
nodes = [
graph.Node(
@@ -116,7 +116,7 @@ async def test_graph_validation_with_tool_nodes_raises_error(server: SpinTestSer
test_user = await create_test_user()
test_tool_graph = await create_graph(server, create_test_graph(), test_user)
- create_credentials(server, test_user)
+ await create_credentials(server, test_user)
nodes = [
graph.Node(
@@ -176,7 +176,7 @@ async def test_graph_validation_with_tool_nodes_raises_error(server: SpinTestSer
async def test_smart_decision_maker_function_signature(server: SpinTestServer):
test_user = await create_test_user()
test_tool_graph = await create_graph(server, create_test_graph(), test_user)
- create_credentials(server, test_user)
+ await create_credentials(server, test_user)
nodes = [
graph.Node(
diff --git a/autogpt_platform/backend/test/util/test_request.py b/autogpt_platform/backend/test/util/test_request.py
index e973e7dd6e..57717ff77f 100644
--- a/autogpt_platform/backend/test/util/test_request.py
+++ b/autogpt_platform/backend/test/util/test_request.py
@@ -54,14 +54,14 @@ from backend.util.request import pin_url, validate_url
("example.com?param=äöü", [], "http://example.com?param=äöü", False),
],
)
-def test_validate_url_no_dns_rebinding(
+async def test_validate_url_no_dns_rebinding(
raw_url: str, trusted_origins: list[str], expected_value: str, should_raise: bool
):
if should_raise:
with pytest.raises(ValueError):
- validate_url(raw_url, trusted_origins)
+ await validate_url(raw_url, trusted_origins)
else:
- validated_url, _, _ = validate_url(raw_url, trusted_origins)
+ validated_url, _, _ = await validate_url(raw_url, trusted_origins)
assert validated_url.geturl() == expected_value
@@ -78,7 +78,7 @@ def test_validate_url_no_dns_rebinding(
("blocked.com", ["127.0.0.1"], True, None),
],
)
-def test_dns_rebinding_fix(
+async def test_dns_rebinding_fix(
monkeypatch,
hostname: str,
resolved_ips: list[str],
@@ -100,10 +100,10 @@ def test_dns_rebinding_fix(
if expect_error:
# If any IP is blocked, we expect a ValueError
with pytest.raises(ValueError):
- url, _, ip_addresses = validate_url(hostname, [])
+ url, _, ip_addresses = await validate_url(hostname, [])
pin_url(url, ip_addresses)
else:
- url, _, ip_addresses = validate_url(hostname, [])
+ url, _, ip_addresses = await validate_url(hostname, [])
pinned_url = pin_url(url, ip_addresses).geturl()
# The pinned_url should contain the first valid IP
assert pinned_url.startswith("http://") or pinned_url.startswith("https://")
diff --git a/autogpt_platform/frontend/.env.example b/autogpt_platform/frontend/.env.example
index e3763c1da0..0660979013 100644
--- a/autogpt_platform/frontend/.env.example
+++ b/autogpt_platform/frontend/.env.example
@@ -8,6 +8,8 @@ NEXT_PUBLIC_LAUNCHDARKLY_ENABLED=false
NEXT_PUBLIC_LAUNCHDARKLY_CLIENT_ID=
NEXT_PUBLIC_APP_ENV=local
+NEXT_PUBLIC_AGPT_SERVER_BASE_URL=http://localhost:8006
+
## Locale settings
NEXT_PUBLIC_DEFAULT_LOCALE=en
@@ -33,3 +35,6 @@ NEXT_PUBLIC_SHOW_BILLING_PAGE=false
## This is the frontend site key
NEXT_PUBLIC_CLOUDFLARE_TURNSTILE_SITE_KEY=
NEXT_PUBLIC_TURNSTILE=disabled
+
+# Devtools
+NEXT_PUBLIC_REACT_QUERY_DEVTOOL=true
diff --git a/autogpt_platform/frontend/.eslintrc.json b/autogpt_platform/frontend/.eslintrc.json
index bb8b1c099d..04a3f05d0f 100644
--- a/autogpt_platform/frontend/.eslintrc.json
+++ b/autogpt_platform/frontend/.eslintrc.json
@@ -1,3 +1,26 @@
{
- "extends": ["next/core-web-vitals", "plugin:storybook/recommended"]
+ "extends": [
+ "next/core-web-vitals",
+ "next/typescript",
+ "plugin:storybook/recommended",
+ "plugin:@tanstack/query/recommended"
+ ],
+ "rules": {
+ // Disabling exhaustive-deps to avoid forcing unnecessary dependencies and useCallback proliferation.
+ // We rely on code review for proper dependency management instead of mechanical rule following.
+ // See: https://kentcdodds.com/blog/usememo-and-usecallback
+ "react-hooks/exhaustive-deps": "off",
+ // Disable temporarily as we have some `any` in the codebase and we need to got case by case
+ // and see if they can be fixed.
+ "@typescript-eslint/no-explicit-any": "off",
+ // Allow unused vars that start with underscore (convention for intentionally unused)
+ "@typescript-eslint/no-unused-vars": [
+ "error",
+ {
+ "argsIgnorePattern": "^_",
+ "varsIgnorePattern": "^_",
+ "caughtErrorsIgnorePattern": "^_"
+ }
+ ]
+ }
}
diff --git a/autogpt_platform/frontend/.prettierignore b/autogpt_platform/frontend/.prettierignore
index 2f038d1278..9951e9905d 100644
--- a/autogpt_platform/frontend/.prettierignore
+++ b/autogpt_platform/frontend/.prettierignore
@@ -1,5 +1,6 @@
node_modules
pnpm-lock.yaml
.next
+.auth
build
public
diff --git a/autogpt_platform/frontend/.storybook/main.ts b/autogpt_platform/frontend/.storybook/main.ts
index fce703bc98..41553c196d 100644
--- a/autogpt_platform/frontend/.storybook/main.ts
+++ b/autogpt_platform/frontend/.storybook/main.ts
@@ -1,13 +1,16 @@
import type { StorybookConfig } from "@storybook/nextjs";
const config: StorybookConfig = {
- stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
+ stories: [
+ "../src/components/overview.stories.@(js|jsx|mjs|ts|tsx)",
+ "../src/components/tokens/**/*.stories.@(js|jsx|mjs|ts|tsx)",
+ "../src/components/atoms/**/*.stories.@(js|jsx|mjs|ts|tsx)",
+ "../src/components/agptui/**/*.stories.@(js|jsx|mjs|ts|tsx)",
+ ],
addons: [
"@storybook/addon-a11y",
"@storybook/addon-onboarding",
"@storybook/addon-links",
- "@storybook/addon-essentials",
- "@storybook/addon-interactions",
"@storybook/addon-docs",
],
features: {
diff --git a/autogpt_platform/frontend/.storybook/manager.ts b/autogpt_platform/frontend/.storybook/manager.ts
index 20734b9f3e..7c7021cb9f 100644
--- a/autogpt_platform/frontend/.storybook/manager.ts
+++ b/autogpt_platform/frontend/.storybook/manager.ts
@@ -1,4 +1,4 @@
-import { addons } from "@storybook/manager-api";
+import { addons } from "storybook/manager-api";
import { theme } from "./theme";
diff --git a/autogpt_platform/frontend/.storybook/preview.tsx b/autogpt_platform/frontend/.storybook/preview.tsx
index a515bbfef9..d8c67a0a3f 100644
--- a/autogpt_platform/frontend/.storybook/preview.tsx
+++ b/autogpt_platform/frontend/.storybook/preview.tsx
@@ -1,17 +1,16 @@
-import React from "react";
-import type { Preview } from "@storybook/react";
-import { initialize, mswLoader } from "msw-storybook-addon";
-import "../src/app/globals.css";
-import "../src/components/styles/fonts.css";
import {
Controls,
- Description,
Primary,
Source,
Stories,
Subtitle,
Title,
-} from "@storybook/blocks";
+} from "@storybook/addon-docs/blocks";
+import { Preview } from "@storybook/nextjs";
+import { initialize, mswLoader } from "msw-storybook-addon";
+import React from "react";
+import "../src/app/globals.css";
+import "../src/components/styles/fonts.css";
import { theme } from "./theme";
// Initialize MSW
@@ -28,7 +27,7 @@ const preview: Preview = {
<>
-
+
diff --git a/autogpt_platform/frontend/.storybook/test-runner.ts b/autogpt_platform/frontend/.storybook/test-runner.ts
deleted file mode 100644
index fc12dcc48d..0000000000
--- a/autogpt_platform/frontend/.storybook/test-runner.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import type { TestRunnerConfig } from "@storybook/test-runner";
-import { injectAxe, checkA11y } from "axe-playwright";
-
-/*
- * See https://storybook.js.org/docs/writing-tests/test-runner#test-hook-api
- * to learn more about the test-runner hooks API.
- */
-const config: TestRunnerConfig = {
- async preVisit(page) {
- await injectAxe(page);
- },
- async postVisit(page) {
- await checkA11y(page, "#storybook-root", {
- detailedReport: true,
- detailedReportOptions: {
- html: true,
- },
- });
- },
-};
-
-export default config;
diff --git a/autogpt_platform/frontend/.storybook/theme.ts b/autogpt_platform/frontend/.storybook/theme.ts
index 0a7693ddcd..bebc5b939d 100644
--- a/autogpt_platform/frontend/.storybook/theme.ts
+++ b/autogpt_platform/frontend/.storybook/theme.ts
@@ -1,4 +1,4 @@
-import { create } from "@storybook/theming/create";
+import { create } from "storybook/theming/create";
export const theme = create({
base: "light",
diff --git a/autogpt_platform/frontend/README.md b/autogpt_platform/frontend/README.md
index ee9dc60df8..18fda747d4 100644
--- a/autogpt_platform/frontend/README.md
+++ b/autogpt_platform/frontend/README.md
@@ -156,3 +156,9 @@ By integrating Storybook into our development workflow, we can streamline UI dev
- [**Zod**](https://zod.dev/) - TypeScript-first schema validation
- [**React Table**](https://tanstack.com/table) - Headless table library
- [**React Flow**](https://reactflow.dev/) - Interactive node-based diagrams
+- [**React Query**](https://tanstack.com/query/latest/docs/framework/react/overview) - Data fetching and caching
+- [**React Query DevTools**](https://tanstack.com/query/latest/docs/framework/react/devtools) - Debugging tool for React Query
+
+### Development Tools
+
+- `NEXT_PUBLIC_REACT_QUERY_DEVTOOL` - Enable React Query DevTools. Set to `true` to enable.
diff --git a/autogpt_platform/frontend/orval.config.ts b/autogpt_platform/frontend/orval.config.ts
new file mode 100644
index 0000000000..afce23a441
--- /dev/null
+++ b/autogpt_platform/frontend/orval.config.ts
@@ -0,0 +1,59 @@
+import { defineConfig } from "orval";
+
+export default defineConfig({
+ autogpt_api_client: {
+ input: {
+ target: `./src/api/openapi.json`,
+ override: {
+ transformer: "./src/api/transformers/fix-tags.mjs",
+ },
+ },
+ output: {
+ workspace: "./src/api",
+ target: `./__generated__/endpoints`,
+ schemas: "./__generated__/models",
+ mode: "tags-split",
+ client: "react-query",
+ httpClient: "fetch",
+ indexFiles: false,
+ mock: {
+ type: "msw",
+ delay: 1000, // artifical latency
+ generateEachHttpStatus: true, // helps us test error-handling scenarios and generate mocks for all HTTP statuses
+ },
+ override: {
+ mutator: {
+ path: "./mutators/custom-mutator.ts",
+ name: "customMutator",
+ },
+ query: {
+ useQuery: true,
+ useMutation: true,
+ // Will add more as their use cases arise
+ },
+ },
+ },
+ hooks: {
+ afterAllFilesWrite: "prettier --write",
+ },
+ },
+ autogpt_zod_schema: {
+ input: {
+ target: `./src/api/openapi.json`,
+ override: {
+ transformer: "./src/api/transformers/fix-tags.mjs",
+ },
+ },
+ output: {
+ workspace: "./src/api",
+ target: `./__generated__/zod-schema`,
+ schemas: "./__generated__/models",
+ mode: "tags-split",
+ client: "zod",
+ indexFiles: false,
+ },
+ hooks: {
+ afterAllFilesWrite: "prettier --write",
+ },
+ },
+});
diff --git a/autogpt_platform/frontend/package.json b/autogpt_platform/frontend/package.json
index ff174e390c..39edca7d05 100644
--- a/autogpt_platform/frontend/package.json
+++ b/autogpt_platform/frontend/package.json
@@ -5,7 +5,7 @@
"scripts": {
"dev": "next dev --turbo",
"dev:test": "NODE_ENV=test && next dev --turbo",
- "build": "SKIP_STORYBOOK_TESTS=true next build",
+ "build": "pnpm run generate:api-client && SKIP_STORYBOOK_TESTS=true next build",
"start": "next start",
"start:standalone": "cd .next/standalone && node server.js",
"lint": "next lint && prettier --check .",
@@ -18,7 +18,10 @@
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"test-storybook": "test-storybook",
- "test-storybook:ci": "concurrently -k -s first -n \"SB,TEST\" -c \"magenta,blue\" \"pnpm run build-storybook -- --quiet && npx http-server storybook-static --port 6006 --silent\" \"wait-on tcp:6006 && pnpm run test-storybook\""
+ "test-storybook:ci": "concurrently -k -s first -n \"SB,TEST\" -c \"magenta,blue\" \"pnpm run build-storybook -- --quiet && npx http-server storybook-static --port 6006 --silent\" \"wait-on tcp:6006 && pnpm run test-storybook\"",
+ "fetch:openapi": "curl http://localhost:8006/openapi.json > ./src/api/openapi.json && prettier --write ./src/api/openapi.json",
+ "generate:api-client": "orval --config ./orval.config.ts",
+ "generate:api-all": "pnpm run fetch:openapi && pnpm run generate:api-client"
},
"browserslist": [
"defaults"
@@ -27,6 +30,7 @@
"@faker-js/faker": "9.8.0",
"@hookform/resolvers": "5.1.1",
"@next/third-parties": "15.3.3",
+ "@phosphor-icons/react": "2.1.10",
"@radix-ui/react-alert-dialog": "1.1.14",
"@radix-ui/react-avatar": "1.1.10",
"@radix-ui/react-checkbox": "1.3.2",
@@ -49,6 +53,7 @@
"@sentry/nextjs": "9.27.0",
"@supabase/ssr": "0.6.1",
"@supabase/supabase-js": "2.50.0",
+ "@tanstack/react-query": "5.80.7",
"@tanstack/react-table": "8.21.3",
"@types/jaro-winkler": "0.2.4",
"@xyflow/react": "12.6.4",
@@ -89,23 +94,17 @@
"zod": "3.25.56"
},
"devDependencies": {
- "@chromatic-com/storybook": "3.2.6",
- "@playwright/test": "1.52.0",
- "@storybook/addon-a11y": "8.6.14",
- "@storybook/addon-docs": "8.6.14",
- "@storybook/addon-essentials": "8.6.14",
- "@storybook/addon-interactions": "8.6.14",
- "@storybook/addon-links": "8.6.14",
- "@storybook/addon-onboarding": "8.6.14",
- "@storybook/blocks": "8.6.14",
- "@storybook/manager-api": "8.6.14",
- "@storybook/nextjs": "8.6.14",
- "@storybook/react": "8.6.14",
- "@storybook/test": "8.6.14",
- "@storybook/test-runner": "0.22.1",
- "@storybook/theming": "8.6.14",
+ "@chromatic-com/storybook": "4.0.0",
+ "@playwright/test": "1.53.1",
+ "@storybook/addon-a11y": "9.0.12",
+ "@storybook/addon-docs": "9.0.12",
+ "@storybook/addon-links": "9.0.12",
+ "@storybook/addon-onboarding": "9.0.12",
+ "@storybook/nextjs": "9.0.12",
+ "@tanstack/eslint-plugin-query": "5.78.0",
+ "@tanstack/react-query-devtools": "5.80.10",
"@types/canvas-confetti": "1.9.0",
- "@types/lodash": "4.17.17",
+ "@types/lodash": "4.17.18",
"@types/negotiator": "0.6.4",
"@types/node": "22.15.30",
"@types/react": "18.3.17",
@@ -115,16 +114,17 @@
"chromatic": "11.25.2",
"concurrently": "9.1.2",
"eslint": "8.57.1",
- "eslint-config-next": "15.3.3",
- "eslint-plugin-storybook": "0.12.0",
- "import-in-the-middle": "1.14.0",
+ "eslint-config-next": "15.3.4",
+ "eslint-plugin-storybook": "9.0.12",
+ "import-in-the-middle": "1.14.2",
"msw": "2.10.2",
"msw-storybook-addon": "2.0.5",
- "postcss": "8.5.4",
+ "orval": "7.10.0",
+ "postcss": "8.5.6",
"prettier": "3.5.3",
"prettier-plugin-tailwindcss": "0.6.12",
"require-in-the-middle": "7.5.2",
- "storybook": "8.6.14",
+ "storybook": "9.0.12",
"tailwindcss": "3.4.17",
"typescript": "5.8.3"
},
diff --git a/autogpt_platform/frontend/pnpm-lock.yaml b/autogpt_platform/frontend/pnpm-lock.yaml
index a258b772eb..b3d1e7975d 100644
--- a/autogpt_platform/frontend/pnpm-lock.yaml
+++ b/autogpt_platform/frontend/pnpm-lock.yaml
@@ -16,7 +16,10 @@ importers:
version: 5.1.1(react-hook-form@7.57.0(react@18.3.1))
'@next/third-parties':
specifier: 15.3.3
- version: 15.3.3(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
+ version: 15.3.3(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.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)
'@radix-ui/react-alert-dialog':
specifier: 1.1.14
version: 1.1.14(@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)
@@ -76,13 +79,16 @@ importers:
version: 1.2.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)
'@sentry/nextjs':
specifier: 9.27.0
- version: 9.27.0(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2))
+ version: 9.27.0(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.99.9(esbuild@0.25.5))
'@supabase/ssr':
specifier: 0.6.1
version: 0.6.1(@supabase/supabase-js@2.50.0)
'@supabase/supabase-js':
specifier: 2.50.0
version: 2.50.0
+ '@tanstack/react-query':
+ specifier: 5.80.7
+ version: 5.80.7(react@18.3.1)
'@tanstack/react-table':
specifier: 8.21.3
version: 8.21.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -91,7 +97,7 @@ importers:
version: 0.2.4
'@xyflow/react':
specifier: 12.6.4
- version: 12.6.4(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ version: 12.6.4(@types/react@18.3.17)(immer@9.0.21)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
ajv:
specifier: 8.17.1
version: 8.17.1
@@ -127,7 +133,7 @@ importers:
version: 12.16.0(@emotion/is-prop-valid@1.2.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
geist:
specifier: 1.4.2
- version: 1.4.2(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
+ version: 1.4.2(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
jaro-winkler:
specifier: 0.2.8
version: 0.2.8
@@ -145,7 +151,7 @@ importers:
version: 2.30.1
next:
specifier: 15.3.3
- version: 15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ version: 15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.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)
@@ -199,56 +205,38 @@ importers:
version: 3.25.56
devDependencies:
'@chromatic-com/storybook':
- specifier: 3.2.6
- version: 3.2.6(react@18.3.1)(storybook@8.6.14(prettier@3.5.3))
+ specifier: 4.0.0
+ version: 4.0.0(storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))
'@playwright/test':
- specifier: 1.52.0
- version: 1.52.0
+ specifier: 1.53.1
+ version: 1.53.1
'@storybook/addon-a11y':
- specifier: 8.6.14
- version: 8.6.14(storybook@8.6.14(prettier@3.5.3))
+ specifier: 9.0.12
+ version: 9.0.12(storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))
'@storybook/addon-docs':
- specifier: 8.6.14
- version: 8.6.14(@types/react@18.3.17)(storybook@8.6.14(prettier@3.5.3))
- '@storybook/addon-essentials':
- specifier: 8.6.14
- version: 8.6.14(@types/react@18.3.17)(storybook@8.6.14(prettier@3.5.3))
- '@storybook/addon-interactions':
- specifier: 8.6.14
- version: 8.6.14(storybook@8.6.14(prettier@3.5.3))
+ specifier: 9.0.12
+ version: 9.0.12(@types/react@18.3.17)(storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))
'@storybook/addon-links':
- specifier: 8.6.14
- version: 8.6.14(react@18.3.1)(storybook@8.6.14(prettier@3.5.3))
+ specifier: 9.0.12
+ version: 9.0.12(react@18.3.1)(storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))
'@storybook/addon-onboarding':
- specifier: 8.6.14
- version: 8.6.14(storybook@8.6.14(prettier@3.5.3))
- '@storybook/blocks':
- specifier: 8.6.14
- version: 8.6.14(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.5.3))
- '@storybook/manager-api':
- specifier: 8.6.14
- version: 8.6.14(storybook@8.6.14(prettier@3.5.3))
+ specifier: 9.0.12
+ version: 9.0.12(storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))
'@storybook/nextjs':
- specifier: 8.6.14
- version: 8.6.14(@swc/core@1.11.31)(esbuild@0.24.2)(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(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@8.6.14(prettier@3.5.3))(type-fest@4.41.0)(typescript@5.8.3)(webpack-hot-middleware@2.26.1)(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2))
- '@storybook/react':
- specifier: 8.6.14
- version: 8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.5.3)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.5.3))(typescript@5.8.3)
- '@storybook/test':
- specifier: 8.6.14
- version: 8.6.14(storybook@8.6.14(prettier@3.5.3))
- '@storybook/test-runner':
- specifier: 0.22.1
- version: 0.22.1(@types/node@22.15.30)(storybook@8.6.14(prettier@3.5.3))
- '@storybook/theming':
- specifier: 8.6.14
- version: 8.6.14(storybook@8.6.14(prettier@3.5.3))
+ specifier: 9.0.12
+ version: 9.0.12(esbuild@0.25.5)(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.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.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))(type-fest@4.41.0)(typescript@5.8.3)(webpack-hot-middleware@2.26.1)(webpack@5.99.9(esbuild@0.25.5))
+ '@tanstack/eslint-plugin-query':
+ specifier: 5.78.0
+ version: 5.78.0(eslint@8.57.1)(typescript@5.8.3)
+ '@tanstack/react-query-devtools':
+ specifier: 5.80.10
+ version: 5.80.10(@tanstack/react-query@5.80.7(react@18.3.1))(react@18.3.1)
'@types/canvas-confetti':
specifier: 1.9.0
version: 1.9.0
'@types/lodash':
- specifier: 4.17.17
- version: 4.17.17
+ specifier: 4.17.18
+ version: 4.17.18
'@types/negotiator':
specifier: 0.6.4
version: 0.6.4
@@ -266,7 +254,7 @@ importers:
version: 3.16.3
axe-playwright:
specifier: 2.1.0
- version: 2.1.0(playwright@1.52.0)
+ version: 2.1.0(playwright@1.53.1)
chromatic:
specifier: 11.25.2
version: 11.25.2
@@ -277,23 +265,26 @@ importers:
specifier: 8.57.1
version: 8.57.1
eslint-config-next:
- specifier: 15.3.3
- version: 15.3.3(eslint@8.57.1)(typescript@5.8.3)
+ specifier: 15.3.4
+ version: 15.3.4(eslint@8.57.1)(typescript@5.8.3)
eslint-plugin-storybook:
- specifier: 0.12.0
- version: 0.12.0(eslint@8.57.1)(typescript@5.8.3)
+ specifier: 9.0.12
+ version: 9.0.12(eslint@8.57.1)(storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))(typescript@5.8.3)
import-in-the-middle:
- specifier: 1.14.0
- version: 1.14.0
+ specifier: 1.14.2
+ version: 1.14.2
msw:
specifier: 2.10.2
version: 2.10.2(@types/node@22.15.30)(typescript@5.8.3)
msw-storybook-addon:
specifier: 2.0.5
version: 2.0.5(msw@2.10.2(@types/node@22.15.30)(typescript@5.8.3))
+ orval:
+ specifier: 7.10.0
+ version: 7.10.0(openapi-types@12.1.3)
postcss:
- specifier: 8.5.4
- version: 8.5.4
+ specifier: 8.5.6
+ version: 8.5.6
prettier:
specifier: 3.5.3
version: 3.5.3
@@ -304,8 +295,8 @@ importers:
specifier: 7.5.2
version: 7.5.2
storybook:
- specifier: 8.6.14
- version: 8.6.14(prettier@3.5.3)
+ specifier: 9.0.12
+ version: 9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3)
tailwindcss:
specifier: 3.4.17
version: 3.4.17
@@ -326,6 +317,25 @@ packages:
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
engines: {node: '>=6.0.0'}
+ '@apidevtools/json-schema-ref-parser@11.7.2':
+ resolution: {integrity: sha512-4gY54eEGEstClvEkGnwVkTkrx0sqwemEFG5OSRRn3tD91XH0+Q8XIkYIfo7IwEWPpJZwILb9GUXeShtplRc/eA==}
+ engines: {node: '>= 16'}
+
+ '@apidevtools/openapi-schemas@2.1.0':
+ resolution: {integrity: sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==}
+ engines: {node: '>=10'}
+
+ '@apidevtools/swagger-methods@3.0.2':
+ resolution: {integrity: sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==}
+
+ '@apidevtools/swagger-parser@10.1.1':
+ resolution: {integrity: sha512-u/kozRnsPO/x8QtKYJOqoGtC4kH6yg1lfYkB9Au0WhYB0FNLpyFusttQtvhlwjtG3rOwiRz4D8DnnXa8iEpIKA==}
+ peerDependencies:
+ openapi-types: '>=7'
+
+ '@asyncapi/specs@6.8.1':
+ resolution: {integrity: sha512-czHoAk3PeXTLR+X8IUaD+IpT+g+zUvkcgMDJVothBsan+oHN3jfcFcFUNdOPAAFoUCQN1hXF1dWuphWy05THlA==}
+
'@babel/code-frame@7.27.1':
resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
engines: {node: '>=6.9.0'}
@@ -466,27 +476,11 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-syntax-async-generators@7.8.4':
- resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
'@babel/plugin-syntax-bigint@7.8.3':
resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-syntax-class-properties@7.12.13':
- resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-class-static-block@7.14.5':
- resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
'@babel/plugin-syntax-dynamic-import@7.8.3':
resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==}
peerDependencies:
@@ -504,64 +498,12 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-syntax-import-meta@7.10.4':
- resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-json-strings@7.8.3':
- resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
'@babel/plugin-syntax-jsx@7.27.1':
resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-syntax-logical-assignment-operators@7.10.4':
- resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3':
- resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-numeric-separator@7.10.4':
- resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-object-rest-spread@7.8.3':
- resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-optional-catch-binding@7.8.3':
- resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-optional-chaining@7.8.3':
- resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-private-property-in-object@7.14.5':
- resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-top-level-await@7.14.5':
- resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
'@babel/plugin-syntax-typescript@7.27.1':
resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==}
engines: {node: '>=6.9.0'}
@@ -949,9 +891,6 @@ packages:
resolution: {integrity: sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==}
engines: {node: '>=6.9.0'}
- '@bcoe/v8-coverage@0.2.3':
- resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
-
'@bundled-es-modules/cookie@2.0.1':
resolution: {integrity: sha512-8o+5fRPLNbjbdGRRmJj3h6Hh1AQJf2dk3qQ/5ZFb+PXkRNiSoMGGUKlsgLfrxneb72axVJyIYji64E2+nNfYyw==}
@@ -961,11 +900,11 @@ packages:
'@bundled-es-modules/tough-cookie@0.1.6':
resolution: {integrity: sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==}
- '@chromatic-com/storybook@3.2.6':
- resolution: {integrity: sha512-FDmn5Ry2DzQdik+eq2sp/kJMMT36Ewe7ONXUXM2Izd97c7r6R/QyGli8eyh/F0iyqVvbLveNYFyF0dBOJNwLqw==}
- engines: {node: '>=16.0.0', yarn: '>=1.22.18'}
+ '@chromatic-com/storybook@4.0.0':
+ resolution: {integrity: sha512-FfyMHK/lz/dHezWxwNZv4ReFORWVvv+bJx71NT2BSfLhOKOaoZnKJOe4QLyGxWAB7ynnedrM9V9qea3FPFj+rQ==}
+ engines: {node: '>=20.0.0', yarn: '>=1.22.18'}
peerDependencies:
- storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0
+ storybook: ^0.0.0-0 || ^9.0.0 || ^9.1.0-0
'@date-fns/tz@1.2.0':
resolution: {integrity: sha512-LBrd7MiJZ9McsOgxqWX7AaxrDjcFVjWH/tIKJd7pnR7McaslGYOP1QmmiBXdJH/H/yLCT+rcQ7FaPBUxRGUtrg==}
@@ -988,152 +927,152 @@ packages:
'@emotion/unitless@0.8.1':
resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==}
- '@esbuild/aix-ppc64@0.24.2':
- resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==}
+ '@esbuild/aix-ppc64@0.25.5':
+ resolution: {integrity: sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [aix]
- '@esbuild/android-arm64@0.24.2':
- resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==}
+ '@esbuild/android-arm64@0.25.5':
+ resolution: {integrity: sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [android]
- '@esbuild/android-arm@0.24.2':
- resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==}
+ '@esbuild/android-arm@0.25.5':
+ resolution: {integrity: sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==}
engines: {node: '>=18'}
cpu: [arm]
os: [android]
- '@esbuild/android-x64@0.24.2':
- resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==}
+ '@esbuild/android-x64@0.25.5':
+ resolution: {integrity: sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==}
engines: {node: '>=18'}
cpu: [x64]
os: [android]
- '@esbuild/darwin-arm64@0.24.2':
- resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==}
+ '@esbuild/darwin-arm64@0.25.5':
+ resolution: {integrity: sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
- '@esbuild/darwin-x64@0.24.2':
- resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==}
+ '@esbuild/darwin-x64@0.25.5':
+ resolution: {integrity: sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
- '@esbuild/freebsd-arm64@0.24.2':
- resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==}
+ '@esbuild/freebsd-arm64@0.25.5':
+ resolution: {integrity: sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
- '@esbuild/freebsd-x64@0.24.2':
- resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==}
+ '@esbuild/freebsd-x64@0.25.5':
+ resolution: {integrity: sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==}
engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
- '@esbuild/linux-arm64@0.24.2':
- resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==}
+ '@esbuild/linux-arm64@0.25.5':
+ resolution: {integrity: sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
- '@esbuild/linux-arm@0.24.2':
- resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==}
+ '@esbuild/linux-arm@0.25.5':
+ resolution: {integrity: sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==}
engines: {node: '>=18'}
cpu: [arm]
os: [linux]
- '@esbuild/linux-ia32@0.24.2':
- resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==}
+ '@esbuild/linux-ia32@0.25.5':
+ resolution: {integrity: sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==}
engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
- '@esbuild/linux-loong64@0.24.2':
- resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==}
+ '@esbuild/linux-loong64@0.25.5':
+ resolution: {integrity: sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==}
engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
- '@esbuild/linux-mips64el@0.24.2':
- resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==}
+ '@esbuild/linux-mips64el@0.25.5':
+ resolution: {integrity: sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==}
engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
- '@esbuild/linux-ppc64@0.24.2':
- resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==}
+ '@esbuild/linux-ppc64@0.25.5':
+ resolution: {integrity: sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
- '@esbuild/linux-riscv64@0.24.2':
- resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==}
+ '@esbuild/linux-riscv64@0.25.5':
+ resolution: {integrity: sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==}
engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
- '@esbuild/linux-s390x@0.24.2':
- resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==}
+ '@esbuild/linux-s390x@0.25.5':
+ resolution: {integrity: sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==}
engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
- '@esbuild/linux-x64@0.24.2':
- resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==}
+ '@esbuild/linux-x64@0.25.5':
+ resolution: {integrity: sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
- '@esbuild/netbsd-arm64@0.24.2':
- resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==}
+ '@esbuild/netbsd-arm64@0.25.5':
+ resolution: {integrity: sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [netbsd]
- '@esbuild/netbsd-x64@0.24.2':
- resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==}
+ '@esbuild/netbsd-x64@0.25.5':
+ resolution: {integrity: sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
- '@esbuild/openbsd-arm64@0.24.2':
- resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==}
+ '@esbuild/openbsd-arm64@0.25.5':
+ resolution: {integrity: sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
- '@esbuild/openbsd-x64@0.24.2':
- resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==}
+ '@esbuild/openbsd-x64@0.25.5':
+ resolution: {integrity: sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==}
engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
- '@esbuild/sunos-x64@0.24.2':
- resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==}
+ '@esbuild/sunos-x64@0.25.5':
+ resolution: {integrity: sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==}
engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
- '@esbuild/win32-arm64@0.24.2':
- resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==}
+ '@esbuild/win32-arm64@0.25.5':
+ resolution: {integrity: sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
- '@esbuild/win32-ia32@0.24.2':
- resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==}
+ '@esbuild/win32-ia32@0.25.5':
+ resolution: {integrity: sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==}
engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
- '@esbuild/win32-x64@0.24.2':
- resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==}
+ '@esbuild/win32-x64@0.25.5':
+ resolution: {integrity: sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==}
engines: {node: '>=18'}
cpu: [x64]
os: [win32]
@@ -1156,6 +1095,9 @@ packages:
resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ '@exodus/schemasafe@1.3.0':
+ resolution: {integrity: sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==}
+
'@faker-js/faker@9.8.0':
resolution: {integrity: sha512-U9wpuSrJC93jZBxx/Qq2wPjCuYISBueyVUGK7qqdmj7r/nxaxwW8AQDCLeRO7wZnjj94sh3p246cAYjUKuqgfg==}
engines: {node: '>=18.0.0', npm: '>=9.0.0'}
@@ -1175,11 +1117,8 @@ packages:
'@floating-ui/utils@0.2.9':
resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==}
- '@hapi/hoek@9.3.0':
- resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==}
-
- '@hapi/topo@5.1.0':
- resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==}
+ '@gerrit0/mini-shiki@3.6.0':
+ resolution: {integrity: sha512-KaeJvPNofTEZR9EzVNp/GQzbQqkGfjiu6k3CXKvhVTX+8OoAKSX/k7qxLKOX3B0yh2XqVAc93rsOu48CGt2Qug==}
'@hookform/resolvers@5.1.1':
resolution: {integrity: sha512-J/NVING3LMAEvexJkyTLjruSm7aOFx7QX21pzkiJfMoNG0wl5aFEjLTl7ay7IQb9EWY6AkrBy7tHL2Alijpdcg==}
@@ -1199,11 +1138,13 @@ packages:
resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==}
deprecated: Use @eslint/object-schema instead
- '@img/sharp-darwin-arm64@0.33.5':
- resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [arm64]
- os: [darwin]
+ '@ibm-cloud/openapi-ruleset-utilities@1.9.0':
+ resolution: {integrity: sha512-AoFbSarOqFBYH+1TZ9Ahkm2IWYSi5v0pBk88fpV+5b3qGJukypX8PwvCWADjuyIccKg48/F73a6hTTkBzDQ2UA==}
+ engines: {node: '>=16.0.0'}
+
+ '@ibm-cloud/openapi-ruleset@1.31.1':
+ resolution: {integrity: sha512-3WK2FREmDA2aadCjD71PE7tx5evyvmhg80ts1kXp2IzXIA0ZJ7guGM66tj40kxaqwpMSGchwEnnfYswntav76g==}
+ engines: {node: '>=16.0.0'}
'@img/sharp-darwin-arm64@0.34.2':
resolution: {integrity: sha512-OfXHZPppddivUJnqyKoi5YVeHRkkNE2zUFT2gbpKxp/JZCFYEYubnMg+gOp6lWfasPrTS+KPosKqdI+ELYVDtg==}
@@ -1211,53 +1152,27 @@ packages:
cpu: [arm64]
os: [darwin]
- '@img/sharp-darwin-x64@0.33.5':
- resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [x64]
- os: [darwin]
-
'@img/sharp-darwin-x64@0.34.2':
resolution: {integrity: sha512-dYvWqmjU9VxqXmjEtjmvHnGqF8GrVjM2Epj9rJ6BUIXvk8slvNDJbhGFvIoXzkDhrJC2jUxNLz/GUjjvSzfw+g==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [darwin]
- '@img/sharp-libvips-darwin-arm64@1.0.4':
- resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==}
- cpu: [arm64]
- os: [darwin]
-
'@img/sharp-libvips-darwin-arm64@1.1.0':
resolution: {integrity: sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA==}
cpu: [arm64]
os: [darwin]
- '@img/sharp-libvips-darwin-x64@1.0.4':
- resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==}
- cpu: [x64]
- os: [darwin]
-
'@img/sharp-libvips-darwin-x64@1.1.0':
resolution: {integrity: sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ==}
cpu: [x64]
os: [darwin]
- '@img/sharp-libvips-linux-arm64@1.0.4':
- resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==}
- cpu: [arm64]
- os: [linux]
-
'@img/sharp-libvips-linux-arm64@1.1.0':
resolution: {integrity: sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==}
cpu: [arm64]
os: [linux]
- '@img/sharp-libvips-linux-arm@1.0.5':
- resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==}
- cpu: [arm]
- os: [linux]
-
'@img/sharp-libvips-linux-arm@1.1.0':
resolution: {integrity: sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==}
cpu: [arm]
@@ -1268,123 +1183,62 @@ packages:
cpu: [ppc64]
os: [linux]
- '@img/sharp-libvips-linux-s390x@1.0.4':
- resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==}
- cpu: [s390x]
- os: [linux]
-
'@img/sharp-libvips-linux-s390x@1.1.0':
resolution: {integrity: sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==}
cpu: [s390x]
os: [linux]
- '@img/sharp-libvips-linux-x64@1.0.4':
- resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==}
- cpu: [x64]
- os: [linux]
-
'@img/sharp-libvips-linux-x64@1.1.0':
resolution: {integrity: sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==}
cpu: [x64]
os: [linux]
- '@img/sharp-libvips-linuxmusl-arm64@1.0.4':
- resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==}
- cpu: [arm64]
- os: [linux]
-
'@img/sharp-libvips-linuxmusl-arm64@1.1.0':
resolution: {integrity: sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==}
cpu: [arm64]
os: [linux]
- '@img/sharp-libvips-linuxmusl-x64@1.0.4':
- resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==}
- cpu: [x64]
- os: [linux]
-
'@img/sharp-libvips-linuxmusl-x64@1.1.0':
resolution: {integrity: sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==}
cpu: [x64]
os: [linux]
- '@img/sharp-linux-arm64@0.33.5':
- resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [arm64]
- os: [linux]
-
'@img/sharp-linux-arm64@0.34.2':
resolution: {integrity: sha512-D8n8wgWmPDakc83LORcfJepdOSN6MvWNzzz2ux0MnIbOqdieRZwVYY32zxVx+IFUT8er5KPcyU3XXsn+GzG/0Q==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [linux]
- '@img/sharp-linux-arm@0.33.5':
- resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [arm]
- os: [linux]
-
'@img/sharp-linux-arm@0.34.2':
resolution: {integrity: sha512-0DZzkvuEOqQUP9mo2kjjKNok5AmnOr1jB2XYjkaoNRwpAYMDzRmAqUIa1nRi58S2WswqSfPOWLNOr0FDT3H5RQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm]
os: [linux]
- '@img/sharp-linux-s390x@0.33.5':
- resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [s390x]
- os: [linux]
-
'@img/sharp-linux-s390x@0.34.2':
resolution: {integrity: sha512-EGZ1xwhBI7dNISwxjChqBGELCWMGDvmxZXKjQRuqMrakhO8QoMgqCrdjnAqJq/CScxfRn+Bb7suXBElKQpPDiw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [s390x]
os: [linux]
- '@img/sharp-linux-x64@0.33.5':
- resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [x64]
- os: [linux]
-
'@img/sharp-linux-x64@0.34.2':
resolution: {integrity: sha512-sD7J+h5nFLMMmOXYH4DD9UtSNBD05tWSSdWAcEyzqW8Cn5UxXvsHAxmxSesYUsTOBmUnjtxghKDl15EvfqLFbQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [linux]
- '@img/sharp-linuxmusl-arm64@0.33.5':
- resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [arm64]
- os: [linux]
-
'@img/sharp-linuxmusl-arm64@0.34.2':
resolution: {integrity: sha512-NEE2vQ6wcxYav1/A22OOxoSOGiKnNmDzCYFOZ949xFmrWZOVII1Bp3NqVVpvj+3UeHMFyN5eP/V5hzViQ5CZNA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [linux]
- '@img/sharp-linuxmusl-x64@0.33.5':
- resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [x64]
- os: [linux]
-
'@img/sharp-linuxmusl-x64@0.34.2':
resolution: {integrity: sha512-DOYMrDm5E6/8bm/yQLCWyuDJwUnlevR8xtF8bs+gjZ7cyUNYXiSf/E8Kp0Ss5xasIaXSHzb888V1BE4i1hFhAA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [linux]
- '@img/sharp-wasm32@0.33.5':
- resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [wasm32]
-
'@img/sharp-wasm32@0.34.2':
resolution: {integrity: sha512-/VI4mdlJ9zkaq53MbIG6rZY+QRN3MLbR6usYlgITEzi4Rpx5S6LFKsycOQjkOGmqTNmkIdLjEvooFKwww6OpdQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
@@ -1396,24 +1250,12 @@ packages:
cpu: [arm64]
os: [win32]
- '@img/sharp-win32-ia32@0.33.5':
- resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [ia32]
- os: [win32]
-
'@img/sharp-win32-ia32@0.34.2':
resolution: {integrity: sha512-QLjGGvAbj0X/FXl8n1WbtQ6iVBpWU7JO94u/P2M4a8CFYsvQi4GW2mRy/JqkRx0qpBzaOdKJKw8uc930EX2AHw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [ia32]
os: [win32]
- '@img/sharp-win32-x64@0.33.5':
- resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [x64]
- os: [win32]
-
'@img/sharp-win32-x64@0.34.2':
resolution: {integrity: sha512-aUdT6zEYtDKCaxkofmmJDJYGCf0+pJg3eU9/oBuqvEeoB9dKI6ZLc/1iLJCTuJQDO4ptntAlkUmHgGjyuobZbw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
@@ -1455,84 +1297,6 @@ packages:
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
- '@istanbuljs/load-nyc-config@1.1.0':
- resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==}
- engines: {node: '>=8'}
-
- '@istanbuljs/schema@0.1.3':
- resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
- engines: {node: '>=8'}
-
- '@jest/console@29.7.0':
- resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/core@29.7.0':
- resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- peerDependencies:
- node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
- peerDependenciesMeta:
- node-notifier:
- optional: true
-
- '@jest/create-cache-key-function@29.7.0':
- resolution: {integrity: sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/environment@29.7.0':
- resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/expect-utils@29.7.0':
- resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/expect@29.7.0':
- resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/fake-timers@29.7.0':
- resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/globals@29.7.0':
- resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/reporters@29.7.0':
- resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- peerDependencies:
- node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
- peerDependenciesMeta:
- node-notifier:
- optional: true
-
- '@jest/schemas@29.6.3':
- resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/source-map@29.6.3':
- resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/test-result@29.7.0':
- resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/test-sequencer@29.7.0':
- resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/transform@29.7.0':
- resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/types@29.6.3':
- resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
'@jridgewell/gen-mapping@0.3.8':
resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==}
engines: {node: '>=6.0.0'}
@@ -1554,6 +1318,27 @@ packages:
'@jridgewell/trace-mapping@0.3.25':
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
+ '@jsdevtools/ono@7.1.3':
+ resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==}
+
+ '@jsep-plugin/assignment@1.3.0':
+ resolution: {integrity: sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==}
+ engines: {node: '>= 10.16.0'}
+ peerDependencies:
+ jsep: ^0.4.0||^1.0.0
+
+ '@jsep-plugin/regex@1.0.4':
+ resolution: {integrity: sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==}
+ engines: {node: '>= 10.16.0'}
+ peerDependencies:
+ jsep: ^0.4.0||^1.0.0
+
+ '@jsep-plugin/ternary@1.1.4':
+ resolution: {integrity: sha512-ck5wiqIbqdMX6WRQztBL7ASDty9YLgJ3sSAK5ZpBzXeySvFGCzIvM6UiAI4hTZ22fEcYQVV/zhUbNscggW+Ukg==}
+ engines: {node: '>= 10.16.0'}
+ peerDependencies:
+ jsep: ^0.4.0||^1.0.0
+
'@mdx-js/react@3.1.0':
resolution: {integrity: sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ==}
peerDependencies:
@@ -1564,14 +1349,17 @@ packages:
resolution: {integrity: sha512-RuzCup9Ct91Y7V79xwCb146RaBRHZ7NBbrIUySumd1rpKqHL5OonaqrGIbug5hNwP/fRyxFMA6ISgw4FTtYFYg==}
engines: {node: '>=18'}
- '@napi-rs/wasm-runtime@0.2.10':
- resolution: {integrity: sha512-bCsCyeZEwVErsGmyPNSzwfwFn4OdxBj0mmv6hOFucB/k81Ojdu68RbZdxYsRQUPc9l6SU5F/cG+bXgWs3oUgsQ==}
+ '@napi-rs/wasm-runtime@0.2.11':
+ resolution: {integrity: sha512-9DPkXtvHydrcOsopiYpUgPHpmj0HWZKMUnL2dZqpvC42lsratuBG06V5ipyno0fUek5VlFsNQ+AcFATSrJXgMA==}
+
+ '@neoconfetti/react@1.0.0':
+ resolution: {integrity: sha512-klcSooChXXOzIm+SE5IISIAn3bYzYfPjbX7D7HoqZL84oAfgREeSg5vSIaSFH+DaGzzvImTyWe1OyrJ67vik4A==}
'@next/env@15.3.3':
resolution: {integrity: sha512-OdiMrzCl2Xi0VTjiQQUK0Xh7bJHnOuET2s+3V+Y40WJBAXrJeGA3f+I8MZJ/YQ3mVGi5XGR1L66oFlgqXhQ4Vw==}
- '@next/eslint-plugin-next@15.3.3':
- resolution: {integrity: sha512-VKZJEiEdpKkfBmcokGjHu0vGDG+8CehGs90tBEy/IDoDDKGngeyIStt2MmE5FYNyU9BhgR7tybNWTAJY/30u+Q==}
+ '@next/eslint-plugin-next@15.3.4':
+ resolution: {integrity: sha512-lBxYdj7TI8phbJcLSAqDt57nIcobEign5NYIKCiy0hXQhrUbTqLqOaSDi568U6vFg4hJfBdZYsG4iP/uKhCqgg==}
'@next/swc-darwin-arm64@15.3.3':
resolution: {integrity: sha512-WRJERLuH+O3oYB4yZNVahSVFmtxRNjNF1I1c34tYMoJb0Pve+7/RaLAJJizyYiFhjYNGHRAE1Ri2Fd23zgDqhg==}
@@ -1840,12 +1628,49 @@ packages:
peerDependencies:
'@opentelemetry/api': ^1.1.0
+ '@orval/angular@7.10.0':
+ resolution: {integrity: sha512-M89GKo/PibxYXvOKp9+i6BLxhEW8YsO+evwuV2kMbDGNS3RiYDwzmMBcA9SVL7m8CumeZoxNEAXsupzq96ZAXA==}
+
+ '@orval/axios@7.10.0':
+ resolution: {integrity: sha512-AB6BjEwyguIcH8olzOTFPvwUP8z63yP4Jfl3T2UoeFchK04KqWqxbUoxmDG9xVQ79uMs/uOrb0X+GFwdZ56gAg==}
+
+ '@orval/core@7.10.0':
+ resolution: {integrity: sha512-Lm7HY4Kwzehe+2HNfi+Ov/IZ+m3nj3NskVGvOyJDAqaaHB7G/xydSCtgELG32ur4G+M/XmwChAjoP4TCNVh0VA==}
+
+ '@orval/fetch@7.10.0':
+ resolution: {integrity: sha512-bWcXPmARcXhXRveBtUnkfPlkUcLEzfGaflAdqN4CtScS48LgNrXXtuyt2BV2wvEXAavCWIhnRyQvz2foTU4U8Q==}
+
+ '@orval/hono@7.10.0':
+ resolution: {integrity: sha512-bOxTdZxx2BpGQf7fFuCeeUe//ZYDWc6Yz9WOhj3HrnsD06xTRKFWVBi/QZ29QcAPxqwunu/VWwbqoiHHuuX3bA==}
+
+ '@orval/mcp@7.10.0':
+ resolution: {integrity: sha512-ztLXGOSxK7jFwPKAeYPR85BjKRh3KTClKEnM2MFmo2FHHojn72DPXRPCmy0Wbw5Ee+JOxK2kIpyx+HZi9XVxiA==}
+
+ '@orval/mock@7.10.0':
+ resolution: {integrity: sha512-vkEWCaKEyMfWGJF5MtxVzl+blwc9vYzwdYxMoSdjA5yS2dNBrdNlt1aLtb4+aoI1jgBgpCg/OB7VtWaL5QYidA==}
+
+ '@orval/query@7.10.0':
+ resolution: {integrity: sha512-DBVg8RyKWSQKhr5Zfvxx5XICUdDUkG4MJKSd4BQCrRjUWgN6vwGunMEKyfnjpS5mFUSCkwWD/I3rTkjW6aysJA==}
+
+ '@orval/swr@7.10.0':
+ resolution: {integrity: sha512-ZdApomZQhJ5ZogjJgBK+haeCOP9gUaMaGKGjTVJr86jJaygDcKn54Ok1quiDUCbX42Eye+cgmQJeKeZvqnPohA==}
+
+ '@orval/zod@7.10.0':
+ resolution: {integrity: sha512-AB/508IBMlVDBcGvlq+ASz7DvqU3nhoDnIeBCyjwNfQwhYzREU0qqiFBnH0XAW70c6SCMf9/bIcYbw8GAx/zxA==}
+
+ '@phosphor-icons/react@2.1.10':
+ resolution: {integrity: sha512-vt8Tvq8GLjheAZZYa+YG/pW7HDbov8El/MANW8pOAz4eGxrwhnbfrQZq0Cp4q8zBEu8NIhHdnr+r8thnfRSNYA==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ react: '>= 16.8'
+ react-dom: '>= 16.8'
+
'@pkgjs/parseargs@0.11.0':
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
- '@playwright/test@1.52.0':
- resolution: {integrity: sha512-uh6W7sb55hl7D6vsAeA+V2p5JnlAqzhqFyF0VcJkKZXkgnFcVG9PziERRHQfPLfNGx1C292a4JqbWzhR8L4R1g==}
+ '@playwright/test@1.53.1':
+ resolution: {integrity: sha512-Z4c23LHV0muZ8hfv4jw6HngPJkbbtZxTkxPNIg7cJcTc9C28N/p2q7g3JZS2SiKBBHJ3uM1dgDye66bB7LEk5w==}
engines: {node: '>=18'}
hasBin: true
@@ -2630,147 +2455,139 @@ packages:
peerDependencies:
webpack: '>=4.40.0'
- '@sideway/address@4.1.5':
- resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==}
+ '@shikijs/engine-oniguruma@3.6.0':
+ resolution: {integrity: sha512-nmOhIZ9yT3Grd+2plmW/d8+vZ2pcQmo/UnVwXMUXAKTXdi+LK0S08Ancrz5tQQPkxvjBalpMW2aKvwXfelauvA==}
- '@sideway/formula@3.0.1':
- resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==}
+ '@shikijs/langs@3.6.0':
+ resolution: {integrity: sha512-IdZkQJaLBu1LCYCwkr30hNuSDfllOT8RWYVZK1tD2J03DkiagYKRxj/pDSl8Didml3xxuyzUjgtioInwEQM/TA==}
- '@sideway/pinpoint@2.0.0':
- resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==}
+ '@shikijs/themes@3.6.0':
+ resolution: {integrity: sha512-Fq2j4nWr1DF4drvmhqKq8x5vVQ27VncF8XZMBuHuQMZvUSS3NBgpqfwz/FoGe36+W6PvniZ1yDlg2d4kmYDU6w==}
- '@sinclair/typebox@0.27.8':
- resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
+ '@shikijs/types@3.6.0':
+ resolution: {integrity: sha512-cLWFiToxYu0aAzJqhXTQsFiJRTFDAGl93IrMSBNaGSzs7ixkLfdG6pH11HipuWFGW5vyx4X47W8HDQ7eSrmBUg==}
- '@sinonjs/commons@3.0.1':
- resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==}
-
- '@sinonjs/fake-timers@10.3.0':
- resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==}
+ '@shikijs/vscode-textmate@10.0.2':
+ resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==}
'@standard-schema/utils@0.3.0':
resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==}
- '@storybook/addon-a11y@8.6.14':
- resolution: {integrity: sha512-fozv6enO9IgpWq2U8qqS8MZ21Nt+MVHiRQe3CjnCpBOejTyo/ATm690PeYYRVHVG6M/15TVePb0h3ngKQbrrzQ==}
+ '@stoplight/better-ajv-errors@1.0.3':
+ resolution: {integrity: sha512-0p9uXkuB22qGdNfy3VeEhxkU5uwvp/KrBTAbrLBURv6ilxIVwanKwjMc41lQfIVgPGcOkmLbTolfFrSsueu7zA==}
+ engines: {node: ^12.20 || >= 14.13}
peerDependencies:
- storybook: ^8.6.14
+ ajv: '>=8'
- '@storybook/addon-actions@8.6.14':
- resolution: {integrity: sha512-mDQxylxGGCQSK7tJPkD144J8jWh9IU9ziJMHfB84PKpI/V5ZgqMDnpr2bssTrUaGDqU5e1/z8KcRF+Melhs9pQ==}
+ '@stoplight/json-ref-readers@1.2.2':
+ resolution: {integrity: sha512-nty0tHUq2f1IKuFYsLM4CXLZGHdMn+X/IwEUIpeSOXt0QjMUbL0Em57iJUDzz+2MkWG83smIigNZ3fauGjqgdQ==}
+ engines: {node: '>=8.3.0'}
+
+ '@stoplight/json-ref-resolver@3.1.6':
+ resolution: {integrity: sha512-YNcWv3R3n3U6iQYBsFOiWSuRGE5su1tJSiX6pAPRVk7dP0L7lqCteXGzuVRQ0gMZqUl8v1P0+fAKxF6PLo9B5A==}
+ engines: {node: '>=8.3.0'}
+
+ '@stoplight/json@3.21.7':
+ resolution: {integrity: sha512-xcJXgKFqv/uCEgtGlPxy3tPA+4I+ZI4vAuMJ885+ThkTHFVkC+0Fm58lA9NlsyjnkpxFh4YiQWpH+KefHdbA0A==}
+ engines: {node: '>=8.3.0'}
+
+ '@stoplight/ordered-object-literal@1.0.5':
+ resolution: {integrity: sha512-COTiuCU5bgMUtbIFBuyyh2/yVVzlr5Om0v5utQDgBCuQUOPgU1DwoffkTfg4UBQOvByi5foF4w4T+H9CoRe5wg==}
+ engines: {node: '>=8'}
+
+ '@stoplight/path@1.3.2':
+ resolution: {integrity: sha512-lyIc6JUlUA8Ve5ELywPC8I2Sdnh1zc1zmbYgVarhXIp9YeAB0ReeqmGEOWNtlHkbP2DAA1AL65Wfn2ncjK/jtQ==}
+ engines: {node: '>=8'}
+
+ '@stoplight/spectral-core@1.20.0':
+ resolution: {integrity: sha512-5hBP81nCC1zn1hJXL/uxPNRKNcB+/pEIHgCjPRpl/w/qy9yC9ver04tw1W0l/PMiv0UeB5dYgozXVQ4j5a6QQQ==}
+ engines: {node: ^16.20 || ^18.18 || >= 20.17}
+
+ '@stoplight/spectral-formats@1.8.2':
+ resolution: {integrity: sha512-c06HB+rOKfe7tuxg0IdKDEA5XnjL2vrn/m/OVIIxtINtBzphZrOgtRn7epQ5bQF5SWp84Ue7UJWaGgDwVngMFw==}
+ engines: {node: ^16.20 || ^18.18 || >= 20.17}
+
+ '@stoplight/spectral-functions@1.10.1':
+ resolution: {integrity: sha512-obu8ZfoHxELOapfGsCJixKZXZcffjg+lSoNuttpmUFuDzVLT3VmH8QkPXfOGOL5Pz80BR35ClNAToDkdnYIURg==}
+ engines: {node: ^16.20 || ^18.18 || >= 20.17}
+
+ '@stoplight/spectral-parsers@1.0.5':
+ resolution: {integrity: sha512-ANDTp2IHWGvsQDAY85/jQi9ZrF4mRrA5bciNHX+PUxPr4DwS6iv4h+FVWJMVwcEYdpyoIdyL+SRmHdJfQEPmwQ==}
+ engines: {node: ^16.20 || ^18.18 || >= 20.17}
+
+ '@stoplight/spectral-ref-resolver@1.0.5':
+ resolution: {integrity: sha512-gj3TieX5a9zMW29z3mBlAtDOCgN3GEc1VgZnCVlr5irmR4Qi5LuECuFItAq4pTn5Zu+sW5bqutsCH7D4PkpyAA==}
+ engines: {node: ^16.20 || ^18.18 || >= 20.17}
+
+ '@stoplight/spectral-rulesets@1.22.0':
+ resolution: {integrity: sha512-l2EY2jiKKLsvnPfGy+pXC0LeGsbJzcQP5G/AojHgf+cwN//VYxW1Wvv4WKFx/CLmLxc42mJYF2juwWofjWYNIQ==}
+ engines: {node: ^16.20 || ^18.18 || >= 20.17}
+
+ '@stoplight/spectral-runtime@1.1.4':
+ resolution: {integrity: sha512-YHbhX3dqW0do6DhiPSgSGQzr6yQLlWybhKwWx0cqxjMwxej3TqLv3BXMfIUYFKKUqIwH4Q2mV8rrMM8qD2N0rQ==}
+ engines: {node: ^16.20 || ^18.18 || >= 20.17}
+
+ '@stoplight/types@13.20.0':
+ resolution: {integrity: sha512-2FNTv05If7ib79VPDA/r9eUet76jewXFH2y2K5vuge6SXbRHtWBhcaRmu+6QpF4/WRNoJj5XYRSwLGXDxysBGA==}
+ engines: {node: ^12.20 || >=14.13}
+
+ '@stoplight/types@13.6.0':
+ resolution: {integrity: sha512-dzyuzvUjv3m1wmhPfq82lCVYGcXG0xUYgqnWfCq3PCVR4BKFhjdkHrnJ+jIDoMKvXb05AZP/ObQF6+NpDo29IQ==}
+ engines: {node: ^12.20 || >=14.13}
+
+ '@stoplight/types@14.1.1':
+ resolution: {integrity: sha512-/kjtr+0t0tjKr+heVfviO9FrU/uGLc+QNX3fHJc19xsCNYqU7lVhaXxDmEID9BZTjG+/r9pK9xP/xU02XGg65g==}
+ engines: {node: ^12.20 || >=14.13}
+
+ '@stoplight/yaml-ast-parser@0.0.50':
+ resolution: {integrity: sha512-Pb6M8TDO9DtSVla9yXSTAxmo9GVEouq5P40DWXdOie69bXogZTkgvopCq+yEvTMA0F6PEvdJmbtTV3ccIp11VQ==}
+
+ '@stoplight/yaml@4.3.0':
+ resolution: {integrity: sha512-JZlVFE6/dYpP9tQmV0/ADfn32L9uFarHWxfcRhReKUnljz1ZiUM5zpX+PH8h5CJs6lao3TuFqnPm9IJJCEkE2w==}
+ engines: {node: '>=10.8'}
+
+ '@storybook/addon-a11y@9.0.12':
+ resolution: {integrity: sha512-xdJPYNxYU6A3DA48h6y0o3XziCp4YDGXcFKkc5Ce1GPFCa7ebFFh2trHqzevoFSGdQxWc5M3W0A4dhQtkpT4Ww==}
peerDependencies:
- storybook: ^8.6.14
+ storybook: ^9.0.12
- '@storybook/addon-backgrounds@8.6.14':
- resolution: {integrity: sha512-l9xS8qWe5n4tvMwth09QxH2PmJbCctEvBAc1tjjRasAfrd69f7/uFK4WhwJAstzBTNgTc8VXI4w8ZR97i1sFbg==}
+ '@storybook/addon-docs@9.0.12':
+ resolution: {integrity: sha512-bAuFy4BWGEBIC0EAS4N+V8mHj7NZiSdDnJUSr4Al3znEVzNHLpQAMRznkga2Ok8x+gwcyBG7W47dLbDXVqLZDg==}
peerDependencies:
- storybook: ^8.6.14
+ storybook: ^9.0.12
- '@storybook/addon-controls@8.6.14':
- resolution: {integrity: sha512-IiQpkNJdiRyA4Mq9mzjZlvQugL/aE7hNgVxBBGPiIZG6wb6Ht9hNnBYpap5ZXXFKV9p2qVI0FZK445ONmAa+Cw==}
- peerDependencies:
- storybook: ^8.6.14
-
- '@storybook/addon-docs@8.6.14':
- resolution: {integrity: sha512-Obpd0OhAF99JyU5pp5ci17YmpcQtMNgqW2pTXV8jAiiipWpwO++hNDeQmLmlSXB399XjtRDOcDVkoc7rc6JzdQ==}
- peerDependencies:
- storybook: ^8.6.14
-
- '@storybook/addon-essentials@8.6.14':
- resolution: {integrity: sha512-5ZZSHNaW9mXMOFkoPyc3QkoNGdJHETZydI62/OASR0lmPlJ1065TNigEo5dJddmZNn0/3bkE8eKMAzLnO5eIdA==}
- peerDependencies:
- storybook: ^8.6.14
-
- '@storybook/addon-highlight@8.6.14':
- resolution: {integrity: sha512-4H19OJlapkofiE9tM6K/vsepf4ir9jMm9T+zw5L85blJZxhKZIbJ6FO0TCG9PDc4iPt3L6+aq5B0X29s9zicNQ==}
- peerDependencies:
- storybook: ^8.6.14
-
- '@storybook/addon-interactions@8.6.14':
- resolution: {integrity: sha512-8VmElhm2XOjh22l/dO4UmXxNOolGhNiSpBcls2pqWSraVh4a670EyYBZsHpkXqfNHo2YgKyZN3C91+9zfH79qQ==}
- peerDependencies:
- storybook: ^8.6.14
-
- '@storybook/addon-links@8.6.14':
- resolution: {integrity: sha512-DRlXHIyZzOruAZkxmXfVgTF+4d6K27pFcH4cUsm3KT1AXuZbr23lb5iZHpUZoG6lmU85Sru4xCEgewSTXBIe1w==}
+ '@storybook/addon-links@9.0.12':
+ resolution: {integrity: sha512-Ix7WXnCMkEWrgBrGCoZAFH276Xj/4g8e5Kao9BSZneUBjJJC2LuCaTftGeiM4kQ7sKBPOc/L6zIyusWckBvXIQ==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
- storybook: ^8.6.14
+ storybook: ^9.0.12
peerDependenciesMeta:
react:
optional: true
- '@storybook/addon-measure@8.6.14':
- resolution: {integrity: sha512-1Tlyb72NX8aAqm6I6OICsUuGOP6hgnXcuFlXucyhKomPa6j3Eu2vKu561t/f0oGtAK2nO93Z70kVaEh5X+vaGw==}
+ '@storybook/addon-onboarding@9.0.12':
+ resolution: {integrity: sha512-hqgaINYMDiA2op+Cb77LvwdJkgpMUMAnp5ugJjkn5icLpSTkZxnaQrlC0lTHOZBxUjR5NlS2ApSAuMvrCXQLAw==}
peerDependencies:
- storybook: ^8.6.14
+ storybook: ^9.0.12
- '@storybook/addon-onboarding@8.6.14':
- resolution: {integrity: sha512-bHdHiGJFigVcSzMIsNLHY5IODZHr+nKwyz5/QOZLMkLcGH2IaUbOJfm4RyGOaTTPsUtAKbdsVXNEG3Otf+qO9A==}
+ '@storybook/builder-webpack5@9.0.12':
+ resolution: {integrity: sha512-zfmGYZjDppYPZZgSwW9ZRfIrCvshZcLombKmVEodlt/RMs5N5zaTCNf5p7+Z1BBcRpH5HXHWjwmrlobW6LzsLg==}
peerDependencies:
- storybook: ^8.6.14
-
- '@storybook/addon-outline@8.6.14':
- resolution: {integrity: sha512-CW857JvN6OxGWElqjlzJO2S69DHf+xO3WsEfT5mT3ZtIjmsvRDukdWfDU9bIYUFyA2lFvYjncBGjbK+I91XR7w==}
- peerDependencies:
- storybook: ^8.6.14
-
- '@storybook/addon-toolbars@8.6.14':
- resolution: {integrity: sha512-W/wEXT8h3VyZTVfWK/84BAcjAxTdtRiAkT2KAN0nbSHxxB5KEM1MjKpKu2upyzzMa3EywITqbfy4dP6lpkVTwQ==}
- peerDependencies:
- storybook: ^8.6.14
-
- '@storybook/addon-viewport@8.6.14':
- resolution: {integrity: sha512-gNzVQbMqRC+/4uQTPI2ZrWuRHGquTMZpdgB9DrD88VTEjNudP+J6r8myLfr2VvGksBbUMHkGHMXHuIhrBEnXYA==}
- peerDependencies:
- storybook: ^8.6.14
-
- '@storybook/blocks@8.6.14':
- resolution: {integrity: sha512-rBMHAfA39AGHgkrDze4RmsnQTMw1ND5fGWobr9pDcJdnDKWQWNRD7Nrlxj0gFlN3n4D9lEZhWGdFrCbku7FVAQ==}
- peerDependencies:
- react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
- react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
- storybook: ^8.6.14
- peerDependenciesMeta:
- react:
- optional: true
- react-dom:
- optional: true
-
- '@storybook/builder-webpack5@8.6.14':
- resolution: {integrity: sha512-YZYAqc6NBKoMTKZpjxnkMch6zDtMkBZdS/yaji1+wJX2QPFBwTbSh7SpeBxDp1S11gXSAJ4f1btUWeqSqo8nJA==}
- peerDependencies:
- storybook: ^8.6.14
+ storybook: ^9.0.12
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
- '@storybook/components@8.6.14':
- resolution: {integrity: sha512-HNR2mC5I4Z5ek8kTrVZlIY/B8gJGs5b3XdZPBPBopTIN6U/YHXiDyOjY3JlaS4fSG1fVhp/Qp1TpMn1w/9m1pw==}
+ '@storybook/core-webpack@9.0.12':
+ resolution: {integrity: sha512-soFgpQh8pfba94YjkFBMNO4460/NEhdWe2WUPJs5drz2tOyGSElYma9KKjkbn+SQtr4qG0Xu7P56e8DJMXiMDg==}
peerDependencies:
- storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0
+ storybook: ^9.0.12
- '@storybook/core-webpack@8.6.14':
- resolution: {integrity: sha512-iG7r8osNKabSGBbuJuSeMWKbU+ilt5PvzTYkClcYaagla/DliXkXvfywA6jOugVk/Cpx+c6tVKlPfjLcaQHwmw==}
+ '@storybook/csf-plugin@9.0.12':
+ resolution: {integrity: sha512-5EueJQJAu77Lh+EedG4Q/kEOZNlTY/g+fWsT7B5DTtLVy0ypnghsHY8X3KYT/0+NNgTtoO0if4F+ejVYaLnMzA==}
peerDependencies:
- storybook: ^8.6.14
-
- '@storybook/core@8.6.14':
- resolution: {integrity: sha512-1P/w4FSNRqP8j3JQBOi3yGt8PVOgSRbP66Ok520T78eJBeqx9ukCfl912PQZ7SPbW3TIunBwLXMZOjZwBB/JmA==}
- peerDependencies:
- prettier: ^2 || ^3
- peerDependenciesMeta:
- prettier:
- optional: true
-
- '@storybook/csf-plugin@8.6.14':
- resolution: {integrity: sha512-dErtc9teAuN+eelN8FojzFE635xlq9cNGGGEu0WEmMUQ4iJ8pingvBO1N8X3scz4Ry7KnxX++NNf3J3gpxS8qQ==}
- peerDependencies:
- storybook: ^8.6.14
-
- '@storybook/csf@0.1.13':
- resolution: {integrity: sha512-7xOOwCLGB3ebM87eemep89MYRFTko+D8qE7EdAAq74lgdqRR5cOUtYWJLjO2dLtP94nqoOdHJo6MdLLKzg412Q==}
+ storybook: ^9.0.12
'@storybook/global@5.0.0':
resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==}
@@ -2782,24 +2599,14 @@ packages:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
- '@storybook/instrumenter@8.6.14':
- resolution: {integrity: sha512-iG4MlWCcz1L7Yu8AwgsnfVAmMbvyRSk700Mfy2g4c8y5O+Cv1ejshE1LBBsCwHgkuqU0H4R0qu4g23+6UnUemQ==}
+ '@storybook/nextjs@9.0.12':
+ resolution: {integrity: sha512-7+toUNcn17S1MlJTMj3miZ3ev8WIeWcr/2OVbwzFp+BKyZVVOXd5+YSWBqwg+k4H5CmwTrFYegQ3Yp2lqzgKoA==}
+ engines: {node: '>=20.0.0'}
peerDependencies:
- storybook: ^8.6.14
-
- '@storybook/manager-api@8.6.14':
- resolution: {integrity: sha512-ez0Zihuy17udLbfHZQXkGqwtep0mSGgHcNzGN7iZrMP1m+VmNo+7aGCJJdvXi7+iU3yq8weXSQFWg5DqWgLS7g==}
- peerDependencies:
- storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0
-
- '@storybook/nextjs@8.6.14':
- resolution: {integrity: sha512-HbOOpwxJxO8nIDBvEQL3Pt51GHxnSeVxQ/WApr1HCT5Ffu6KCHz8WVsX56taHdigxjonSq0NTnog+aTIP06Nkw==}
- engines: {node: '>=18.0.0'}
- peerDependencies:
- next: ^13.5.0 || ^14.0.0 || ^15.0.0
+ next: ^14.1.0 || ^15.0.0
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
- storybook: ^8.6.14
+ storybook: ^9.0.12
typescript: '*'
webpack: ^5.0.0
peerDependenciesMeta:
@@ -2808,68 +2615,43 @@ packages:
webpack:
optional: true
- '@storybook/preset-react-webpack@8.6.14':
- resolution: {integrity: sha512-M7Q6ErNx7N2hQorTz0OLa3YV8nc8OcvkDlCxqqnkHPGQNEIWEpeDvq3wn2OvZlrHDpchyuiquGXZ8aztVtBP2g==}
- engines: {node: '>=18.0.0'}
+ '@storybook/preset-react-webpack@9.0.12':
+ resolution: {integrity: sha512-Tl3Qrll29dwltI4lP15zbeSXqikKa4Ucp6NKf4+W/4adzOqGRjj/bIzO3FsIPoGNs4wfy5DsOgUUPHxI4Jx97w==}
+ engines: {node: '>=20.0.0'}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
- storybook: ^8.6.14
+ storybook: ^9.0.12
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
- '@storybook/preview-api@8.6.14':
- resolution: {integrity: sha512-2GhcCd4dNMrnD7eooEfvbfL4I83qAqEyO0CO7JQAmIO6Rxb9BsOLLI/GD5HkvQB73ArTJ+PT50rfaO820IExOQ==}
- peerDependencies:
- storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0
-
'@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0':
resolution: {integrity: sha512-KUqXC3oa9JuQ0kZJLBhVdS4lOneKTOopnNBK4tUAgoxWQ3u/IjzdueZjFr7gyBrXMoU6duutk3RQR9u8ZpYJ4Q==}
peerDependencies:
typescript: '>= 4.x'
webpack: '>= 4'
- '@storybook/react-dom-shim@8.6.14':
- resolution: {integrity: sha512-0hixr3dOy3f3M+HBofp3jtMQMS+sqzjKNgl7Arfuj3fvjmyXOks/yGjDImySR4imPtEllvPZfhiQNlejheaInw==}
+ '@storybook/react-dom-shim@9.0.12':
+ resolution: {integrity: sha512-OMBitzkJRga/UJF1ScSnaxgBSlAVePCK8wzPkGDn0MmsjZ4oDWuNZeKnVO1+tb6n2rZHws7RmKGxHzHAZTY+zQ==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
- storybook: ^8.6.14
+ storybook: ^9.0.12
- '@storybook/react@8.6.14':
- resolution: {integrity: sha512-BOepx5bBFwl/CPI+F+LnmMmsG1wQYmrX/UQXgUbHQUU9Tj7E2ndTnNbpIuSLc8IrM03ru+DfwSg1Co3cxWtT+g==}
- engines: {node: '>=18.0.0'}
+ '@storybook/react@9.0.12':
+ resolution: {integrity: sha512-rDrf5MDfsguNDTSOfGqhAjQDhp3jDMdzAoCqLjQ75M647C8nsv9i+fftO3k0rMxIJRrESpZWqVZ4tsjOX+J3DA==}
+ engines: {node: '>=20.0.0'}
peerDependencies:
- '@storybook/test': 8.6.14
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
- storybook: ^8.6.14
- typescript: '>= 4.2.x'
+ storybook: ^9.0.12
+ typescript: '>= 4.9.x'
peerDependenciesMeta:
- '@storybook/test':
- optional: true
typescript:
optional: true
- '@storybook/test-runner@0.22.1':
- resolution: {integrity: sha512-F5omZH0Pj2Y0UXSqShl1RuPrnhLBbb/yPFnZbVWDSPWZHDSX+dfBuu1T2zVfJplNKd04RzJuMbWHPFtZ0mimSw==}
- engines: {node: ^16.10.0 || ^18.0.0 || >=20.0.0}
- hasBin: true
- peerDependencies:
- storybook: ^0.0.0-0 || ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 || ^9.0.0-0
-
- '@storybook/test@8.6.14':
- resolution: {integrity: sha512-GkPNBbbZmz+XRdrhMtkxPotCLOQ1BaGNp/gFZYdGDk2KmUWBKmvc5JxxOhtoXM2703IzNFlQHSSNnhrDZYuLlw==}
- peerDependencies:
- storybook: ^8.6.14
-
- '@storybook/theming@8.6.14':
- resolution: {integrity: sha512-r4y+LsiB37V5hzpQo+BM10PaCsp7YlZ0YcZzQP1OCkPlYXmUAFy2VvDKaFRpD8IeNPKug2u4iFm/laDEbs03dg==}
- peerDependencies:
- storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0
-
'@supabase/auth-js@2.70.0':
resolution: {integrity: sha512-BaAK/tOAZFJtzF1sE3gJ2FwTjLf4ky3PSvcvLGEgEmO4BSBkwWKu8l67rLLIBZPDnCyV7Owk2uPyKHa0kj5QGg==}
@@ -2897,89 +2679,33 @@ packages:
'@supabase/supabase-js@2.50.0':
resolution: {integrity: sha512-M1Gd5tPaaghYZ9OjeO1iORRqbTWFEz/cF3pPubRnMPzA+A8SiUsXXWDP+DWsASZcjEcVEcVQIAF38i5wrijYOg==}
- '@swc/core-darwin-arm64@1.11.31':
- resolution: {integrity: sha512-NTEaYOts0OGSbJZc0O74xsji+64JrF1stmBii6D5EevWEtrY4wlZhm8SiP/qPrOB+HqtAihxWIukWkP2aSdGSQ==}
- engines: {node: '>=10'}
- cpu: [arm64]
- os: [darwin]
-
- '@swc/core-darwin-x64@1.11.31':
- resolution: {integrity: sha512-THSGaSwT96JwXDwuXQ6yFBbn+xDMdyw7OmBpnweAWsh5DhZmQkALEm1DgdQO3+rrE99MkmzwAfclc0UmYro/OA==}
- engines: {node: '>=10'}
- cpu: [x64]
- os: [darwin]
-
- '@swc/core-linux-arm-gnueabihf@1.11.31':
- resolution: {integrity: sha512-laKtQFnW7KHgE57Hx32os2SNAogcuIDxYE+3DYIOmDMqD7/1DCfJe6Rln2N9WcOw6HuDbDpyQavIwZNfSAa8vQ==}
- engines: {node: '>=10'}
- cpu: [arm]
- os: [linux]
-
- '@swc/core-linux-arm64-gnu@1.11.31':
- resolution: {integrity: sha512-T+vGw9aPE1YVyRxRr1n7NAdkbgzBzrXCCJ95xAZc/0+WUwmL77Z+js0J5v1KKTRxw4FvrslNCOXzMWrSLdwPSA==}
- engines: {node: '>=10'}
- cpu: [arm64]
- os: [linux]
-
- '@swc/core-linux-arm64-musl@1.11.31':
- resolution: {integrity: sha512-Mztp5NZkyd5MrOAG+kl+QSn0lL4Uawd4CK4J7wm97Hs44N9DHGIG5nOz7Qve1KZo407Y25lTxi/PqzPKHo61zQ==}
- engines: {node: '>=10'}
- cpu: [arm64]
- os: [linux]
-
- '@swc/core-linux-x64-gnu@1.11.31':
- resolution: {integrity: sha512-DDVE0LZcXOWwOqFU1Xi7gdtiUg3FHA0vbGb3trjWCuI1ZtDZHEQYL4M3/2FjqKZtIwASrDvO96w91okZbXhvMg==}
- engines: {node: '>=10'}
- cpu: [x64]
- os: [linux]
-
- '@swc/core-linux-x64-musl@1.11.31':
- resolution: {integrity: sha512-mJA1MzPPRIfaBUHZi0xJQ4vwL09MNWDeFtxXb0r4Yzpf0v5Lue9ymumcBPmw/h6TKWms+Non4+TDquAsweuKSw==}
- engines: {node: '>=10'}
- cpu: [x64]
- os: [linux]
-
- '@swc/core-win32-arm64-msvc@1.11.31':
- resolution: {integrity: sha512-RdtakUkNVAb/FFIMw3LnfNdlH1/ep6KgiPDRlmyUfd0WdIQ3OACmeBegEFNFTzi7gEuzy2Yxg4LWf4IUVk8/bg==}
- engines: {node: '>=10'}
- cpu: [arm64]
- os: [win32]
-
- '@swc/core-win32-ia32-msvc@1.11.31':
- resolution: {integrity: sha512-hErXdCGsg7swWdG1fossuL8542I59xV+all751mYlBoZ8kOghLSKObGQTkBbuNvc0sUKWfWg1X0iBuIhAYar+w==}
- engines: {node: '>=10'}
- cpu: [ia32]
- os: [win32]
-
- '@swc/core-win32-x64-msvc@1.11.31':
- resolution: {integrity: sha512-5t7SGjUBMMhF9b5j17ml/f/498kiBJNf4vZFNM421UGUEETdtjPN9jZIuQrowBkoFGJTCVL/ECM4YRtTH30u/A==}
- engines: {node: '>=10'}
- cpu: [x64]
- os: [win32]
-
- '@swc/core@1.11.31':
- resolution: {integrity: sha512-mAby9aUnKRjMEA7v8cVZS9Ah4duoRBnX7X6r5qrhTxErx+68MoY1TPrVwj/66/SWN3Bl+jijqAqoB8Qx0QE34A==}
- engines: {node: '>=10'}
- peerDependencies:
- '@swc/helpers': '>=0.5.17'
- peerDependenciesMeta:
- '@swc/helpers':
- optional: true
-
'@swc/counter@0.1.3':
resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==}
'@swc/helpers@0.5.15':
resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==}
- '@swc/jest@0.2.38':
- resolution: {integrity: sha512-HMoZgXWMqChJwffdDjvplH53g9G2ALQes3HKXDEdliB/b85OQ0CTSbxG8VSeCwiAn7cOaDVEt4mwmZvbHcS52w==}
- engines: {npm: '>= 7.0.0'}
+ '@tanstack/eslint-plugin-query@5.78.0':
+ resolution: {integrity: sha512-hYkhWr3UP0CkAsn/phBVR98UQawbw8CmTSgWtdgEBUjI60/GBaEIkpgi/Bp/2I8eIDK4+vdY7ac6jZx+GR+hEQ==}
peerDependencies:
- '@swc/core': '*'
+ eslint: ^8.57.0 || ^9.0.0
- '@swc/types@0.1.22':
- resolution: {integrity: sha512-D13mY/ZA4PPEFSy6acki9eBT/3WgjMoRqNcdpIvjaYLQ44Xk5BdaL7UkDxAh6Z9UOe7tCCp67BVmZCojYp9owg==}
+ '@tanstack/query-core@5.80.7':
+ resolution: {integrity: sha512-s09l5zeUKC8q7DCCCIkVSns8zZrK4ZDT6ryEjxNBFi68G4z2EBobBS7rdOY3r6W1WbUDpc1fe5oY+YO/+2UVUg==}
+
+ '@tanstack/query-devtools@5.80.0':
+ resolution: {integrity: sha512-D6gH4asyjaoXrCOt5vG5Og/YSj0D/TxwNQgtLJIgWbhbWCC/emu2E92EFoVHh4ppVWg1qT2gKHvKyQBEFZhCuA==}
+
+ '@tanstack/react-query-devtools@5.80.10':
+ resolution: {integrity: sha512-6JL63fSc7kxyGOLV2w466SxhMn/m7LZk/ximQciy6OpVt+n2A8Mq3S0QwhIzfm4WEwLK/F3OELfzRToQburnYA==}
+ peerDependencies:
+ '@tanstack/react-query': ^5.80.10
+ react: ^18 || ^19
+
+ '@tanstack/react-query@5.80.7':
+ resolution: {integrity: sha512-u2F0VK6+anItoEvB3+rfvTO9GEh2vb00Je05OwlUe/A0lkJBgW1HckiY3f9YZa+jx6IOe4dHPh10dyp9aY3iRQ==}
+ peerDependencies:
+ react: ^18 || ^19
'@tanstack/react-table@8.21.3':
resolution: {integrity: sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==}
@@ -2996,12 +2722,12 @@ packages:
resolution: {integrity: sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==}
engines: {node: '>=18'}
- '@testing-library/jest-dom@6.5.0':
- resolution: {integrity: sha512-xGGHpBXYSHUUr6XsKBfs85TWlYKpTc37cSBBVrXcib2MkHLboWlkClhWF37JKlDb9KEq3dHs+f2xR7XJEWGBxA==}
+ '@testing-library/jest-dom@6.6.3':
+ resolution: {integrity: sha512-IteBhl4XqYNkM54f4ejhLRJiZNqcSCoXUOG2CPK7qbD322KjQozM4kHQOfkG2oln9b9HTYqs+Sae8vBATubxxA==}
engines: {node: '>=14', npm: '>=6', yarn: '>=1'}
- '@testing-library/user-event@14.5.2':
- resolution: {integrity: sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==}
+ '@testing-library/user-event@14.6.1':
+ resolution: {integrity: sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==}
engines: {node: '>=12', npm: '>=6'}
peerDependencies:
'@testing-library/dom': '>=7.21.4'
@@ -3078,6 +2804,9 @@ packages:
'@types/doctrine@0.0.9':
resolution: {integrity: sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==}
+ '@types/es-aggregate-error@1.0.6':
+ resolution: {integrity: sha512-qJ7LIFp06h1QE1aVxbVd+zJP2wdaugYXYfd6JxsyRMrYHaxb6itXPogW2tz+ylUJ1n1b+JF1PHyYCfYHm0dvUg==}
+
'@types/eslint-scope@3.7.7':
resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==}
@@ -3090,30 +2819,15 @@ packages:
'@types/estree@1.0.6':
resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
- '@types/estree@1.0.7':
- resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==}
-
'@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
- '@types/graceful-fs@4.1.9':
- resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==}
-
'@types/hast@3.0.4':
resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
'@types/html-minifier-terser@6.1.0':
resolution: {integrity: sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==}
- '@types/istanbul-lib-coverage@2.0.6':
- resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==}
-
- '@types/istanbul-lib-report@3.0.3':
- resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==}
-
- '@types/istanbul-reports@3.0.4':
- resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==}
-
'@types/jaro-winkler@0.2.4':
resolution: {integrity: sha512-TNVu6vL0Z3h+hYcW78IRloINA0y0MTVJ1PFVtVpBSgk+ejmaH5aVfcVghzNXZ0fa6gXe4zapNMQtMGWOJKTLig==}
@@ -3126,8 +2840,8 @@ packages:
'@types/junit-report-builder@3.0.2':
resolution: {integrity: sha512-R5M+SYhMbwBeQcNXYWNCZkl09vkVfAtcPIaCGdzIkkbeaTrVbGQ7HVgi4s+EmM/M1K4ZuWQH0jGcvMvNePfxYA==}
- '@types/lodash@4.17.17':
- resolution: {integrity: sha512-RRVJ+J3J+WmyOTqnz3PiBLA501eKwXl2noseKOrNo/6+XEHjTAxO4xHvxQB6QuNm+s4WRbn6rSiap8+EA+ykFQ==}
+ '@types/lodash@4.17.18':
+ resolution: {integrity: sha512-KJ65INaxqxmU6EoCiJmRPZC9H9RVWCRd349tXM2M3O5NA7cY6YL7c0bHAHQ93NOfTObEQ004kd2QVHs/r0+m4g==}
'@types/mdast@4.0.4':
resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
@@ -3159,8 +2873,8 @@ packages:
'@types/phoenix@1.6.6':
resolution: {integrity: sha512-PIzZZlEppgrpoT2QgbnDU+MMzuR6BbCjllj0bM70lWoejMeNJAxCchxnv7J3XFkI8MpygtRpzXrIlmWUBclP5A==}
- '@types/prop-types@15.7.14':
- resolution: {integrity: sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==}
+ '@types/prop-types@15.7.15':
+ resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==}
'@types/react-dom@18.3.5':
resolution: {integrity: sha512-P4t6saawp+b/dFrUr2cvkVsfvPguwsxtH6dNIYRllMsefqFzkZk5UIjzyDOv5g1dXIPdG4Sp1yCR4Z6RCUsG/Q==}
@@ -3182,9 +2896,6 @@ packages:
'@types/shimmer@1.2.0':
resolution: {integrity: sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg==}
- '@types/stack-utils@2.0.3':
- resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==}
-
'@types/statuses@2.0.6':
resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==}
@@ -3203,185 +2914,180 @@ packages:
'@types/unist@3.0.3':
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
- '@types/uuid@9.0.8':
- resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==}
-
- '@types/wait-on@5.3.4':
- resolution: {integrity: sha512-EBsPjFMrFlMbbUFf9D1Fp+PAB2TwmUn7a3YtHyD9RLuTIk1jDd8SxXVAoez2Ciy+8Jsceo2MYEYZzJ/DvorOKw==}
+ '@types/urijs@1.19.25':
+ resolution: {integrity: sha512-XOfUup9r3Y06nFAZh3WvO0rBU4OtlfPB/vgxpjg+NRdGU6CN6djdc6OEiH+PcqHCY6eFLo9Ista73uarf4gnBg==}
'@types/ws@8.18.1':
resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==}
- '@types/yargs-parser@21.0.3':
- resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==}
-
- '@types/yargs@17.0.33':
- resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==}
-
- '@typescript-eslint/eslint-plugin@8.33.1':
- resolution: {integrity: sha512-TDCXj+YxLgtvxvFlAvpoRv9MAncDLBV2oT9Bd7YBGC/b/sEURoOYuIwLI99rjWOfY3QtDzO+mk0n4AmdFExW8A==}
+ '@typescript-eslint/eslint-plugin@8.34.1':
+ resolution: {integrity: sha512-STXcN6ebF6li4PxwNeFnqF8/2BNDvBupf2OPx2yWNzr6mKNGF7q49VM00Pz5FaomJyqvbXpY6PhO+T9w139YEQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
- '@typescript-eslint/parser': ^8.33.1
+ '@typescript-eslint/parser': ^8.34.1
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
- '@typescript-eslint/parser@8.33.1':
- resolution: {integrity: sha512-qwxv6dq682yVvgKKp2qWwLgRbscDAYktPptK4JPojCwwi3R9cwrvIxS4lvBpzmcqzR4bdn54Z0IG1uHFskW4dA==}
+ '@typescript-eslint/parser@8.34.1':
+ resolution: {integrity: sha512-4O3idHxhyzjClSMJ0a29AcoK0+YwnEqzI6oz3vlRf3xw0zbzt15MzXwItOlnr5nIth6zlY2RENLsOPvhyrKAQA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
- '@typescript-eslint/project-service@8.33.1':
- resolution: {integrity: sha512-DZR0efeNklDIHHGRpMpR5gJITQpu6tLr9lDJnKdONTC7vvzOlLAG/wcfxcdxEWrbiZApcoBCzXqU/Z458Za5Iw==}
+ '@typescript-eslint/project-service@8.34.1':
+ resolution: {integrity: sha512-nuHlOmFZfuRwLJKDGQOVc0xnQrAmuq1Mj/ISou5044y1ajGNp2BNliIqp7F2LPQ5sForz8lempMFCovfeS1XoA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <5.9.0'
- '@typescript-eslint/scope-manager@8.33.1':
- resolution: {integrity: sha512-dM4UBtgmzHR9bS0Rv09JST0RcHYearoEoo3pG5B6GoTR9XcyeqX87FEhPo+5kTvVfKCvfHaHrcgeJQc6mrDKrA==}
+ '@typescript-eslint/scope-manager@8.34.1':
+ resolution: {integrity: sha512-beu6o6QY4hJAgL1E8RaXNC071G4Kso2MGmJskCFQhRhg8VOH/FDbC8soP8NHN7e/Hdphwp8G8cE6OBzC8o41ZA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@typescript-eslint/tsconfig-utils@8.33.1':
- resolution: {integrity: sha512-STAQsGYbHCF0/e+ShUQ4EatXQ7ceh3fBCXkNU7/MZVKulrlq1usH7t2FhxvCpuCi5O5oi1vmVaAjrGeL71OK1g==}
+ '@typescript-eslint/tsconfig-utils@8.34.1':
+ resolution: {integrity: sha512-K4Sjdo4/xF9NEeA2khOb7Y5nY6NSXBnod87uniVYW9kHP+hNlDV8trUSFeynA2uxWam4gIWgWoygPrv9VMWrYg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <5.9.0'
- '@typescript-eslint/type-utils@8.33.1':
- resolution: {integrity: sha512-1cG37d9xOkhlykom55WVwG2QRNC7YXlxMaMzqw2uPeJixBFfKWZgaP/hjAObqMN/u3fr5BrTwTnc31/L9jQ2ww==}
+ '@typescript-eslint/type-utils@8.34.1':
+ resolution: {integrity: sha512-Tv7tCCr6e5m8hP4+xFugcrwTOucB8lshffJ6zf1mF1TbU67R+ntCc6DzLNKM+s/uzDyv8gLq7tufaAhIBYeV8g==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
- '@typescript-eslint/types@8.33.1':
- resolution: {integrity: sha512-xid1WfizGhy/TKMTwhtVOgalHwPtV8T32MS9MaH50Cwvz6x6YqRIPdD2WvW0XaqOzTV9p5xdLY0h/ZusU5Lokg==}
+ '@typescript-eslint/types@8.34.1':
+ resolution: {integrity: sha512-rjLVbmE7HR18kDsjNIZQHxmv9RZwlgzavryL5Lnj2ujIRTeXlKtILHgRNmQ3j4daw7zd+mQgy+uyt6Zo6I0IGA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@typescript-eslint/typescript-estree@8.33.1':
- resolution: {integrity: sha512-+s9LYcT8LWjdYWu7IWs7FvUxpQ/DGkdjZeE/GGulHvv8rvYwQvVaUZ6DE+j5x/prADUgSbbCWZ2nPI3usuVeOA==}
+ '@typescript-eslint/typescript-estree@8.34.1':
+ resolution: {integrity: sha512-rjCNqqYPuMUF5ODD+hWBNmOitjBWghkGKJg6hiCHzUvXRy6rK22Jd3rwbP2Xi+R7oYVvIKhokHVhH41BxPV5mA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <5.9.0'
- '@typescript-eslint/utils@8.33.1':
- resolution: {integrity: sha512-52HaBiEQUaRYqAXpfzWSR2U3gxk92Kw006+xZpElaPMg3C4PgM+A5LqwoQI1f9E5aZ/qlxAZxzm42WX+vn92SQ==}
+ '@typescript-eslint/utils@8.34.1':
+ resolution: {integrity: sha512-mqOwUdZ3KjtGk7xJJnLbHxTuWVn3GO2WZZuM+Slhkun4+qthLdXx32C8xIXbO1kfCECb3jIs3eoxK3eryk7aoQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
- '@typescript-eslint/visitor-keys@8.33.1':
- resolution: {integrity: sha512-3i8NrFcZeeDHJ+7ZUuDkGT+UHq+XoFGsymNK2jZCOHcfEzRQ0BdpRtdpSx/Iyf3MHLWIcLS0COuOPibKQboIiQ==}
+ '@typescript-eslint/visitor-keys@8.34.1':
+ resolution: {integrity: sha512-xoh5rJ+tgsRKoXnkBPFRLZ7rjKM0AfVbC68UZ/ECXoDbfggb9RbEySN359acY1vS3qZ0jVTVWzbtfapwm5ztxw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@ungap/structured-clone@1.3.0':
resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
- '@unrs/resolver-binding-darwin-arm64@1.7.10':
- resolution: {integrity: sha512-ABsM3eEiL3yu903G0uxgvGAoIw011XjTzyEk//gGtuVY1PuXP2IJG6novd6DBjm7MaWmRV/CZFY1rWBXSlSVVw==}
+ '@unrs/resolver-binding-android-arm-eabi@1.9.0':
+ resolution: {integrity: sha512-h1T2c2Di49ekF2TE8ZCoJkb+jwETKUIPDJ/nO3tJBKlLFPu+fyd93f0rGP/BvArKx2k2HlRM4kqkNarj3dvZlg==}
+ cpu: [arm]
+ os: [android]
+
+ '@unrs/resolver-binding-android-arm64@1.9.0':
+ resolution: {integrity: sha512-sG1NHtgXtX8owEkJ11yn34vt0Xqzi3k9TJ8zppDmyG8GZV4kVWw44FHwKwHeEFl07uKPeC4ZoyuQaGh5ruJYPA==}
+ cpu: [arm64]
+ os: [android]
+
+ '@unrs/resolver-binding-darwin-arm64@1.9.0':
+ resolution: {integrity: sha512-nJ9z47kfFnCxN1z/oYZS7HSNsFh43y2asePzTEZpEvK7kGyuShSl3RRXnm/1QaqFL+iP+BjMwuB+DYUymOkA5A==}
cpu: [arm64]
os: [darwin]
- '@unrs/resolver-binding-darwin-x64@1.7.10':
- resolution: {integrity: sha512-lGVWy4FQEDo/PuI1VQXaQCY0XUg4xUJilf3fQ8NY4wtsQTm9lbasbUYf3nkoma+O2/do90jQTqkb02S3meyTDg==}
+ '@unrs/resolver-binding-darwin-x64@1.9.0':
+ resolution: {integrity: sha512-TK+UA1TTa0qS53rjWn7cVlEKVGz2B6JYe0C++TdQjvWYIyx83ruwh0wd4LRxYBM5HeuAzXcylA9BH2trARXJTw==}
cpu: [x64]
os: [darwin]
- '@unrs/resolver-binding-freebsd-x64@1.7.10':
- resolution: {integrity: sha512-g9XLCHzNGatY79JJNgxrUH6uAAfBDj2NWIlTnqQN5odwGKjyVfFZ5tFL1OxYPcxTHh384TY5lvTtF+fuEZNvBQ==}
+ '@unrs/resolver-binding-freebsd-x64@1.9.0':
+ resolution: {integrity: sha512-6uZwzMRFcD7CcCd0vz3Hp+9qIL2jseE/bx3ZjaLwn8t714nYGwiE84WpaMCYjU+IQET8Vu/+BNAGtYD7BG/0yA==}
cpu: [x64]
os: [freebsd]
- '@unrs/resolver-binding-linux-arm-gnueabihf@1.7.10':
- resolution: {integrity: sha512-zV0ZMNy50sJFJapsjec8onyL9YREQKT88V8KwMoOA+zki/duFUP0oyTlbax1jGKdh8rQnruvW9VYkovGvdBAsw==}
+ '@unrs/resolver-binding-linux-arm-gnueabihf@1.9.0':
+ resolution: {integrity: sha512-bPUBksQfrgcfv2+mm+AZinaKq8LCFvt5PThYqRotqSuuZK1TVKkhbVMS/jvSRfYl7jr3AoZLYbDkItxgqMKRkg==}
cpu: [arm]
os: [linux]
- '@unrs/resolver-binding-linux-arm-musleabihf@1.7.10':
- resolution: {integrity: sha512-jQxgb1DIDI7goyrabh4uvyWWBrFRfF+OOnS9SbF15h52g3Qjn/u8zG7wOQ0NjtcSMftzO75TITu9aHuI7FcqQQ==}
+ '@unrs/resolver-binding-linux-arm-musleabihf@1.9.0':
+ resolution: {integrity: sha512-uT6E7UBIrTdCsFQ+y0tQd3g5oudmrS/hds5pbU3h4s2t/1vsGWbbSKhBSCD9mcqaqkBwoqlECpUrRJCmldl8PA==}
cpu: [arm]
os: [linux]
- '@unrs/resolver-binding-linux-arm64-gnu@1.7.10':
- resolution: {integrity: sha512-9wVVlO6+aNlm90YWitwSI++HyCyBkzYCwMi7QbuGrTxDFm2pAgtpT0OEliaI7tLS8lAWYuDbzRRCJDgsdm6nwg==}
+ '@unrs/resolver-binding-linux-arm64-gnu@1.9.0':
+ resolution: {integrity: sha512-vdqBh911wc5awE2bX2zx3eflbyv8U9xbE/jVKAm425eRoOVv/VseGZsqi3A3SykckSpF4wSROkbQPvbQFn8EsA==}
cpu: [arm64]
os: [linux]
- '@unrs/resolver-binding-linux-arm64-musl@1.7.10':
- resolution: {integrity: sha512-FtFweORChdXOes0RAAyTZp6I4PodU2cZiSILAbGaEKDXp378UOumD2vaAkWHNxpsreQUKRxG5O1uq9EoV1NiVQ==}
+ '@unrs/resolver-binding-linux-arm64-musl@1.9.0':
+ resolution: {integrity: sha512-/8JFZ/SnuDr1lLEVsxsuVwrsGquTvT51RZGvyDB/dOK3oYK2UqeXzgeyq6Otp8FZXQcEYqJwxb9v+gtdXn03eQ==}
cpu: [arm64]
os: [linux]
- '@unrs/resolver-binding-linux-ppc64-gnu@1.7.10':
- resolution: {integrity: sha512-B+hOjpG2ncCR96a9d9ww1dWVuRVC2NChD0bITgrUhEWBhpdv2o/Mu2l8MsB2fzjdV/ku+twaQhr8iLHBoZafZQ==}
+ '@unrs/resolver-binding-linux-ppc64-gnu@1.9.0':
+ resolution: {integrity: sha512-FkJjybtrl+rajTw4loI3L6YqSOpeZfDls4SstL/5lsP2bka9TiHUjgMBjygeZEis1oC8LfJTS8FSgpKPaQx2tQ==}
cpu: [ppc64]
os: [linux]
- '@unrs/resolver-binding-linux-riscv64-gnu@1.7.10':
- resolution: {integrity: sha512-DS6jFDoQCFsnsdLXlj3z3THakQLBic63B6A0rpQ1kpkyKa3OzEfqhwRNVaywuUuOKP9bX55Jk2uqpvn/hGjKCg==}
+ '@unrs/resolver-binding-linux-riscv64-gnu@1.9.0':
+ resolution: {integrity: sha512-w/NZfHNeDusbqSZ8r/hp8iL4S39h4+vQMc9/vvzuIKMWKppyUGKm3IST0Qv0aOZ1rzIbl9SrDeIqK86ZpUK37w==}
cpu: [riscv64]
os: [linux]
- '@unrs/resolver-binding-linux-riscv64-musl@1.7.10':
- resolution: {integrity: sha512-A82SB6yEaA8EhIW2r0I7P+k5lg7zPscFnGs1Gna5rfPwoZjeUAGX76T55+DiyTiy08VFKUi79PGCulXnfjDq0g==}
+ '@unrs/resolver-binding-linux-riscv64-musl@1.9.0':
+ resolution: {integrity: sha512-bEPBosut8/8KQbUixPry8zg/fOzVOWyvwzOfz0C0Rw6dp+wIBseyiHKjkcSyZKv/98edrbMknBaMNJfA/UEdqw==}
cpu: [riscv64]
os: [linux]
- '@unrs/resolver-binding-linux-s390x-gnu@1.7.10':
- resolution: {integrity: sha512-J+VmOPH16U69QshCp9WS+Zuiuu9GWTISKchKIhLbS/6JSCEfw2A4N02whv2VmrkXE287xxZbhW1p6xlAXNzwqg==}
+ '@unrs/resolver-binding-linux-s390x-gnu@1.9.0':
+ resolution: {integrity: sha512-LDtMT7moE3gK753gG4pc31AAqGUC86j3AplaFusc717EUGF9ZFJ356sdQzzZzkBk1XzMdxFyZ4f/i35NKM/lFA==}
cpu: [s390x]
os: [linux]
- '@unrs/resolver-binding-linux-x64-gnu@1.7.10':
- resolution: {integrity: sha512-bYTdDltcB/V3fEqpx8YDwDw8ta9uEg8TUbJOtek6JM42u9ciJ7R/jBjNeAOs+QbyxGDd2d6xkBaGwty1HzOz3Q==}
+ '@unrs/resolver-binding-linux-x64-gnu@1.9.0':
+ resolution: {integrity: sha512-WmFd5KINHIXj8o1mPaT8QRjA9HgSXhN1gl9Da4IZihARihEnOylu4co7i/yeaIpcfsI6sYs33cNZKyHYDh0lrA==}
cpu: [x64]
os: [linux]
- '@unrs/resolver-binding-linux-x64-musl@1.7.10':
- resolution: {integrity: sha512-NYZ1GvSuTokJ28lqcjrMTnGMySoo4dVcNK/nsNCKCXT++1zekZtJaE+N+4jc1kR7EV0fc1OhRrOGcSt7FT9t8w==}
+ '@unrs/resolver-binding-linux-x64-musl@1.9.0':
+ resolution: {integrity: sha512-CYuXbANW+WgzVRIl8/QvZmDaZxrqvOldOwlbUjIM4pQ46FJ0W5cinJ/Ghwa/Ng1ZPMJMk1VFdsD/XwmCGIXBWg==}
cpu: [x64]
os: [linux]
- '@unrs/resolver-binding-wasm32-wasi@1.7.10':
- resolution: {integrity: sha512-MRjJhTaQzLoX8OtzRBQDJ84OJ8IX1FqpRAUSxp/JtPeak+fyDfhXaEjcA/fhfgrACUnvC+jWC52f/V6MixSKCQ==}
+ '@unrs/resolver-binding-wasm32-wasi@1.9.0':
+ resolution: {integrity: sha512-6Rp2WH0OoitMYR57Z6VE8Y6corX8C6QEMWLgOV6qXiJIeZ1F9WGXY/yQ8yDC4iTraotyLOeJ2Asea0urWj2fKQ==}
engines: {node: '>=14.0.0'}
cpu: [wasm32]
- '@unrs/resolver-binding-win32-arm64-msvc@1.7.10':
- resolution: {integrity: sha512-Cgw6qhdsfzXJnHb006CzqgaX8mD445x5FGKuueaLeH1ptCxDbzRs8wDm6VieOI7rdbstfYBaFtaYN7zBT5CUPg==}
+ '@unrs/resolver-binding-win32-arm64-msvc@1.9.0':
+ resolution: {integrity: sha512-rknkrTRuvujprrbPmGeHi8wYWxmNVlBoNW8+4XF2hXUnASOjmuC9FNF1tGbDiRQWn264q9U/oGtixyO3BT8adQ==}
cpu: [arm64]
os: [win32]
- '@unrs/resolver-binding-win32-ia32-msvc@1.7.10':
- resolution: {integrity: sha512-Z7oECyIT2/HsrWpJ6wi2b+lVbPmWqQHuW5zeatafoRXizk1+2wUl+aSop1PF58XcyBuwPP2YpEUUpMZ8ILV4fA==}
+ '@unrs/resolver-binding-win32-ia32-msvc@1.9.0':
+ resolution: {integrity: sha512-Ceymm+iBl+bgAICtgiHyMLz6hjxmLJKqBim8tDzpX61wpZOx2bPK6Gjuor7I2RiUynVjvvkoRIkrPyMwzBzF3A==}
cpu: [ia32]
os: [win32]
- '@unrs/resolver-binding-win32-x64-msvc@1.7.10':
- resolution: {integrity: sha512-DGAOo5asNvDsmFgwkb7xsgxNyN0If6XFYwDIC1QlRE7kEYWIMRChtWJyHDf30XmGovDNOs/37krxhnga/nm/4w==}
+ '@unrs/resolver-binding-win32-x64-msvc@1.9.0':
+ resolution: {integrity: sha512-k59o9ZyeyS0hAlcaKFezYSH2agQeRFEB7KoQLXl3Nb3rgkqT1NY9Vwy+SqODiLmYnEjxWJVRE/yq2jFVqdIxZw==}
cpu: [x64]
os: [win32]
- '@vitest/expect@2.0.5':
- resolution: {integrity: sha512-yHZtwuP7JZivj65Gxoi8upUN2OzHTi3zVfjwdpu2WrvCZPLwsJ2Ey5ILIPccoW23dd/zQBlJ4/dhi7DWNyXCpA==}
+ '@vitest/expect@3.0.9':
+ resolution: {integrity: sha512-5eCqRItYgIML7NNVgJj6TVCmdzE7ZVgJhruW0ziSQV4V7PvLkDL1bBkBdcTs/VuIz0IxPb5da1IDSqc1TR9eig==}
- '@vitest/pretty-format@2.0.5':
- resolution: {integrity: sha512-h8k+1oWHfwTkyTkb9egzwNMfJAEx4veaPSnMeKbVSjp4euqGSbQlm5+6VHwTr7u4FJslVVsUG5nopCaAYdOmSQ==}
+ '@vitest/pretty-format@3.0.9':
+ resolution: {integrity: sha512-OW9F8t2J3AwFEwENg3yMyKWweF7oRJlMyHOMIhO5F3n0+cgQAJZBjNgrF8dLwFTEXl5jUqBLXd9QyyKv8zEcmA==}
- '@vitest/pretty-format@2.1.9':
- resolution: {integrity: sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==}
+ '@vitest/spy@3.0.9':
+ resolution: {integrity: sha512-/CcK2UDl0aQ2wtkp3YVWldrpLRNCfVcIOFGlVGKO4R5eajsH393Z1yiXLVQ7vWsj26JOEjeZI0x5sm5P4OGUNQ==}
- '@vitest/spy@2.0.5':
- resolution: {integrity: sha512-c/jdthAhvJdpfVuaexSrnawxZz6pywlTPe84LUB2m/4t3rl2fTo9NFGBG4oWgaD+FTgDDV8hJ/nibT7IfH3JfA==}
-
- '@vitest/utils@2.0.5':
- resolution: {integrity: sha512-d8HKbqIcya+GR67mkZbrzhS5kKhtp8dQLcmRZLGTscGVg7yImT82cIrhtn2L8+VujWcy6KZweApgNmPsTAO/UQ==}
-
- '@vitest/utils@2.1.9':
- resolution: {integrity: sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==}
+ '@vitest/utils@3.0.9':
+ resolution: {integrity: sha512-ilHM5fHhZ89MCp5aAaM9uhfl1c2JdxVxl3McqsdVyVNN6JffnEen8UMCdRTzOhGXNQGo5GNL9QugHrz727Wnng==}
'@webassemblyjs/ast@1.14.1':
resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==}
@@ -3457,11 +3163,6 @@ packages:
peerDependencies:
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
- acorn@8.14.1:
- resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==}
- engines: {node: '>=0.4.0'}
- hasBin: true
-
acorn@8.15.0:
resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
engines: {node: '>=0.4.0'}
@@ -3475,9 +3176,18 @@ packages:
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
engines: {node: '>= 6.0.0'}
- aggregate-error@3.1.0:
- resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==}
- engines: {node: '>=8'}
+ ajv-draft-04@1.0.0:
+ resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==}
+ peerDependencies:
+ ajv: ^8.5.0
+ peerDependenciesMeta:
+ ajv:
+ optional: true
+
+ ajv-errors@3.0.0:
+ resolution: {integrity: sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ==}
+ peerDependencies:
+ ajv: ^8.0.1
ajv-formats@2.1.1:
resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
@@ -3503,14 +3213,14 @@ packages:
ajv@8.17.1:
resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
+ ansi-colors@4.1.3:
+ resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
+ engines: {node: '>=6'}
+
ansi-escapes@4.3.2:
resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
engines: {node: '>=8'}
- ansi-escapes@6.2.1:
- resolution: {integrity: sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==}
- engines: {node: '>=14.16'}
-
ansi-html-community@0.0.8:
resolution: {integrity: sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==}
engines: {'0': node >= 0.8.0}
@@ -3529,10 +3239,6 @@ packages:
resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==}
engines: {node: '>=12'}
- ansi-styles@3.2.1:
- resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
- engines: {node: '>=4'}
-
ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
@@ -3552,19 +3258,9 @@ packages:
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
engines: {node: '>= 8'}
- append-transform@2.0.0:
- resolution: {integrity: sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==}
- engines: {node: '>=8'}
-
- archy@1.0.0:
- resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==}
-
arg@5.0.2:
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
- argparse@1.0.10:
- resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
-
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
@@ -3587,6 +3283,10 @@ packages:
resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==}
engines: {node: '>= 0.4'}
+ array-union@2.1.0:
+ resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
+ engines: {node: '>=8'}
+
array.prototype.findlast@1.2.5:
resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==}
engines: {node: '>= 0.4'}
@@ -3628,13 +3328,14 @@ packages:
resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==}
engines: {node: '>=4'}
+ astring@1.9.0:
+ resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==}
+ hasBin: true
+
async-function@1.0.0:
resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==}
engines: {node: '>= 0.4'}
- asynckit@0.4.0:
- resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
-
available-typed-arrays@1.0.7:
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
engines: {node: '>= 0.4'}
@@ -3654,19 +3355,10 @@ packages:
peerDependencies:
playwright: '>1.0.0'
- axios@1.9.0:
- resolution: {integrity: sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==}
-
axobject-query@4.1.0:
resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
engines: {node: '>= 0.4'}
- babel-jest@29.7.0:
- resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- peerDependencies:
- '@babel/core': ^7.8.0
-
babel-loader@9.2.1:
resolution: {integrity: sha512-fqe8naHt46e0yIdkjUZYqddSXfej3AHajX+CSO5X7oy0EmPc6o5Xh+RClNoHjnieWz9AW4kZxW9yyFMhVB1QLA==}
engines: {node: '>= 14.15.0'}
@@ -3674,14 +3366,6 @@ packages:
'@babel/core': ^7.12.0
webpack: '>=5'
- babel-plugin-istanbul@6.1.1:
- resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==}
- engines: {node: '>=8'}
-
- babel-plugin-jest-hoist@29.6.3:
- resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
babel-plugin-polyfill-corejs2@0.4.13:
resolution: {integrity: sha512-3sX/eOms8kd3q2KZ6DAhKPc0dgm525Gqq5NtWKZ7QYYZEv57OQ54KtblzJzH1lQF/eQxO8KjWGIK9IPUJNus5g==}
peerDependencies:
@@ -3697,17 +3381,6 @@ packages:
peerDependencies:
'@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
- babel-preset-current-node-syntax@1.1.0:
- resolution: {integrity: sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==}
- peerDependencies:
- '@babel/core': ^7.0.0
-
- babel-preset-jest@29.6.3:
- resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- peerDependencies:
- '@babel/core': ^7.0.0
-
bail@2.0.2:
resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==}
@@ -3740,11 +3413,11 @@ packages:
boring-avatars@1.11.2:
resolution: {integrity: sha512-3+wkwPeObwS4R37FGXMYViqc4iTrIRj5yzfX9Qy4mnpZ26sX41dGMhsAgmKks1r/uufY1pl4vpgzMWHYfJRb2A==}
- brace-expansion@1.1.11:
- resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
+ brace-expansion@1.1.12:
+ resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==}
- brace-expansion@2.0.1:
- resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
+ brace-expansion@2.0.2:
+ resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
braces@3.0.3:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
@@ -3753,9 +3426,6 @@ packages:
brorand@1.1.0:
resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==}
- browser-assert@1.2.1:
- resolution: {integrity: sha512-nfulgvOR6S4gt9UKCeGJOuSGBPGiFT6oQ/2UBnvTY/5aQ1PnksW72fhZkM30DzoRRv2WpwZf1vHHEr3mtuXIWQ==}
-
browserify-aes@1.2.0:
resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==}
@@ -3781,9 +3451,6 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
- bser@2.1.1:
- resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==}
-
buffer-from@1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
@@ -3800,8 +3467,8 @@ packages:
resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
engines: {node: '>=10.16.0'}
- caching-transform@4.0.0:
- resolution: {integrity: sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==}
+ cac@6.7.14:
+ resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
engines: {node: '>=8'}
call-bind-apply-helpers@1.0.2:
@@ -3816,6 +3483,9 @@ packages:
resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
engines: {node: '>= 0.4'}
+ call-me-maybe@1.0.2:
+ resolution: {integrity: sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==}
+
callsites@3.1.0:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
@@ -3827,19 +3497,11 @@ packages:
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
engines: {node: '>= 6'}
- camelcase@5.3.1:
- resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
- engines: {node: '>=6'}
-
- camelcase@6.3.0:
- resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
- engines: {node: '>=10'}
-
camelize@1.0.1:
resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==}
- caniuse-lite@1.0.30001721:
- resolution: {integrity: sha512-cOuvmUVtKrtEaoKiO0rSc29jcjwMwX5tOHDy4MgVFEWiUXj4uBMJkwI8MDySkgXidpMiHUcviogAvFi4pA2hDQ==}
+ caniuse-lite@1.0.30001723:
+ resolution: {integrity: sha512-1R/elMjtehrFejxwmexeXAtae5UO9iSyFn6G/I806CYC/BLyyBk1EPhrKBkWhy6wM6Xnm47dSJQec+tLJ39WHw==}
case-sensitive-paths-webpack-plugin@2.4.0:
resolution: {integrity: sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==}
@@ -3852,10 +3514,6 @@ packages:
resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==}
engines: {node: '>=12'}
- chalk@2.4.2:
- resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
- engines: {node: '>=4'}
-
chalk@3.0.0:
resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==}
engines: {node: '>=8'}
@@ -3864,18 +3522,6 @@ packages:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
- chalk@5.4.1:
- resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==}
- engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
-
- char-regex@1.0.2:
- resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==}
- engines: {node: '>=10'}
-
- char-regex@2.0.2:
- resolution: {integrity: sha512-cbGOjAptfM2LVmWhwRFHEKTPkLwNddVmuqYZQt895yXwAsWsXObCG+YN4DGQ/JBtT4GP1a1lPPdio2z413LmTg==}
- engines: {node: '>=12.20'}
-
character-entities-html4@2.1.0:
resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==}
@@ -3896,6 +3542,10 @@ packages:
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
engines: {node: '>= 8.10.0'}
+ chokidar@4.0.3:
+ resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
+ engines: {node: '>= 14.16.0'}
+
chromatic@11.25.2:
resolution: {integrity: sha512-/9eQWn6BU1iFsop86t8Au21IksTRxwXAl7if8YHD05L2AbuMjClLWZo5cZojqrJHGKDhTqfrC2X2xE4uSm0iKw==}
hasBin: true
@@ -3908,14 +3558,22 @@ packages:
'@chromatic-com/playwright':
optional: true
+ chromatic@12.2.0:
+ resolution: {integrity: sha512-GswmBW9ZptAoTns1BMyjbm55Z7EsIJnUvYKdQqXIBZIKbGErmpA+p4c0BYA+nzw5B0M+rb3Iqp1IaH8TFwIQew==}
+ hasBin: true
+ peerDependencies:
+ '@chromatic-com/cypress': ^0.*.* || ^1.0.0
+ '@chromatic-com/playwright': ^0.*.* || ^1.0.0
+ peerDependenciesMeta:
+ '@chromatic-com/cypress':
+ optional: true
+ '@chromatic-com/playwright':
+ optional: true
+
chrome-trace-event@1.0.4:
resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==}
engines: {node: '>=6.0'}
- ci-info@3.9.0:
- resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==}
- engines: {node: '>=8'}
-
cipher-base@1.0.6:
resolution: {integrity: sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==}
engines: {node: '>= 0.10'}
@@ -3933,10 +3591,6 @@ packages:
resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==}
engines: {node: '>= 10.0'}
- clean-stack@2.2.0:
- resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==}
- engines: {node: '>=6'}
-
cli-width@4.1.0:
resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==}
engines: {node: '>= 12'}
@@ -3944,9 +3598,6 @@ packages:
client-only@0.0.1:
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
- cliui@6.0.0:
- resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==}
-
cliui@8.0.1:
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
engines: {node: '>=12'}
@@ -3961,23 +3612,10 @@ packages:
react: ^18 || ^19 || ^19.0.0-rc
react-dom: ^18 || ^19 || ^19.0.0-rc
- co@4.6.0:
- resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==}
- engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}
-
- collect-v8-coverage@1.0.2:
- resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==}
-
- color-convert@1.9.3:
- resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
-
color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
- color-name@1.1.3:
- resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
-
color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
@@ -3991,23 +3629,12 @@ packages:
colorette@2.0.20:
resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
- combined-stream@1.0.8:
- resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
- engines: {node: '>= 0.8'}
-
comma-separated-tokens@2.0.3:
resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
- commander@12.1.0:
- resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==}
- engines: {node: '>=18'}
-
commander@2.20.3:
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
- commander@3.0.2:
- resolution: {integrity: sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==}
-
commander@4.1.1:
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
engines: {node: '>= 6'}
@@ -4022,6 +3649,9 @@ packages:
commondir@1.0.1:
resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==}
+ compare-versions@6.1.1:
+ resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==}
+
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
@@ -4050,11 +3680,11 @@ packages:
resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==}
engines: {node: '>=18'}
- core-js-compat@3.42.0:
- resolution: {integrity: sha512-bQasjMfyDGyaeWKBIu33lHh9qlSR0MFE/Nmc6nMjf/iU9b3rSMdAYz1Baxrv4lPdGUsTqZudHA4jIGSJy0SWZQ==}
+ core-js-compat@3.43.0:
+ resolution: {integrity: sha512-2GML2ZsCc5LR7hZYz4AXmjQw8zuy2T//2QntwdnpuYI7jteT6GVYJL7F6C2C57R7gSYrcqVW3lAALefdbhBLDA==}
- core-js-pure@3.42.0:
- resolution: {integrity: sha512-007bM04u91fF4kMgwom2I5cQxAFIy8jVulgr9eozILl/SZE53QOqnW/+vviC+wQWLv+AunBG+8Q0TLoeSsSxRQ==}
+ core-js-pure@3.43.0:
+ resolution: {integrity: sha512-i/AgxU2+A+BbJdMxh3v7/vxi2SbFqxiFmg6VsDwYB4jkucrd1BZNA9a9gphC0fYMG5IBSgQcbQnk865VCLe7xA==}
core-util-is@1.0.3:
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
@@ -4081,11 +3711,6 @@ packages:
create-hmac@1.1.7:
resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==}
- create-jest@29.7.0:
- resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- hasBin: true
-
cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
@@ -4131,10 +3756,6 @@ packages:
csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
- cwd@0.10.0:
- resolution: {integrity: sha512-YGZxdTTL9lmLkCUTpg4j0zQ7IhRB5ZmqNBbGCl3Tg6MP/d5/6sY7L5mmTjzbc6JKgVZYiqTQTNhPFsbXNGlRaA==}
- engines: {node: '>=0.8'}
-
d3-array@3.2.4:
resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==}
engines: {node: '>=12'}
@@ -4239,27 +3860,15 @@ packages:
supports-color:
optional: true
- decamelize@1.2.0:
- resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
- engines: {node: '>=0.10.0'}
-
decimal.js-light@2.5.1:
resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==}
- decode-named-character-reference@1.1.0:
- resolution: {integrity: sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==}
+ decode-named-character-reference@1.2.0:
+ resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==}
dedent@0.7.0:
resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==}
- dedent@1.6.0:
- resolution: {integrity: sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==}
- peerDependencies:
- babel-plugin-macros: ^3.1.0
- peerDependenciesMeta:
- babel-plugin-macros:
- optional: true
-
deep-eql@5.0.2:
resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
engines: {node: '>=6'}
@@ -4275,10 +3884,6 @@ packages:
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
engines: {node: '>=0.10.0'}
- default-require-extensions@3.0.1:
- resolution: {integrity: sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==}
- engines: {node: '>=8'}
-
define-data-property@1.1.4:
resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
engines: {node: '>= 0.4'}
@@ -4291,9 +3896,9 @@ packages:
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
engines: {node: '>= 0.4'}
- delayed-stream@1.0.0:
- resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
- engines: {node: '>=0.4.0'}
+ dependency-graph@0.11.0:
+ resolution: {integrity: sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==}
+ engines: {node: '>= 0.6.0'}
dequal@2.0.3:
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
@@ -4306,10 +3911,6 @@ packages:
resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==}
engines: {node: '>=8'}
- detect-newline@3.1.0:
- resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==}
- engines: {node: '>=8'}
-
detect-node-es@1.1.0:
resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==}
@@ -4319,16 +3920,13 @@ packages:
didyoumean@1.2.2:
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
- diff-sequences@29.6.3:
- resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- diffable-html@4.1.0:
- resolution: {integrity: sha512-++kyNek+YBLH8cLXS+iTj/Hiy2s5qkRJEJ8kgu/WHbFrVY2vz9xPFUT+fii2zGF0m1CaojDlQJjkfrCt7YWM1g==}
-
diffie-hellman@5.0.3:
resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==}
+ dir-glob@3.0.1:
+ resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
+ engines: {node: '>=8'}
+
dlv@1.1.3:
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
@@ -4352,9 +3950,6 @@ packages:
dom-helpers@5.2.1:
resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==}
- dom-serializer@0.2.2:
- resolution: {integrity: sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==}
-
dom-serializer@1.4.1:
resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==}
@@ -4362,22 +3957,13 @@ packages:
resolution: {integrity: sha512-ArzcM/II1wCCujdCNyQjXrAFwS4mrLh4C7DZWlaI8mdh7h3BfKdNd3bKXITfl2PT9FtfQqaGvhi1vPRQPimjGA==}
engines: {node: '>=10'}
- domelementtype@1.3.1:
- resolution: {integrity: sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==}
-
domelementtype@2.3.0:
resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
- domhandler@2.4.2:
- resolution: {integrity: sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==}
-
domhandler@4.3.1:
resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==}
engines: {node: '>= 4'}
- domutils@1.7.0:
- resolution: {integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==}
-
domutils@2.8.0:
resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==}
@@ -4395,8 +3981,8 @@ packages:
eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
- electron-to-chromium@1.5.165:
- resolution: {integrity: sha512-naiMx1Z6Nb2TxPU6fiFrUrDTjyPMLdTtaOd2oLmG8zVSg2hCWGkhPyxwk+qRmZ1ytwVqUv0u7ZcDA5+ALhaUtw==}
+ electron-to-chromium@1.5.169:
+ resolution: {integrity: sha512-q7SQx6mkLy0GTJK9K9OiWeaBMV4XQtBSdf6MJUzDB/H/5tFXfIiX38Lci1Kl6SsgiEhz1SQI1ejEOU5asWEhwQ==}
elliptic@6.6.1:
resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==}
@@ -4414,10 +4000,6 @@ packages:
embla-carousel@8.6.0:
resolution: {integrity: sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==}
- emittery@0.13.1:
- resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==}
- engines: {node: '>=12'}
-
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
@@ -4435,12 +4017,17 @@ packages:
resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==}
engines: {node: '>=10.13.0'}
- entities@1.1.2:
- resolution: {integrity: sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==}
+ enquirer@2.4.1:
+ resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==}
+ engines: {node: '>=8.6'}
entities@2.2.0:
resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==}
+ entities@4.5.0:
+ resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
+ engines: {node: '>=0.12'}
+
env-paths@2.2.1:
resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
engines: {node: '>=6'}
@@ -4455,6 +4042,10 @@ packages:
resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==}
engines: {node: '>= 0.4'}
+ es-aggregate-error@1.0.14:
+ resolution: {integrity: sha512-3YxX6rVb07B5TV11AV5wsL7nQCHXNwoHPsQC8S4AmBiqYhyNCJ5BRKXkXyDJvs8QzXN20NgRtxe3dEEQD9NLHA==}
+ engines: {node: '>= 0.4'}
+
es-define-property@1.0.1:
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
engines: {node: '>= 0.4'}
@@ -4486,16 +4077,16 @@ packages:
resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
engines: {node: '>= 0.4'}
- es6-error@4.1.1:
- resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==}
+ es6-promise@3.3.1:
+ resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==}
esbuild-register@3.6.0:
resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==}
peerDependencies:
esbuild: '>=0.12 <1'
- esbuild@0.24.2:
- resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==}
+ esbuild@0.25.5:
+ resolution: {integrity: sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==}
engines: {node: '>=18'}
hasBin: true
@@ -4503,20 +4094,12 @@ packages:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'}
- escape-string-regexp@1.0.5:
- resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
- engines: {node: '>=0.8.0'}
-
- escape-string-regexp@2.0.0:
- resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==}
- engines: {node: '>=8'}
-
escape-string-regexp@4.0.0:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'}
- eslint-config-next@15.3.3:
- resolution: {integrity: sha512-QJLv/Ouk2vZnxL4b67njJwTLjTf7uZRltI0LL4GERYR4qMF5z08+gxkfODAeaK7TiC6o+cER91bDaEnwrTWV6Q==}
+ eslint-config-next@15.3.4:
+ resolution: {integrity: sha512-WqeumCq57QcTP2lYlV6BRUySfGiBYEXlQ1L0mQ+u4N4X4ZhUVSSQ52WtjqHv60pJ6dD7jn+YZc0d1/ZSsxccvg==}
peerDependencies:
eslint: ^7.23.0 || ^8.0.0 || ^9.0.0
typescript: '>=3.3.1'
@@ -4589,11 +4172,12 @@ packages:
peerDependencies:
eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7
- eslint-plugin-storybook@0.12.0:
- resolution: {integrity: sha512-Lg5I0+npTgiYgZ4KSvGWGDFZi3eOCNJPaWX0c9rTEEXC5wvooOClsP9ZtbI4hhFKyKgYR877KiJxbRTSJq9gWA==}
- engines: {node: '>= 18'}
+ eslint-plugin-storybook@9.0.12:
+ resolution: {integrity: sha512-dSzcozoI7tQRqfMODWfxahrRmKWsK88yKSUcO0+s361oYcX7nf8nEu99TQ/wuDLRHh+Zi7E2j43cPMH8gFo8OA==}
+ engines: {node: '>=20.0.0'}
peerDependencies:
eslint: '>=8'
+ storybook: ^9.0.12
eslint-scope@5.1.1:
resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==}
@@ -4607,8 +4191,8 @@ packages:
resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
- eslint-visitor-keys@4.2.0:
- resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==}
+ eslint-visitor-keys@4.2.1:
+ resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
eslint@8.57.1:
@@ -4648,9 +4232,6 @@ packages:
estree-walker@2.0.2:
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
- estree-walker@3.0.3:
- resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
-
esutils@2.0.3:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
@@ -4676,21 +4257,6 @@ packages:
exenv@1.2.2:
resolution: {integrity: sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==}
- exit@0.1.2:
- resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==}
- engines: {node: '>= 0.8.0'}
-
- expand-tilde@1.2.2:
- resolution: {integrity: sha512-rtmc+cjLZqnu9dSYosX9EWmSJhTwpACgJQTfj4hgg2JjOD/6SIQalZrt4a3aQeh++oNxkazcaxrhPUj6+g5G/Q==}
- engines: {node: '>=0.10.0'}
-
- expect-playwright@0.8.0:
- resolution: {integrity: sha512-+kn8561vHAY+dt+0gMqqj1oY+g5xWrsuGMk4QGxotT2WS545nVqqjs37z6hrYfIuucwqthzwJfCJUEYqixyljg==}
-
- expect@29.7.0:
- resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
extend@3.0.2:
resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
@@ -4721,17 +4287,20 @@ packages:
fast-levenshtein@2.0.6:
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+ fast-memoize@2.5.2:
+ resolution: {integrity: sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==}
+
+ fast-safe-stringify@2.1.1:
+ resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==}
+
fast-uri@3.0.6:
resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==}
fastq@1.19.1:
resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
- fb-watchman@2.0.2:
- resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==}
-
- fdir@6.4.5:
- resolution: {integrity: sha512-4BG7puHpVsIYxZUbiUE3RqGloLaSSwzYie5jvasC4LWuBWzZawynvYouhjbQKw2JuIGYdm0DzIxl8iVidKlUEw==}
+ fdir@6.4.6:
+ resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==}
peerDependencies:
picomatch: ^3 || ^4
peerDependenciesMeta:
@@ -4762,18 +4331,6 @@ packages:
resolution: {integrity: sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==}
engines: {node: '>=14.16'}
- find-file-up@0.1.3:
- resolution: {integrity: sha512-mBxmNbVyjg1LQIIpgO8hN+ybWBgDQK8qjht+EbrTCGmmPV/sc7RF1i9stPTD6bpvXZywBdrwRYxhSdJv867L6A==}
- engines: {node: '>=0.10.0'}
-
- find-pkg@0.1.2:
- resolution: {integrity: sha512-0rnQWcFwZr7eO0513HahrWafsc3CTFioEB7DRiEYCUM/70QXSY8f3mCST17HXLcPvEhzH/Ty/Bxd72ZZsr/yvw==}
- engines: {node: '>=0.10.0'}
-
- find-process@1.4.10:
- resolution: {integrity: sha512-ncYFnWEIwL7PzmrK1yZtaccN8GhethD37RzBHG6iOZoFYB4vSmLLXfeWJjeN5nMvCJMjOtBvBBF8OgxEcikiZg==}
- hasBin: true
-
find-up@4.1.0:
resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
engines: {node: '>=8'}
@@ -4786,6 +4343,10 @@ packages:
resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ find-up@7.0.0:
+ resolution: {integrity: sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==}
+ engines: {node: '>=18'}
+
flat-cache@3.2.0:
resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==}
engines: {node: ^10.12.0 || >=12.0.0}
@@ -4793,23 +4354,10 @@ packages:
flatted@3.3.3:
resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
- follow-redirects@1.15.9:
- resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
- engines: {node: '>=4.0'}
- peerDependencies:
- debug: '*'
- peerDependenciesMeta:
- debug:
- optional: true
-
for-each@0.3.5:
resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
engines: {node: '>= 0.4'}
- foreground-child@2.0.0:
- resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==}
- engines: {node: '>=8.0.0'}
-
foreground-child@3.3.1:
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
engines: {node: '>=14'}
@@ -4821,10 +4369,6 @@ packages:
typescript: '>3.6.0'
webpack: ^5.11.0
- form-data@4.0.3:
- resolution: {integrity: sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==}
- engines: {node: '>= 6'}
-
forwarded-parse@2.1.2:
resolution: {integrity: sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==}
@@ -4842,17 +4386,14 @@ packages:
react-dom:
optional: true
- fromentries@1.3.2:
- resolution: {integrity: sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==}
-
- fs-exists-sync@0.1.0:
- resolution: {integrity: sha512-cR/vflFyPZtrN6b38ZyWxpWdhlXrzZEBawlpBQMq7033xVY7/kg0GDMBK5jg8lDYQckdJ5x/YC88lM3C7VMsLg==}
- engines: {node: '>=0.10.0'}
-
fs-extra@10.1.0:
resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
engines: {node: '>=12'}
+ fs-extra@11.3.0:
+ resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==}
+ engines: {node: '>=14.14'}
+
fs-monkey@1.0.6:
resolution: {integrity: sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==}
@@ -4900,10 +4441,6 @@ packages:
resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==}
engines: {node: '>=6'}
- get-package-type@0.1.0:
- resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==}
- engines: {node: '>=8.0.0'}
-
get-proto@1.0.1:
resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
engines: {node: '>= 0.4'}
@@ -4942,14 +4479,6 @@ packages:
resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==}
engines: {node: '>=16 || 14 >=14.17'}
- global-modules@0.2.3:
- resolution: {integrity: sha512-JeXuCbvYzYXcwE6acL9V2bAOeSIGl4dD+iwLY9iUx2VBJJ80R18HCn+JCwHM9Oegdfya3lEkGCdaRkSyc10hDA==}
- engines: {node: '>=0.10.0'}
-
- global-prefix@0.1.5:
- resolution: {integrity: sha512-gOPiyxcD9dJGCEArAhF4Hd0BAqvAe/JzERP7tYumE4yIkmIedPUVXcJFWbV3/p/ovIIvKjkrTk+f1UVkq7vvbw==}
- engines: {node: '>=0.10.0'}
-
globals@11.12.0:
resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
engines: {node: '>=4'}
@@ -4962,6 +4491,10 @@ packages:
resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==}
engines: {node: '>= 0.4'}
+ globby@11.1.0:
+ resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
+ engines: {node: '>=10'}
+
gopd@1.2.0:
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
engines: {node: '>= 0.4'}
@@ -4980,10 +4513,6 @@ packages:
resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==}
engines: {node: '>= 0.4'}
- has-flag@3.0.0:
- resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
- engines: {node: '>=4'}
-
has-flag@4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
@@ -5010,10 +4539,6 @@ packages:
hash.js@1.1.7:
resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==}
- hasha@5.2.2:
- resolution: {integrity: sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==}
- engines: {node: '>=8'}
-
hasown@2.0.2:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
@@ -5037,16 +4562,9 @@ packages:
hoist-non-react-statics@3.3.2:
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
- homedir-polyfill@1.0.3:
- resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==}
- engines: {node: '>=0.10.0'}
-
html-entities@2.6.0:
resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==}
- html-escaper@2.0.2:
- resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
-
html-minifier-terser@6.1.0:
resolution: {integrity: sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==}
engines: {node: '>=12'}
@@ -5067,12 +4585,12 @@ packages:
webpack:
optional: true
- htmlparser2@3.10.1:
- resolution: {integrity: sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==}
-
htmlparser2@6.1.0:
resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==}
+ http2-client@1.3.5:
+ resolution: {integrity: sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA==}
+
https-browserify@1.0.0:
resolution: {integrity: sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==}
@@ -5101,22 +4619,20 @@ packages:
resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==}
engines: {node: '>= 4'}
- image-size@1.2.1:
- resolution: {integrity: sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==}
+ image-size@2.0.2:
+ resolution: {integrity: sha512-IRqXKlaXwgSMAMtpNzZa1ZAe8m+Sa1770Dhk8VkSsP9LS+iHD62Zd8FQKs8fbPiagBE7BzoFX23cxFnwshpV6w==}
engines: {node: '>=16.x'}
hasBin: true
+ immer@9.0.21:
+ resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==}
+
import-fresh@3.3.1:
resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
engines: {node: '>=6'}
- import-in-the-middle@1.14.0:
- resolution: {integrity: sha512-g5zLT0HaztRJWysayWYiUq/7E5H825QIiecMD2pI5QO7Wzr847l6GDvPvmZaDIdrDtS2w7qRczywxiK6SL5vRw==}
-
- import-local@3.2.0:
- resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==}
- engines: {node: '>=8'}
- hasBin: true
+ import-in-the-middle@1.14.2:
+ resolution: {integrity: sha512-5tCuY9BV8ujfOpwtAGgsTx9CGUapcFMEEyByLv1B+v2+6DhAcw+Zr0nhQT7uwaZ7DiourxFEscghOR8e1aPLQw==}
imurmurhash@0.1.4:
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
@@ -5133,9 +4649,6 @@ packages:
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
- ini@1.3.8:
- resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
-
inline-style-parser@0.2.4:
resolution: {integrity: sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==}
@@ -5222,10 +4735,6 @@ packages:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
- is-generator-fn@2.1.0:
- resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==}
- engines: {node: '>=6'}
-
is-generator-function@1.1.0:
resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==}
engines: {node: '>= 0.4'}
@@ -5299,9 +4808,6 @@ packages:
resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==}
engines: {node: '>= 0.4'}
- is-typedarray@1.0.0:
- resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==}
-
is-weakmap@2.0.2:
resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==}
engines: {node: '>= 0.4'}
@@ -5314,14 +4820,6 @@ packages:
resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==}
engines: {node: '>= 0.4'}
- is-windows@0.2.0:
- resolution: {integrity: sha512-n67eJYmXbniZB7RF4I/FTjK1s6RPOCTxhYrVYLRaCt3lF0mpWZPKr3T2LSZAqyjQsxR2qMmGYXXzK0YWwcPM1Q==}
- engines: {node: '>=0.10.0'}
-
- is-windows@1.0.2:
- resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==}
- engines: {node: '>=0.10.0'}
-
is-wsl@2.2.0:
resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==}
engines: {node: '>=8'}
@@ -5335,42 +4833,6 @@ packages:
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
- istanbul-lib-coverage@3.2.2:
- resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
- engines: {node: '>=8'}
-
- istanbul-lib-hook@3.0.0:
- resolution: {integrity: sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==}
- engines: {node: '>=8'}
-
- istanbul-lib-instrument@4.0.3:
- resolution: {integrity: sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==}
- engines: {node: '>=8'}
-
- istanbul-lib-instrument@5.2.1:
- resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==}
- engines: {node: '>=8'}
-
- istanbul-lib-instrument@6.0.3:
- resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==}
- engines: {node: '>=10'}
-
- istanbul-lib-processinfo@2.0.3:
- resolution: {integrity: sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==}
- engines: {node: '>=8'}
-
- istanbul-lib-report@3.0.1:
- resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
- engines: {node: '>=10'}
-
- istanbul-lib-source-maps@4.0.1:
- resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==}
- engines: {node: '>=10'}
-
- istanbul-reports@3.1.7:
- resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==}
- engines: {node: '>=8'}
-
iterator.prototype@1.1.5:
resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==}
engines: {node: '>= 0.4'}
@@ -5381,184 +4843,24 @@ packages:
jaro-winkler@0.2.8:
resolution: {integrity: sha512-yr+mElb6dWxA1mzFu0+26njV5DWAQRNTi5pB6fFMm79zHrfAs3d0qjhe/IpZI4AHIUJkzvu5QXQRWOw2O0GQyw==}
- jest-changed-files@29.7.0:
- resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-circus@29.7.0:
- resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-cli@29.7.0:
- resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- hasBin: true
- peerDependencies:
- node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
- peerDependenciesMeta:
- node-notifier:
- optional: true
-
- jest-config@29.7.0:
- resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- peerDependencies:
- '@types/node': '*'
- ts-node: '>=9.0.0'
- peerDependenciesMeta:
- '@types/node':
- optional: true
- ts-node:
- optional: true
-
- jest-diff@29.7.0:
- resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-docblock@29.7.0:
- resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-each@29.7.0:
- resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-environment-node@29.7.0:
- resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-get-type@29.6.3:
- resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-haste-map@29.7.0:
- resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-junit@16.0.0:
- resolution: {integrity: sha512-A94mmw6NfJab4Fg/BlvVOUXzXgF0XIH6EmTgJ5NDPp4xoKq0Kr7sErb+4Xs9nZvu58pJojz5RFGpqnZYJTrRfQ==}
- engines: {node: '>=10.12.0'}
-
- jest-leak-detector@29.7.0:
- resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-matcher-utils@29.7.0:
- resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-message-util@29.7.0:
- resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-mock@29.7.0:
- resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-playwright-preset@4.0.0:
- resolution: {integrity: sha512-+dGZ1X2KqtwXaabVjTGxy0a3VzYfvYsWaRcuO8vMhyclHSOpGSI1+5cmlqzzCwQ3+fv0EjkTc7I5aV9lo08dYw==}
- peerDependencies:
- jest: ^29.3.1
- jest-circus: ^29.3.1
- jest-environment-node: ^29.3.1
- jest-runner: ^29.3.1
-
- jest-pnp-resolver@1.2.3:
- resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==}
- engines: {node: '>=6'}
- peerDependencies:
- jest-resolve: '*'
- peerDependenciesMeta:
- jest-resolve:
- optional: true
-
- jest-process-manager@0.4.0:
- resolution: {integrity: sha512-80Y6snDyb0p8GG83pDxGI/kQzwVTkCxc7ep5FPe/F6JYdvRDhwr6RzRmPSP7SEwuLhxo80lBS/NqOdUIbHIfhw==}
-
- jest-regex-util@29.6.3:
- resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-resolve-dependencies@29.7.0:
- resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-resolve@29.7.0:
- resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-runner@29.7.0:
- resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-runtime@29.7.0:
- resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-serializer-html@7.1.0:
- resolution: {integrity: sha512-xYL2qC7kmoYHJo8MYqJkzrl/Fdlx+fat4U1AqYg+kafqwcKPiMkOcjWHPKhueuNEgr+uemhGc+jqXYiwCyRyLA==}
-
- jest-snapshot@29.7.0:
- resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-util@29.7.0:
- resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-validate@29.7.0:
- resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-watch-typeahead@2.2.2:
- resolution: {integrity: sha512-+QgOFW4o5Xlgd6jGS5X37i08tuuXNW8X0CV9WNFi+3n8ExCIP+E1melYhvYLjv5fE6D0yyzk74vsSO8I6GqtvQ==}
- engines: {node: ^14.17.0 || ^16.10.0 || >=18.0.0}
- peerDependencies:
- jest: ^27.0.0 || ^28.0.0 || ^29.0.0
-
- jest-watcher@29.7.0:
- resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
jest-worker@27.5.1:
resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==}
engines: {node: '>= 10.13.0'}
- jest-worker@29.7.0:
- resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest@29.7.0:
- resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- hasBin: true
- peerDependencies:
- node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
- peerDependenciesMeta:
- node-notifier:
- optional: true
-
jiti@1.21.7:
resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==}
hasBin: true
- joi@17.13.3:
- resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==}
-
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
- js-yaml@3.14.1:
- resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
- hasBin: true
-
js-yaml@4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
- jsdoc-type-pratt-parser@4.1.0:
- resolution: {integrity: sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==}
- engines: {node: '>=12.0.0'}
+ 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==}
@@ -5594,12 +4896,24 @@ packages:
engines: {node: '>=6'}
hasBin: true
- jsonc-parser@3.3.1:
- resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==}
+ jsonc-parser@2.2.1:
+ resolution: {integrity: sha512-o6/yDBYccGvTz1+QFevz6l6OBZ2+fMVu2JZ9CIhzsYRX4mjaK5IyX9eldUdCmga16zlgQxyrj5pt9kzuj2C02w==}
jsonfile@6.1.0:
resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
+ jsonpath-plus@10.3.0:
+ resolution: {integrity: sha512-8TNmfeTCk2Le33A3vRRwtuworG/L5RrgMvdjhKZxvyShO+mBu2fP50OWUjRLNtvw344DdDarFh9buFAZs5ujeA==}
+ engines: {node: '>=18.0.0'}
+ hasBin: true
+
+ jsonpointer@5.0.1:
+ resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==}
+ engines: {node: '>=0.10.0'}
+
+ jsonschema@1.5.0:
+ resolution: {integrity: sha512-K+A9hhqbn0f3pJX17Q/7H6yQfD/5OXgdrR5UE12gMXCiN9D5Xq2o5mddV2QEcX/bjla99ASsAAQUyMCCRWAEhw==}
+
jsx-ast-utils@3.3.5:
resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==}
engines: {node: '>=4.0'}
@@ -5611,10 +4925,6 @@ packages:
keyv@4.5.4:
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
- kleur@3.0.3:
- resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
- engines: {node: '>=6'}
-
language-subtag-registry@0.3.23:
resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==}
@@ -5649,6 +4959,9 @@ packages:
lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
+ linkify-it@5.0.0:
+ resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==}
+
loader-runner@4.3.0:
resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==}
engines: {node: '>=6.11.5'}
@@ -5679,15 +4992,33 @@ packages:
lodash.debounce@4.0.8:
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
- lodash.flattendeep@4.4.0:
- resolution: {integrity: sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==}
+ lodash.isempty@4.4.0:
+ resolution: {integrity: sha512-oKMuF3xEeqDltrGMfDxAPGIVMSSRv8tbRSODbrs4KGsRRLEhrW8N8Rd4DRgB2+621hY8A8XwwrTVhXWpxFvMzg==}
lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+ lodash.omitby@4.6.0:
+ resolution: {integrity: sha512-5OrRcIVR75M288p4nbI2WLAf3ndw2GD9fyNv3Bc15+WCxJDdZ4lYndSxGd7hnG6PVjiJTeJE2dHEGhIuKGicIQ==}
+
+ lodash.topath@4.5.2:
+ resolution: {integrity: sha512-1/W4dM+35DwvE/iEd1M9ekewOSTlpFekhw9mhAtrwjVqUr83/ilQiyAvmg4tVX7Unkcfl1KC+i9WdaT4B6aQcg==}
+
+ lodash.uniq@4.5.0:
+ resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==}
+
+ lodash.uniqby@4.7.0:
+ resolution: {integrity: sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==}
+
+ lodash.uniqwith@4.5.0:
+ resolution: {integrity: sha512-7lYL8bLopMoy4CTICbxygAUq6CdRJ36vFc80DucPueUee+d5NBRxz3FdT9Pes/HEx5mPoT9jwnsEJWz1N7uq7Q==}
+
lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
+ loglevel-plugin-prefix@0.8.4:
+ resolution: {integrity: sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==}
+
loglevel@1.9.2:
resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==}
engines: {node: '>= 0.6.0'}
@@ -5699,8 +5030,8 @@ packages:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
- loupe@3.1.3:
- resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==}
+ loupe@3.1.4:
+ resolution: {integrity: sha512-wJzkKwJrheKtknCOKNEtDK4iqg/MxmZheEMtSTYvnzRdEYaZzmgH976nenp8WdJRdx5Vc1X/9MO0Oszl6ezeXg==}
lower-case@2.0.2:
resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==}
@@ -5716,6 +5047,9 @@ packages:
peerDependencies:
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
+ lunr@2.3.9:
+ resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==}
+
lz-string@1.5.0:
resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==}
hasBin: true
@@ -5731,15 +5065,9 @@ packages:
resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
engines: {node: '>=8'}
- make-dir@4.0.0:
- resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
- engines: {node: '>=10'}
-
- makeerror@1.0.12:
- resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==}
-
- map-or-similar@1.5.0:
- resolution: {integrity: sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==}
+ markdown-it@14.1.0:
+ resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==}
+ hasBin: true
math-intrinsics@1.1.0:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
@@ -5772,13 +5100,13 @@ packages:
mdast-util-to-string@4.0.0:
resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==}
+ mdurl@2.0.0:
+ resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==}
+
memfs@3.5.3:
resolution: {integrity: sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==}
engines: {node: '>= 4.0.0'}
- memoizerific@1.11.3:
- resolution: {integrity: sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==}
-
merge-stream@2.0.0:
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
@@ -5882,6 +5210,10 @@ packages:
minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
+ minimatch@6.2.0:
+ 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'}
@@ -5901,22 +5233,17 @@ packages:
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
engines: {node: '>=16 || 14 >=14.17'}
- mkdirp@1.0.4:
- resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
- engines: {node: '>=10'}
- hasBin: true
-
module-details-from-path@1.0.4:
resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==}
moment@2.30.1:
resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==}
- motion-dom@12.16.0:
- resolution: {integrity: sha512-Z2nGwWrrdH4egLEtgYMCEN4V2qQt1qxlKy/uV7w691ztyA41Q5Rbn0KNGbsNVDZr9E8PD2IOQ3hSccRnB6xWzw==}
+ motion-dom@12.18.1:
+ resolution: {integrity: sha512-dR/4EYT23Snd+eUSLrde63Ws3oXQtJNw/krgautvTfwrN/2cHfCZMdu6CeTxVfRRWREW3Fy1f5vobRDiBb/q+w==}
- motion-utils@12.12.1:
- resolution: {integrity: sha512-f9qiqUHm7hWSLlNW8gS9pisnsN7CRFRD58vNjptKdsqFLpkVnX00TNeD6Q0d27V9KzT7ySFyK1TZ/DShfVOv6w==}
+ motion-utils@12.18.1:
+ resolution: {integrity: sha512-az26YDU4WoDP0ueAkUtABLk2BIxe28d8NH1qWT8jPGhPyf44XTdDUh8pDk9OPphaSrR9McgpcJlgwSOIw/sfkA==}
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
@@ -5990,12 +5317,20 @@ packages:
sass:
optional: true
+ nimma@0.2.3:
+ resolution: {integrity: sha512-1ZOI8J+1PKKGceo/5CT5GfQOG6H8I2BencSK06YarZ2wXwH37BSSUWldqJmMJYA5JfqDqffxDXynt6f11AyKcA==}
+ engines: {node: ^12.20 || >=14.13}
+
no-case@3.0.4:
resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==}
node-abort-controller@3.1.1:
resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==}
+ node-fetch-h2@2.3.0:
+ resolution: {integrity: sha512-ofRW94Ab0T4AOh5Fk8t0h8OBWrmjb0SSB20xh1H8YnPV9EJ+f5AMoYSUQ2zgJ4Iq2HAK0I2l5/Nequ8YzFS3Hg==}
+ engines: {node: 4.x || >=6.0.0}
+
node-fetch@2.7.0:
resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
engines: {node: 4.x || >=6.0.0}
@@ -6005,18 +5340,14 @@ packages:
encoding:
optional: true
- node-int64@0.4.0:
- resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==}
-
node-polyfill-webpack-plugin@2.0.1:
resolution: {integrity: sha512-ZUMiCnZkP1LF0Th2caY6J/eKKoA0TefpoVa68m/LQU1I/mE8rGt4fNYGgNuCcK+aG8P8P43nbeJ2RqJMOL/Y1A==}
engines: {node: '>=12'}
peerDependencies:
webpack: '>=5'
- node-preload@0.2.1:
- resolution: {integrity: sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==}
- engines: {node: '>=8'}
+ node-readfiles@0.2.0:
+ resolution: {integrity: sha512-SU00ZarexNlE4Rjdm83vglt5Y9yiQ+XI1XpflWlb7q7UTN1JUItm69xMeiQCTxtTfnzt+83T8Cx+vI2ED++VDA==}
node-releases@2.0.19:
resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==}
@@ -6032,11 +5363,22 @@ packages:
nth-check@2.1.1:
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
- nyc@15.1.0:
- resolution: {integrity: sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==}
- engines: {node: '>=8.9'}
+ oas-kit-common@1.0.8:
+ resolution: {integrity: sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ==}
+
+ oas-linter@3.2.2:
+ resolution: {integrity: sha512-KEGjPDVoU5K6swgo9hJVA/qYGlwfbFx+Kg2QB/kd7rzV5N8N5Mg6PlsoCMohVnQmo+pzJap/F610qTodKzecGQ==}
+
+ oas-resolver@2.5.6:
+ resolution: {integrity: sha512-Yx5PWQNZomfEhPPOphFbZKi9W93CocQj18NlD2Pa4GWZzdZpSJvYwoiuurRI7m3SpcChrnO08hkuQDL3FGsVFQ==}
hasBin: true
+ oas-schema-walker@1.1.5:
+ resolution: {integrity: sha512-2yucenq1a9YPmeNExoUa9Qwrt9RFkjqaMAA1X+U7sbb0AqBeTIdMHky9SQQ6iN94bO5NW0W4TRYXerG+BdAvAQ==}
+
+ oas-validator@5.0.8:
+ resolution: {integrity: sha512-cu20/HE5N5HKqVygs3dt94eYJfBi0TsZvPVXDhbXQHiEityDN+RROTleefoKRKKJ9dFAF2JBkDHgvWj0sjKGmw==}
+
object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
@@ -6091,17 +5433,26 @@ packages:
resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==}
engines: {node: '>=12'}
+ openapi-types@12.1.3:
+ resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==}
+
+ openapi3-ts@4.2.2:
+ resolution: {integrity: sha512-+9g4actZKeb3czfi9gVQ4Br2Ju3KwhCAQJBNaKgye5KggqcBLIhFHH+nIkcm0BUX00TrAJl6dH4JWgM4G4JWrw==}
+
+ openapi3-ts@4.4.0:
+ resolution: {integrity: sha512-9asTNB9IkKEzWMcHmVZE7Ts3kC9G7AFHfs8i7caD8HbI76gEjdkId4z/AkP83xdZsH7PLAnnbl47qZkXuxpArw==}
+
optionator@0.9.4:
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
engines: {node: '>= 0.8.0'}
+ orval@7.10.0:
+ resolution: {integrity: sha512-R1TlDDgK82dHfTXG0IuaIXHOrk6HQ1CuGejQQpQW9mBSCQA84AInp8U4Ovxw3upjMFNhghE8OlAQqD0ES8GgHQ==}
+ hasBin: true
+
os-browserify@0.3.0:
resolution: {integrity: sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==}
- os-homedir@1.0.2:
- resolution: {integrity: sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==}
- engines: {node: '>=0.10.0'}
-
outvariant@1.4.3:
resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==}
@@ -6133,18 +5484,10 @@ packages:
resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
- p-map@3.0.0:
- resolution: {integrity: sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==}
- engines: {node: '>=8'}
-
p-try@2.2.0:
resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
engines: {node: '>=6'}
- package-hash@4.0.0:
- resolution: {integrity: sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==}
- engines: {node: '>=8'}
-
package-json-from-dist@1.0.1:
resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
@@ -6169,10 +5512,6 @@ packages:
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
engines: {node: '>=8'}
- parse-passwd@1.0.0:
- resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==}
- engines: {node: '>=0.10.0'}
-
party-js@2.2.0:
resolution: {integrity: sha512-50hGuALCpvDTrQLPQ1fgUgxKIWAH28ShVkmeK/3zhO0YJyCqkhrZhQEkWPxDYLvbFJ7YAXyROmFEu35gKpZLtQ==}
@@ -6258,23 +5597,19 @@ packages:
resolution: {integrity: sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==}
engines: {node: '>=14.16'}
- playwright-core@1.52.0:
- resolution: {integrity: sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==}
+ playwright-core@1.53.1:
+ resolution: {integrity: sha512-Z46Oq7tLAyT0lGoFx4DOuB1IA9D1TPj0QkYxpPVUnGDqHHvDpCftu1J2hM2PiWsNMoZh8+LQaarAWcDfPBc6zg==}
engines: {node: '>=18'}
hasBin: true
- playwright@1.52.0:
- resolution: {integrity: sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==}
+ playwright@1.53.1:
+ resolution: {integrity: sha512-LJ13YLr/ocweuwxyGf1XNFWIU4M2zUSo149Qbp+A4cpwDjsxRPj7k6H25LBrEHiEwxvRbD8HdwvQmRMSvquhYw==}
engines: {node: '>=18'}
hasBin: true
- pnp-webpack-plugin@1.7.0:
- resolution: {integrity: sha512-2Rb3vm+EXble/sMXNSu6eoBx8e79gKqhNq9F5ZWW6ERNCTE/Q0wQNne5541tE5vKjfM8hpNCYL+LGc1YTfI0dg==}
- engines: {node: '>=6'}
-
- polished@4.3.1:
- resolution: {integrity: sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==}
- engines: {node: '>=10'}
+ pony-cause@1.1.1:
+ resolution: {integrity: sha512-PxkIc/2ZpLiEzQXu5YRDOUgBlfGYBY8156HY5ZcRAwwonMk5W/MrJP2LLkG/hF7GEQzaHo2aS7ho6ZLCOvf+6g==}
+ engines: {node: '>=12.0.0'}
possible-typed-array-names@1.1.0:
resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
@@ -6366,8 +5701,8 @@ packages:
resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==}
engines: {node: ^10 || ^12 || >=14}
- postcss@8.5.4:
- resolution: {integrity: sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==}
+ postcss@8.5.6:
+ resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
engines: {node: ^10 || ^12 || >=14}
postgres-array@2.0.0:
@@ -6457,17 +5792,9 @@ packages:
resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==}
engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
- pretty-format@29.7.0:
- resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
process-nextick-args@2.0.1:
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
- process-on-spawn@1.1.0:
- resolution: {integrity: sha512-JOnOPQ/8TZgjs1JIH/m9ni7FfimjNa/PRx7y/Wb5qdItsnhO0jE4AT7fC0HjC28DUQWDr50dwSYZLdRMlqDq3Q==}
- engines: {node: '>=8'}
-
process@0.11.10:
resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==}
engines: {node: '>= 0.6.0'}
@@ -6476,10 +5803,6 @@ packages:
resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==}
engines: {node: '>=0.4.0'}
- prompts@2.4.2:
- resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
- engines: {node: '>= 6'}
-
prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
@@ -6495,6 +5818,10 @@ packages:
public-encrypt@4.0.3:
resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==}
+ punycode.js@2.3.1:
+ resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
+ engines: {node: '>=6'}
+
punycode@1.4.1:
resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==}
@@ -6502,9 +5829,6 @@ packages:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
- pure-rand@6.1.0:
- resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==}
-
qs@6.14.0:
resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==}
engines: {node: '>=0.6'}
@@ -6519,9 +5843,6 @@ packages:
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
- queue@6.0.2:
- resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==}
-
randombytes@2.1.0:
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
@@ -6532,20 +5853,14 @@ packages:
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
engines: {node: '>= 0.6'}
- react-confetti@6.4.0:
- resolution: {integrity: sha512-5MdGUcqxrTU26I2EU7ltkWPwxvucQTuqMm8dUz72z2YMqTD6s9vMcDUysk7n9jnC+lXuCPeJJ7Knf98VEYE9Rg==}
- engines: {node: '>=16'}
- peerDependencies:
- react: ^16.3.0 || ^17.0.1 || ^18.0.0 || ^19.0.0
-
react-day-picker@9.7.0:
resolution: {integrity: sha512-urlK4C9XJZVpQ81tmVgd2O7lZ0VQldZeHzNejbwLWZSkzHH498KnArT0EHNfKBOWwKc935iMLGZdxXPRISzUxQ==}
engines: {node: '>=18'}
peerDependencies:
react: '>=16.8.0'
- react-docgen-typescript@2.2.2:
- resolution: {integrity: sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg==}
+ react-docgen-typescript@2.4.0:
+ resolution: {integrity: sha512-ZtAp5XTO5HRzQctjPU0ybY0RRCQO19X/8fxn3w7y2VVTUbGHDKULPTL4ky3vB05euSgG5NpALhEhDPvQ56wvXg==}
peerDependencies:
typescript: '>= 4.3.x'
@@ -6674,6 +5989,10 @@ packages:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
+ readdirp@4.1.2:
+ resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
+ engines: {node: '>= 14.18.0'}
+
recast@0.23.11:
resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==}
engines: {node: '>= 4'}
@@ -6696,6 +6015,9 @@ packages:
resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==}
engines: {node: '>= 0.4'}
+ reftools@1.1.9:
+ resolution: {integrity: sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w==}
+
regenerate-unicode-properties@10.2.0:
resolution: {integrity: sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==}
engines: {node: '>=4'}
@@ -6725,10 +6047,6 @@ packages:
resolution: {integrity: sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==}
engines: {node: '>= 0.10'}
- release-zalgo@1.0.0:
- resolution: {integrity: sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==}
- engines: {node: '>=4'}
-
remark-parse@11.0.0:
resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==}
@@ -6750,28 +6068,13 @@ packages:
resolution: {integrity: sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ==}
engines: {node: '>=8.6.0'}
- require-main-filename@2.0.0:
- resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
-
requires-port@1.0.0:
resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
- resolve-cwd@3.0.0:
- resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==}
- engines: {node: '>=8'}
-
- resolve-dir@0.1.1:
- resolution: {integrity: sha512-QxMPqI6le2u0dCLyiGzgy92kjkkL6zO0XyvHzjdTNH3zM6e5Hz3BwG6+aEyNgiQ5Xz6PwTwgQEj3U50dByPKIA==}
- engines: {node: '>=0.10.0'}
-
resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
- resolve-from@5.0.0:
- resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
- engines: {node: '>=8'}
-
resolve-pkg-maps@1.0.0:
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
@@ -6779,10 +6082,6 @@ packages:
resolution: {integrity: sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==}
engines: {node: '>=12'}
- resolve.exports@2.0.3:
- resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==}
- engines: {node: '>=10'}
-
resolve@1.22.10:
resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==}
engines: {node: '>= 0.4'}
@@ -6837,6 +6136,9 @@ packages:
resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==}
engines: {node: '>= 0.4'}
+ safe-stable-stringify@1.1.1:
+ resolution: {integrity: sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw==}
+
sass-loader@14.2.1:
resolution: {integrity: sha512-G0VcnMYU18a4N7VoNDegg2OuMjYtxnqzQWARVWCIVSZwJeiL9kg8QMsuIZOplsJgTzZLF6jGxI3AClj8I9nRdQ==}
engines: {node: '>= 18.12.0'}
@@ -6881,9 +6183,6 @@ packages:
serialize-javascript@6.0.2:
resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==}
- set-blocking@2.0.0:
- resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
-
set-function-length@1.2.2:
resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
engines: {node: '>= 0.4'}
@@ -6906,10 +6205,6 @@ packages:
shallowequal@1.1.0:
resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==}
- sharp@0.33.5:
- resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-
sharp@0.34.2:
resolution: {integrity: sha512-lszvBmB9QURERtyKT2bNmsgxXK0ShJrL/fvqlonCo7e6xBF8nT8xU6pW+PMIbLsz0RxQk3rgH9kd8UmvOzlMJg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
@@ -6933,6 +6228,24 @@ packages:
shimmer@1.2.1:
resolution: {integrity: sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==}
+ should-equal@2.0.0:
+ resolution: {integrity: sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==}
+
+ should-format@3.0.3:
+ resolution: {integrity: sha512-hZ58adtulAk0gKtua7QxevgUaXTTXxIi8t41L3zo9AHvjXO1/7sdLECuHeIN2SRtYXpNkmhoUP2pdeWgricQ+Q==}
+
+ should-type-adaptors@1.1.0:
+ resolution: {integrity: sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==}
+
+ should-type@1.4.0:
+ resolution: {integrity: sha512-MdAsTu3n25yDbIe1NeN69G4n6mUnJGtSJHygX3+oN0ZbO3DTiATnf7XnYJdGT42JCXurTb1JI0qOBR65shvhPQ==}
+
+ should-util@1.0.1:
+ resolution: {integrity: sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==}
+
+ should@13.2.3:
+ resolution: {integrity: sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==}
+
side-channel-list@1.0.0:
resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
engines: {node: '>= 0.4'}
@@ -6956,27 +6269,21 @@ packages:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
+ simple-eval@1.0.1:
+ 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==}
- sisteransi@1.0.5:
- resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
-
slash@3.0.0:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'}
- slash@5.1.0:
- resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==}
- engines: {node: '>=14.16'}
-
source-map-js@1.2.1:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
- source-map-support@0.5.13:
- resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==}
-
source-map-support@0.5.21:
resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
@@ -6991,23 +6298,9 @@ packages:
space-separated-tokens@2.0.2:
resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
- spawn-wrap@2.0.0:
- resolution: {integrity: sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==}
- engines: {node: '>=8'}
-
- spawnd@5.0.0:
- resolution: {integrity: sha512-28+AJr82moMVWolQvlAIv3JcYDkjkFTEmfDc503wxrF5l2rQ3dFz6DpbXp3kD4zmgGGldfM4xM4v1sFj/ZaIOA==}
-
- sprintf-js@1.0.3:
- resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
-
stable-hash@0.0.5:
resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==}
- stack-utils@2.0.6:
- resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
- engines: {node: '>=10'}
-
stackframe@1.3.4:
resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==}
@@ -7023,8 +6316,8 @@ packages:
resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==}
engines: {node: '>= 0.4'}
- storybook@8.6.14:
- resolution: {integrity: sha512-sVKbCj/OTx67jhmauhxc2dcr1P+yOgz/x3h0krwjyMgdc5Oubvxyg4NYDZmzAw+ym36g/lzH8N0Ccp4dwtdfxw==}
+ storybook@9.0.12:
+ resolution: {integrity: sha512-mpACe6BMd/M5sqcOiA8NmWIm2zdx0t4ujnA4NTcq4aErdK/KKuU255UM4pO3DIf5zWR5VrDfNV5UaMi/VgE2mA==}
hasBin: true
peerDependencies:
prettier: ^2 || ^3
@@ -7045,13 +6338,9 @@ packages:
strict-event-emitter@0.5.1:
resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==}
- string-length@4.0.2:
- resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==}
- engines: {node: '>=10'}
-
- string-length@5.0.1:
- resolution: {integrity: sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow==}
- engines: {node: '>=12.20'}
+ string-argv@0.3.2:
+ resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==}
+ engines: {node: '>=0.6.19'}
string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
@@ -7105,10 +6394,6 @@ packages:
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
engines: {node: '>=4'}
- strip-bom@4.0.0:
- resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==}
- engines: {node: '>=8'}
-
strip-final-newline@2.0.0:
resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
engines: {node: '>=6'}
@@ -7131,14 +6416,14 @@ packages:
peerDependencies:
webpack: ^5.0.0
- style-to-js@1.1.16:
- resolution: {integrity: sha512-/Q6ld50hKYPH3d/r6nr117TZkHR0w0kGGIVfpG9N6D8NymRPM9RqCUv4pRpJ62E5DqOYx2AFpbZMyCPnjQCnOw==}
+ style-to-js@1.1.17:
+ resolution: {integrity: sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA==}
- style-to-object@1.0.8:
- resolution: {integrity: sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==}
+ style-to-object@1.0.9:
+ resolution: {integrity: sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw==}
- styled-components@6.1.18:
- resolution: {integrity: sha512-Mvf3gJFzZCkhjY2Y/Fx9z1m3dxbza0uI9H1CbNZm/jSHCojzJhQ0R7bByrlFJINnMzz/gPulpoFFGymNwrsMcw==}
+ styled-components@6.1.19:
+ resolution: {integrity: sha512-1v/e3Dl1BknC37cXMhwGomhO8AkYmN41CqyX9xhUDxry1ns3BFQy2lLDRQXJRdVVWB9OHemv/53xaStimvWyuA==}
engines: {node: '>= 16'}
peerDependencies:
react: '>= 16.8.0'
@@ -7178,10 +6463,6 @@ packages:
engines: {node: '>=16 || 14 >=14.17'}
hasBin: true
- supports-color@5.5.0:
- resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
- engines: {node: '>=4'}
-
supports-color@7.2.0:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'}
@@ -7194,6 +6475,10 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
+ swagger2openapi@7.0.8:
+ resolution: {integrity: sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g==}
+ hasBin: true
+
tailwind-merge@2.6.0:
resolution: {integrity: sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==}
@@ -7227,15 +6512,11 @@ packages:
uglify-js:
optional: true
- terser@5.41.0:
- resolution: {integrity: sha512-H406eLPXpZbAX14+B8psIuvIr8+3c+2hkuYzpMkoE0ij+NdsVATbA78vb8neA/eqrj7rywa2pIkdmWRsXW6wmw==}
+ terser@5.42.0:
+ resolution: {integrity: sha512-UYCvU9YQW2f/Vwl+P0GfhxJxbUGLwd+5QrrGgLajzWAtC/23AX0vcise32kkP7Eu0Wu9VlzzHAXkLObgjQfFlQ==}
engines: {node: '>=10'}
hasBin: true
- test-exclude@6.0.0:
- resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
- engines: {node: '>=8'}
-
text-table@0.2.0:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
@@ -7260,17 +6541,14 @@ packages:
resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==}
engines: {node: '>=12.0.0'}
- tinyrainbow@1.2.0:
- resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==}
+ tinyrainbow@2.0.0:
+ resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==}
engines: {node: '>=14.0.0'}
tinyspy@3.0.2:
resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==}
engines: {node: '>=14.0.0'}
- tmpl@1.0.5:
- resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==}
-
to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
@@ -7305,11 +6583,12 @@ packages:
ts-interface-checker@0.1.13:
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
- ts-pnp@1.2.0:
- resolution: {integrity: sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==}
- engines: {node: '>=6'}
+ tsconfck@2.1.2:
+ resolution: {integrity: sha512-ghqN1b0puy3MhhviwO2kGF8SeMDNhEbnKxjK7h6+fvY9JAxqvXi8y5NAHSQv687OVboS2uZIByzGd45/YxrRHg==}
+ engines: {node: ^14.13.1 || ^16 || >=18}
+ hasBin: true
peerDependencies:
- typescript: '*'
+ typescript: ^4.3.5 || ^5.0.0
peerDependenciesMeta:
typescript:
optional: true
@@ -7325,6 +6604,9 @@ packages:
resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==}
engines: {node: '>=6'}
+ tslib@1.14.1:
+ resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
+
tslib@2.6.2:
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
@@ -7334,17 +6616,10 @@ packages:
tty-browserify@0.0.1:
resolution: {integrity: sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==}
- tween-functions@1.2.0:
- resolution: {integrity: sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA==}
-
type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
- type-detect@4.0.8:
- resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
- engines: {node: '>=4'}
-
type-fest@0.20.2:
resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
engines: {node: '>=10'}
@@ -7357,10 +6632,6 @@ packages:
resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==}
engines: {node: '>=8'}
- type-fest@0.8.1:
- resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==}
- engines: {node: '>=8'}
-
type-fest@2.19.0:
resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==}
engines: {node: '>=12.20'}
@@ -7385,14 +6656,27 @@ packages:
resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==}
engines: {node: '>= 0.4'}
- typedarray-to-buffer@3.1.5:
- resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==}
+ typedoc-plugin-markdown@4.6.4:
+ resolution: {integrity: sha512-AnbToFS1T1H+n40QbO2+i0wE6L+55rWnj7zxnM1r781+2gmhMF2dB6dzFpaylWLQYkbg4D1Y13sYnne/6qZwdw==}
+ engines: {node: '>= 18'}
+ peerDependencies:
+ typedoc: 0.28.x
+
+ typedoc@0.28.5:
+ resolution: {integrity: sha512-5PzUddaA9FbaarUzIsEc4wNXCiO4Ot3bJNeMF2qKpYlTmM9TTaSHQ7162w756ERCkXER/+o2purRG6YOAv6EMA==}
+ engines: {node: '>= 18', pnpm: '>= 10'}
+ hasBin: true
+ peerDependencies:
+ typescript: 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x
typescript@5.8.3:
resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==}
engines: {node: '>=14.17'}
hasBin: true
+ uc.micro@2.1.0:
+ resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==}
+
unbox-primitive@1.1.0:
resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
engines: {node: '>= 0.4'}
@@ -7416,6 +6700,10 @@ packages:
resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==}
engines: {node: '>=4'}
+ unicorn-magic@0.1.0:
+ resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==}
+ engines: {node: '>=18'}
+
unified@11.0.5:
resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==}
@@ -7449,8 +6737,8 @@ packages:
resolution: {integrity: sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==}
engines: {node: '>=14.0.0'}
- unrs-resolver@1.7.10:
- resolution: {integrity: sha512-CJEMJcz6vuwRK6xxWc+uf8AGi0OyfoVtHs5mExtNecS0HZq3a3Br1JC/InwwTn6uy+qkAdAdK+nJUYO9FPtgZw==}
+ unrs-resolver@1.9.0:
+ resolution: {integrity: sha512-wqaRu4UnzBD2ABTC1kLfBjAqIDZ5YUTr/MLGa7By47JV1bJDSW7jq/ZSLigB7enLe7ubNaJhtnBXgrc/50cEhg==}
update-browserslist-db@1.1.3:
resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==}
@@ -7461,6 +6749,9 @@ packages:
uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+ urijs@1.19.11:
+ resolution: {integrity: sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==}
+
url-parse@1.5.10:
resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
@@ -7502,6 +6793,10 @@ packages:
utila@0.4.0:
resolution: {integrity: sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==}
+ utility-types@3.11.0:
+ resolution: {integrity: sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==}
+ engines: {node: '>= 4'}
+
uuid@11.1.0:
resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==}
hasBin: true
@@ -7514,9 +6809,9 @@ packages:
resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
hasBin: true
- v8-to-istanbul@9.3.0:
- resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==}
- engines: {node: '>=10.12.0'}
+ validator@13.15.15:
+ resolution: {integrity: sha512-BgWVbCI72aIQy937xbawcs+hrVaN/CZ2UwutgaJ36hGqRrLNM+f5LUT/YPRbo8IV/ASeFzXszezV+y2+rq3l8A==}
+ engines: {node: '>= 0.10'}
vfile-message@4.0.2:
resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==}
@@ -7530,19 +6825,6 @@ packages:
vm-browserify@1.1.2:
resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==}
- wait-on@7.2.0:
- resolution: {integrity: sha512-wCQcHkRazgjG5XoAq9jbTMLpNIjoSlZslrJ2+N9MxDsGEv1HnFoVjOCexL0ESva7Y9cu350j+DWADdk54s4AFQ==}
- engines: {node: '>=12.0.0'}
- hasBin: true
-
- wait-port@0.2.14:
- resolution: {integrity: sha512-kIzjWcr6ykl7WFbZd0TMae8xovwqcqbx6FM9l+7agOgUByhzdjfzZBPK2CPufldTOMxbUivss//Sh9MFawmPRQ==}
- engines: {node: '>=8'}
- hasBin: true
-
- walker@1.0.8:
- resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}
-
warning@4.0.3:
resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==}
@@ -7600,17 +6882,10 @@ packages:
resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==}
engines: {node: '>= 0.4'}
- which-module@2.0.1:
- resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==}
-
which-typed-array@1.1.19:
resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==}
engines: {node: '>= 0.4'}
- which@1.3.1:
- resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}
- hasBin: true
-
which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
@@ -7635,13 +6910,6 @@ packages:
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
- write-file-atomic@3.0.3:
- resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==}
-
- write-file-atomic@4.0.2:
- resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==}
- engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
-
ws@8.18.2:
resolution: {integrity: sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==}
engines: {node: '>=10.0.0'}
@@ -7654,9 +6922,6 @@ packages:
utf-8-validate:
optional: true
- xml@1.0.1:
- resolution: {integrity: sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==}
-
xmlbuilder@15.1.1:
resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==}
engines: {node: '>=8.0'}
@@ -7665,9 +6930,6 @@ packages:
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
engines: {node: '>=0.4'}
- y18n@4.0.3:
- resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
-
y18n@5.0.8:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'}
@@ -7684,18 +6946,10 @@ packages:
engines: {node: '>= 14.6'}
hasBin: true
- yargs-parser@18.1.3:
- resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==}
- engines: {node: '>=6'}
-
yargs-parser@21.1.1:
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
engines: {node: '>=12'}
- yargs@15.4.1:
- resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==}
- engines: {node: '>=8'}
-
yargs@17.7.2:
resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
engines: {node: '>=12'}
@@ -7744,6 +6998,31 @@ snapshots:
'@jridgewell/gen-mapping': 0.3.8
'@jridgewell/trace-mapping': 0.3.25
+ '@apidevtools/json-schema-ref-parser@11.7.2':
+ dependencies:
+ '@jsdevtools/ono': 7.1.3
+ '@types/json-schema': 7.0.15
+ js-yaml: 4.1.0
+
+ '@apidevtools/openapi-schemas@2.1.0': {}
+
+ '@apidevtools/swagger-methods@3.0.2': {}
+
+ '@apidevtools/swagger-parser@10.1.1(openapi-types@12.1.3)':
+ dependencies:
+ '@apidevtools/json-schema-ref-parser': 11.7.2
+ '@apidevtools/openapi-schemas': 2.1.0
+ '@apidevtools/swagger-methods': 3.0.2
+ '@jsdevtools/ono': 7.1.3
+ ajv: 8.17.1
+ ajv-draft-04: 1.0.0(ajv@8.17.1)
+ call-me-maybe: 1.0.2
+ openapi-types: 12.1.3
+
+ '@asyncapi/specs@6.8.1':
+ dependencies:
+ '@types/json-schema': 7.0.15
+
'@babel/code-frame@7.27.1':
dependencies:
'@babel/helper-validator-identifier': 7.27.1
@@ -7939,26 +7218,11 @@ snapshots:
dependencies:
'@babel/core': 7.27.4
- '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.27.4)':
- dependencies:
- '@babel/core': 7.27.4
- '@babel/helper-plugin-utils': 7.27.1
-
'@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.27.4)':
dependencies:
'@babel/core': 7.27.4
'@babel/helper-plugin-utils': 7.27.1
- '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.27.4)':
- dependencies:
- '@babel/core': 7.27.4
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.27.4)':
- dependencies:
- '@babel/core': 7.27.4
- '@babel/helper-plugin-utils': 7.27.1
-
'@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.27.4)':
dependencies:
'@babel/core': 7.27.4
@@ -7974,61 +7238,11 @@ snapshots:
'@babel/core': 7.27.4
'@babel/helper-plugin-utils': 7.27.1
- '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.27.4)':
- dependencies:
- '@babel/core': 7.27.4
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.27.4)':
- dependencies:
- '@babel/core': 7.27.4
- '@babel/helper-plugin-utils': 7.27.1
-
'@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.27.4)':
dependencies:
'@babel/core': 7.27.4
'@babel/helper-plugin-utils': 7.27.1
- '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.27.4)':
- dependencies:
- '@babel/core': 7.27.4
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.27.4)':
- dependencies:
- '@babel/core': 7.27.4
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.27.4)':
- dependencies:
- '@babel/core': 7.27.4
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.27.4)':
- dependencies:
- '@babel/core': 7.27.4
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.27.4)':
- dependencies:
- '@babel/core': 7.27.4
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.27.4)':
- dependencies:
- '@babel/core': 7.27.4
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.27.4)':
- dependencies:
- '@babel/core': 7.27.4
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.27.4)':
- dependencies:
- '@babel/core': 7.27.4
- '@babel/helper-plugin-utils': 7.27.1
-
'@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.27.4)':
dependencies:
'@babel/core': 7.27.4
@@ -8481,7 +7695,7 @@ snapshots:
babel-plugin-polyfill-corejs2: 0.4.13(@babel/core@7.27.4)
babel-plugin-polyfill-corejs3: 0.11.1(@babel/core@7.27.4)
babel-plugin-polyfill-regenerator: 0.6.4(@babel/core@7.27.4)
- core-js-compat: 3.42.0
+ core-js-compat: 3.43.0
semver: 6.3.1
transitivePeerDependencies:
- supports-color
@@ -8541,8 +7755,6 @@ snapshots:
'@babel/helper-string-parser': 7.27.1
'@babel/helper-validator-identifier': 7.27.1
- '@bcoe/v8-coverage@0.2.3': {}
-
'@bundled-es-modules/cookie@2.0.1':
dependencies:
cookie: 0.7.2
@@ -8556,18 +7768,17 @@ snapshots:
'@types/tough-cookie': 4.0.5
tough-cookie: 4.1.4
- '@chromatic-com/storybook@3.2.6(react@18.3.1)(storybook@8.6.14(prettier@3.5.3))':
+ '@chromatic-com/storybook@4.0.0(storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))':
dependencies:
- chromatic: 11.25.2
+ '@neoconfetti/react': 1.0.0
+ chromatic: 12.2.0
filesize: 10.1.6
jsonfile: 6.1.0
- react-confetti: 6.4.0(react@18.3.1)
- storybook: 8.6.14(prettier@3.5.3)
+ storybook: 9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3)
strip-ansi: 7.1.0
transitivePeerDependencies:
- '@chromatic-com/cypress'
- '@chromatic-com/playwright'
- - react
'@date-fns/tz@1.2.0': {}
@@ -8595,79 +7806,79 @@ snapshots:
'@emotion/unitless@0.8.1': {}
- '@esbuild/aix-ppc64@0.24.2':
+ '@esbuild/aix-ppc64@0.25.5':
optional: true
- '@esbuild/android-arm64@0.24.2':
+ '@esbuild/android-arm64@0.25.5':
optional: true
- '@esbuild/android-arm@0.24.2':
+ '@esbuild/android-arm@0.25.5':
optional: true
- '@esbuild/android-x64@0.24.2':
+ '@esbuild/android-x64@0.25.5':
optional: true
- '@esbuild/darwin-arm64@0.24.2':
+ '@esbuild/darwin-arm64@0.25.5':
optional: true
- '@esbuild/darwin-x64@0.24.2':
+ '@esbuild/darwin-x64@0.25.5':
optional: true
- '@esbuild/freebsd-arm64@0.24.2':
+ '@esbuild/freebsd-arm64@0.25.5':
optional: true
- '@esbuild/freebsd-x64@0.24.2':
+ '@esbuild/freebsd-x64@0.25.5':
optional: true
- '@esbuild/linux-arm64@0.24.2':
+ '@esbuild/linux-arm64@0.25.5':
optional: true
- '@esbuild/linux-arm@0.24.2':
+ '@esbuild/linux-arm@0.25.5':
optional: true
- '@esbuild/linux-ia32@0.24.2':
+ '@esbuild/linux-ia32@0.25.5':
optional: true
- '@esbuild/linux-loong64@0.24.2':
+ '@esbuild/linux-loong64@0.25.5':
optional: true
- '@esbuild/linux-mips64el@0.24.2':
+ '@esbuild/linux-mips64el@0.25.5':
optional: true
- '@esbuild/linux-ppc64@0.24.2':
+ '@esbuild/linux-ppc64@0.25.5':
optional: true
- '@esbuild/linux-riscv64@0.24.2':
+ '@esbuild/linux-riscv64@0.25.5':
optional: true
- '@esbuild/linux-s390x@0.24.2':
+ '@esbuild/linux-s390x@0.25.5':
optional: true
- '@esbuild/linux-x64@0.24.2':
+ '@esbuild/linux-x64@0.25.5':
optional: true
- '@esbuild/netbsd-arm64@0.24.2':
+ '@esbuild/netbsd-arm64@0.25.5':
optional: true
- '@esbuild/netbsd-x64@0.24.2':
+ '@esbuild/netbsd-x64@0.25.5':
optional: true
- '@esbuild/openbsd-arm64@0.24.2':
+ '@esbuild/openbsd-arm64@0.25.5':
optional: true
- '@esbuild/openbsd-x64@0.24.2':
+ '@esbuild/openbsd-x64@0.25.5':
optional: true
- '@esbuild/sunos-x64@0.24.2':
+ '@esbuild/sunos-x64@0.25.5':
optional: true
- '@esbuild/win32-arm64@0.24.2':
+ '@esbuild/win32-arm64@0.25.5':
optional: true
- '@esbuild/win32-ia32@0.24.2':
+ '@esbuild/win32-ia32@0.25.5':
optional: true
- '@esbuild/win32-x64@0.24.2':
+ '@esbuild/win32-x64@0.25.5':
optional: true
'@eslint-community/eslint-utils@4.7.0(eslint@8.57.1)':
@@ -8693,6 +7904,8 @@ snapshots:
'@eslint/js@8.57.1': {}
+ '@exodus/schemasafe@1.3.0': {}
+
'@faker-js/faker@9.8.0': {}
'@floating-ui/core@1.7.1':
@@ -8712,11 +7925,13 @@ snapshots:
'@floating-ui/utils@0.2.9': {}
- '@hapi/hoek@9.3.0': {}
-
- '@hapi/topo@5.1.0':
+ '@gerrit0/mini-shiki@3.6.0':
dependencies:
- '@hapi/hoek': 9.3.0
+ '@shikijs/engine-oniguruma': 3.6.0
+ '@shikijs/langs': 3.6.0
+ '@shikijs/themes': 3.6.0
+ '@shikijs/types': 3.6.0
+ '@shikijs/vscode-textmate': 10.0.2
'@hookform/resolvers@5.1.1(react-hook-form@7.57.0(react@18.3.1))':
dependencies:
@@ -8735,142 +7950,91 @@ snapshots:
'@humanwhocodes/object-schema@2.0.3': {}
- '@img/sharp-darwin-arm64@0.33.5':
- optionalDependencies:
- '@img/sharp-libvips-darwin-arm64': 1.0.4
- optional: true
+ '@ibm-cloud/openapi-ruleset-utilities@1.9.0': {}
+
+ '@ibm-cloud/openapi-ruleset@1.31.1':
+ dependencies:
+ '@ibm-cloud/openapi-ruleset-utilities': 1.9.0
+ '@stoplight/spectral-formats': 1.8.2
+ '@stoplight/spectral-functions': 1.10.1
+ '@stoplight/spectral-rulesets': 1.22.0
+ chalk: 4.1.2
+ jsonschema: 1.5.0
+ lodash: 4.17.21
+ loglevel: 1.9.2
+ loglevel-plugin-prefix: 0.8.4
+ minimatch: 6.2.0
+ validator: 13.15.15
+ transitivePeerDependencies:
+ - encoding
'@img/sharp-darwin-arm64@0.34.2':
optionalDependencies:
'@img/sharp-libvips-darwin-arm64': 1.1.0
optional: true
- '@img/sharp-darwin-x64@0.33.5':
- optionalDependencies:
- '@img/sharp-libvips-darwin-x64': 1.0.4
- optional: true
-
'@img/sharp-darwin-x64@0.34.2':
optionalDependencies:
'@img/sharp-libvips-darwin-x64': 1.1.0
optional: true
- '@img/sharp-libvips-darwin-arm64@1.0.4':
- optional: true
-
'@img/sharp-libvips-darwin-arm64@1.1.0':
optional: true
- '@img/sharp-libvips-darwin-x64@1.0.4':
- optional: true
-
'@img/sharp-libvips-darwin-x64@1.1.0':
optional: true
- '@img/sharp-libvips-linux-arm64@1.0.4':
- optional: true
-
'@img/sharp-libvips-linux-arm64@1.1.0':
optional: true
- '@img/sharp-libvips-linux-arm@1.0.5':
- optional: true
-
'@img/sharp-libvips-linux-arm@1.1.0':
optional: true
'@img/sharp-libvips-linux-ppc64@1.1.0':
optional: true
- '@img/sharp-libvips-linux-s390x@1.0.4':
- optional: true
-
'@img/sharp-libvips-linux-s390x@1.1.0':
optional: true
- '@img/sharp-libvips-linux-x64@1.0.4':
- optional: true
-
'@img/sharp-libvips-linux-x64@1.1.0':
optional: true
- '@img/sharp-libvips-linuxmusl-arm64@1.0.4':
- optional: true
-
'@img/sharp-libvips-linuxmusl-arm64@1.1.0':
optional: true
- '@img/sharp-libvips-linuxmusl-x64@1.0.4':
- optional: true
-
'@img/sharp-libvips-linuxmusl-x64@1.1.0':
optional: true
- '@img/sharp-linux-arm64@0.33.5':
- optionalDependencies:
- '@img/sharp-libvips-linux-arm64': 1.0.4
- optional: true
-
'@img/sharp-linux-arm64@0.34.2':
optionalDependencies:
'@img/sharp-libvips-linux-arm64': 1.1.0
optional: true
- '@img/sharp-linux-arm@0.33.5':
- optionalDependencies:
- '@img/sharp-libvips-linux-arm': 1.0.5
- optional: true
-
'@img/sharp-linux-arm@0.34.2':
optionalDependencies:
'@img/sharp-libvips-linux-arm': 1.1.0
optional: true
- '@img/sharp-linux-s390x@0.33.5':
- optionalDependencies:
- '@img/sharp-libvips-linux-s390x': 1.0.4
- optional: true
-
'@img/sharp-linux-s390x@0.34.2':
optionalDependencies:
'@img/sharp-libvips-linux-s390x': 1.1.0
optional: true
- '@img/sharp-linux-x64@0.33.5':
- optionalDependencies:
- '@img/sharp-libvips-linux-x64': 1.0.4
- optional: true
-
'@img/sharp-linux-x64@0.34.2':
optionalDependencies:
'@img/sharp-libvips-linux-x64': 1.1.0
optional: true
- '@img/sharp-linuxmusl-arm64@0.33.5':
- optionalDependencies:
- '@img/sharp-libvips-linuxmusl-arm64': 1.0.4
- optional: true
-
'@img/sharp-linuxmusl-arm64@0.34.2':
optionalDependencies:
'@img/sharp-libvips-linuxmusl-arm64': 1.1.0
optional: true
- '@img/sharp-linuxmusl-x64@0.33.5':
- optionalDependencies:
- '@img/sharp-libvips-linuxmusl-x64': 1.0.4
- optional: true
-
'@img/sharp-linuxmusl-x64@0.34.2':
optionalDependencies:
'@img/sharp-libvips-linuxmusl-x64': 1.1.0
optional: true
- '@img/sharp-wasm32@0.33.5':
- dependencies:
- '@emnapi/runtime': 1.4.3
- optional: true
-
'@img/sharp-wasm32@0.34.2':
dependencies:
'@emnapi/runtime': 1.4.3
@@ -8879,15 +8043,9 @@ snapshots:
'@img/sharp-win32-arm64@0.34.2':
optional: true
- '@img/sharp-win32-ia32@0.33.5':
- optional: true
-
'@img/sharp-win32-ia32@0.34.2':
optional: true
- '@img/sharp-win32-x64@0.33.5':
- optional: true
-
'@img/sharp-win32-x64@0.34.2':
optional: true
@@ -8926,182 +8084,6 @@ snapshots:
wrap-ansi: 8.1.0
wrap-ansi-cjs: wrap-ansi@7.0.0
- '@istanbuljs/load-nyc-config@1.1.0':
- dependencies:
- camelcase: 5.3.1
- find-up: 4.1.0
- get-package-type: 0.1.0
- js-yaml: 3.14.1
- resolve-from: 5.0.0
-
- '@istanbuljs/schema@0.1.3': {}
-
- '@jest/console@29.7.0':
- dependencies:
- '@jest/types': 29.6.3
- '@types/node': 22.15.30
- chalk: 4.1.2
- jest-message-util: 29.7.0
- jest-util: 29.7.0
- slash: 3.0.0
-
- '@jest/core@29.7.0':
- dependencies:
- '@jest/console': 29.7.0
- '@jest/reporters': 29.7.0
- '@jest/test-result': 29.7.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 22.15.30
- ansi-escapes: 4.3.2
- chalk: 4.1.2
- ci-info: 3.9.0
- exit: 0.1.2
- graceful-fs: 4.2.11
- jest-changed-files: 29.7.0
- jest-config: 29.7.0(@types/node@22.15.30)
- jest-haste-map: 29.7.0
- jest-message-util: 29.7.0
- jest-regex-util: 29.6.3
- jest-resolve: 29.7.0
- jest-resolve-dependencies: 29.7.0
- jest-runner: 29.7.0
- jest-runtime: 29.7.0
- jest-snapshot: 29.7.0
- jest-util: 29.7.0
- jest-validate: 29.7.0
- jest-watcher: 29.7.0
- micromatch: 4.0.8
- pretty-format: 29.7.0
- slash: 3.0.0
- strip-ansi: 6.0.1
- transitivePeerDependencies:
- - babel-plugin-macros
- - supports-color
- - ts-node
-
- '@jest/create-cache-key-function@29.7.0':
- dependencies:
- '@jest/types': 29.6.3
-
- '@jest/environment@29.7.0':
- dependencies:
- '@jest/fake-timers': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 22.15.30
- jest-mock: 29.7.0
-
- '@jest/expect-utils@29.7.0':
- dependencies:
- jest-get-type: 29.6.3
-
- '@jest/expect@29.7.0':
- dependencies:
- expect: 29.7.0
- jest-snapshot: 29.7.0
- transitivePeerDependencies:
- - supports-color
-
- '@jest/fake-timers@29.7.0':
- dependencies:
- '@jest/types': 29.6.3
- '@sinonjs/fake-timers': 10.3.0
- '@types/node': 22.15.30
- jest-message-util: 29.7.0
- jest-mock: 29.7.0
- jest-util: 29.7.0
-
- '@jest/globals@29.7.0':
- dependencies:
- '@jest/environment': 29.7.0
- '@jest/expect': 29.7.0
- '@jest/types': 29.6.3
- jest-mock: 29.7.0
- transitivePeerDependencies:
- - supports-color
-
- '@jest/reporters@29.7.0':
- dependencies:
- '@bcoe/v8-coverage': 0.2.3
- '@jest/console': 29.7.0
- '@jest/test-result': 29.7.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- '@jridgewell/trace-mapping': 0.3.25
- '@types/node': 22.15.30
- chalk: 4.1.2
- collect-v8-coverage: 1.0.2
- exit: 0.1.2
- glob: 7.2.3
- graceful-fs: 4.2.11
- istanbul-lib-coverage: 3.2.2
- istanbul-lib-instrument: 6.0.3
- istanbul-lib-report: 3.0.1
- istanbul-lib-source-maps: 4.0.1
- istanbul-reports: 3.1.7
- jest-message-util: 29.7.0
- jest-util: 29.7.0
- jest-worker: 29.7.0
- slash: 3.0.0
- string-length: 4.0.2
- strip-ansi: 6.0.1
- v8-to-istanbul: 9.3.0
- transitivePeerDependencies:
- - supports-color
-
- '@jest/schemas@29.6.3':
- dependencies:
- '@sinclair/typebox': 0.27.8
-
- '@jest/source-map@29.6.3':
- dependencies:
- '@jridgewell/trace-mapping': 0.3.25
- callsites: 3.1.0
- graceful-fs: 4.2.11
-
- '@jest/test-result@29.7.0':
- dependencies:
- '@jest/console': 29.7.0
- '@jest/types': 29.6.3
- '@types/istanbul-lib-coverage': 2.0.6
- collect-v8-coverage: 1.0.2
-
- '@jest/test-sequencer@29.7.0':
- dependencies:
- '@jest/test-result': 29.7.0
- graceful-fs: 4.2.11
- jest-haste-map: 29.7.0
- slash: 3.0.0
-
- '@jest/transform@29.7.0':
- dependencies:
- '@babel/core': 7.27.4
- '@jest/types': 29.6.3
- '@jridgewell/trace-mapping': 0.3.25
- babel-plugin-istanbul: 6.1.1
- chalk: 4.1.2
- convert-source-map: 2.0.0
- fast-json-stable-stringify: 2.1.0
- graceful-fs: 4.2.11
- jest-haste-map: 29.7.0
- jest-regex-util: 29.6.3
- jest-util: 29.7.0
- micromatch: 4.0.8
- pirates: 4.0.7
- slash: 3.0.0
- write-file-atomic: 4.0.2
- transitivePeerDependencies:
- - supports-color
-
- '@jest/types@29.6.3':
- dependencies:
- '@jest/schemas': 29.6.3
- '@types/istanbul-lib-coverage': 2.0.6
- '@types/istanbul-reports': 3.0.4
- '@types/node': 22.15.30
- '@types/yargs': 17.0.33
- chalk: 4.1.2
-
'@jridgewell/gen-mapping@0.3.8':
dependencies:
'@jridgewell/set-array': 1.2.1
@@ -9124,6 +8106,20 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.0
+ '@jsdevtools/ono@7.1.3': {}
+
+ '@jsep-plugin/assignment@1.3.0(jsep@1.4.0)':
+ dependencies:
+ jsep: 1.4.0
+
+ '@jsep-plugin/regex@1.0.4(jsep@1.4.0)':
+ dependencies:
+ jsep: 1.4.0
+
+ '@jsep-plugin/ternary@1.1.4(jsep@1.4.0)':
+ dependencies:
+ jsep: 1.4.0
+
'@mdx-js/react@3.1.0(@types/react@18.3.17)(react@18.3.1)':
dependencies:
'@types/mdx': 2.0.13
@@ -9139,16 +8135,18 @@ snapshots:
outvariant: 1.4.3
strict-event-emitter: 0.5.1
- '@napi-rs/wasm-runtime@0.2.10':
+ '@napi-rs/wasm-runtime@0.2.11':
dependencies:
'@emnapi/core': 1.4.3
'@emnapi/runtime': 1.4.3
'@tybys/wasm-util': 0.9.0
optional: true
+ '@neoconfetti/react@1.0.0': {}
+
'@next/env@15.3.3': {}
- '@next/eslint-plugin-next@15.3.3':
+ '@next/eslint-plugin-next@15.3.4':
dependencies:
fast-glob: 3.3.1
@@ -9176,9 +8174,9 @@ snapshots:
'@next/swc-win32-x64-msvc@15.3.3':
optional: true
- '@next/third-parties@15.3.3(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)':
+ '@next/third-parties@15.3.3(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)':
dependencies:
- next: 15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ next: 15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react: 18.3.1
third-party-capital: 1.0.20
@@ -9416,7 +8414,7 @@ snapshots:
'@opentelemetry/api': 1.9.0
'@opentelemetry/api-logs': 0.57.2
'@types/shimmer': 1.2.0
- import-in-the-middle: 1.14.0
+ import-in-the-middle: 1.14.2
require-in-the-middle: 7.5.2
semver: 7.7.2
shimmer: 1.2.1
@@ -9447,24 +8445,134 @@ snapshots:
'@opentelemetry/api': 1.9.0
'@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0)
+ '@orval/angular@7.10.0(openapi-types@12.1.3)':
+ dependencies:
+ '@orval/core': 7.10.0(openapi-types@12.1.3)
+ transitivePeerDependencies:
+ - encoding
+ - openapi-types
+ - supports-color
+
+ '@orval/axios@7.10.0(openapi-types@12.1.3)':
+ dependencies:
+ '@orval/core': 7.10.0(openapi-types@12.1.3)
+ transitivePeerDependencies:
+ - encoding
+ - openapi-types
+ - supports-color
+
+ '@orval/core@7.10.0(openapi-types@12.1.3)':
+ dependencies:
+ '@apidevtools/swagger-parser': 10.1.1(openapi-types@12.1.3)
+ '@ibm-cloud/openapi-ruleset': 1.31.1
+ acorn: 8.15.0
+ ajv: 8.17.1
+ chalk: 4.1.2
+ compare-versions: 6.1.1
+ debug: 4.4.1
+ esbuild: 0.25.5
+ esutils: 2.0.3
+ fs-extra: 11.3.0
+ globby: 11.1.0
+ lodash.isempty: 4.4.0
+ lodash.uniq: 4.5.0
+ lodash.uniqby: 4.7.0
+ lodash.uniqwith: 4.5.0
+ micromatch: 4.0.8
+ openapi3-ts: 4.4.0
+ swagger2openapi: 7.0.8
+ transitivePeerDependencies:
+ - encoding
+ - openapi-types
+ - supports-color
+
+ '@orval/fetch@7.10.0(openapi-types@12.1.3)':
+ dependencies:
+ '@orval/core': 7.10.0(openapi-types@12.1.3)
+ transitivePeerDependencies:
+ - encoding
+ - openapi-types
+ - supports-color
+
+ '@orval/hono@7.10.0(openapi-types@12.1.3)':
+ dependencies:
+ '@orval/core': 7.10.0(openapi-types@12.1.3)
+ '@orval/zod': 7.10.0(openapi-types@12.1.3)
+ lodash.uniq: 4.5.0
+ transitivePeerDependencies:
+ - encoding
+ - openapi-types
+ - supports-color
+
+ '@orval/mcp@7.10.0(openapi-types@12.1.3)':
+ dependencies:
+ '@orval/core': 7.10.0(openapi-types@12.1.3)
+ '@orval/zod': 7.10.0(openapi-types@12.1.3)
+ transitivePeerDependencies:
+ - encoding
+ - openapi-types
+ - supports-color
+
+ '@orval/mock@7.10.0(openapi-types@12.1.3)':
+ dependencies:
+ '@orval/core': 7.10.0(openapi-types@12.1.3)
+ openapi3-ts: 4.2.2
+ transitivePeerDependencies:
+ - encoding
+ - openapi-types
+ - supports-color
+
+ '@orval/query@7.10.0(openapi-types@12.1.3)':
+ dependencies:
+ '@orval/core': 7.10.0(openapi-types@12.1.3)
+ '@orval/fetch': 7.10.0(openapi-types@12.1.3)
+ lodash.omitby: 4.6.0
+ transitivePeerDependencies:
+ - encoding
+ - openapi-types
+ - supports-color
+
+ '@orval/swr@7.10.0(openapi-types@12.1.3)':
+ dependencies:
+ '@orval/core': 7.10.0(openapi-types@12.1.3)
+ '@orval/fetch': 7.10.0(openapi-types@12.1.3)
+ transitivePeerDependencies:
+ - encoding
+ - openapi-types
+ - supports-color
+
+ '@orval/zod@7.10.0(openapi-types@12.1.3)':
+ dependencies:
+ '@orval/core': 7.10.0(openapi-types@12.1.3)
+ lodash.uniq: 4.5.0
+ transitivePeerDependencies:
+ - encoding
+ - openapi-types
+ - supports-color
+
+ '@phosphor-icons/react@2.1.10(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)
+
'@pkgjs/parseargs@0.11.0':
optional: true
- '@playwright/test@1.52.0':
+ '@playwright/test@1.53.1':
dependencies:
- playwright: 1.52.0
+ playwright: 1.53.1
- '@pmmmwh/react-refresh-webpack-plugin@0.5.16(react-refresh@0.14.2)(type-fest@4.41.0)(webpack-hot-middleware@2.26.1)(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2))':
+ '@pmmmwh/react-refresh-webpack-plugin@0.5.16(react-refresh@0.14.2)(type-fest@4.41.0)(webpack-hot-middleware@2.26.1)(webpack@5.99.9(esbuild@0.25.5))':
dependencies:
ansi-html: 0.0.9
- core-js-pure: 3.42.0
+ core-js-pure: 3.43.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
source-map: 0.7.4
- webpack: 5.99.9(@swc/core@1.11.31)(esbuild@0.24.2)
+ webpack: 5.99.9(esbuild@0.25.5)
optionalDependencies:
type-fest: 4.41.0
webpack-hot-middleware: 2.26.1
@@ -10020,7 +9128,7 @@ snapshots:
'@rollup/pluginutils': 5.1.4(rollup@4.35.0)
commondir: 1.0.1
estree-walker: 2.0.2
- fdir: 6.4.5(picomatch@4.0.2)
+ fdir: 6.4.6(picomatch@4.0.2)
is-reference: 1.2.1
magic-string: 0.30.17
picomatch: 4.0.2
@@ -10182,7 +9290,7 @@ snapshots:
'@sentry/core@9.27.0': {}
- '@sentry/nextjs@9.27.0(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2))':
+ '@sentry/nextjs@9.27.0(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.99.9(esbuild@0.25.5))':
dependencies:
'@opentelemetry/api': 1.9.0
'@opentelemetry/semantic-conventions': 1.34.0
@@ -10193,9 +9301,9 @@ snapshots:
'@sentry/opentelemetry': 9.27.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.34.0)
'@sentry/react': 9.27.0(react@18.3.1)
'@sentry/vercel-edge': 9.27.0
- '@sentry/webpack-plugin': 3.5.0(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2))
+ '@sentry/webpack-plugin': 3.5.0(webpack@5.99.9(esbuild@0.25.5))
chalk: 3.0.0
- next: 15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ next: 15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
resolve: 1.22.8
rollup: 4.35.0
stacktrace-parser: 0.1.11
@@ -10243,7 +9351,7 @@ snapshots:
'@prisma/instrumentation': 6.8.2(@opentelemetry/api@1.9.0)
'@sentry/core': 9.27.0
'@sentry/opentelemetry': 9.27.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.34.0)
- import-in-the-middle: 1.14.0
+ import-in-the-middle: 1.14.2
minimatch: 9.0.5
transitivePeerDependencies:
- supports-color
@@ -10270,177 +9378,247 @@ snapshots:
'@opentelemetry/api': 1.9.0
'@sentry/core': 9.27.0
- '@sentry/webpack-plugin@3.5.0(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2))':
+ '@sentry/webpack-plugin@3.5.0(webpack@5.99.9(esbuild@0.25.5))':
dependencies:
'@sentry/bundler-plugin-core': 3.5.0
unplugin: 1.0.1
uuid: 9.0.1
- webpack: 5.99.9(@swc/core@1.11.31)(esbuild@0.24.2)
+ webpack: 5.99.9(esbuild@0.25.5)
transitivePeerDependencies:
- encoding
- supports-color
- '@sideway/address@4.1.5':
+ '@shikijs/engine-oniguruma@3.6.0':
dependencies:
- '@hapi/hoek': 9.3.0
+ '@shikijs/types': 3.6.0
+ '@shikijs/vscode-textmate': 10.0.2
- '@sideway/formula@3.0.1': {}
-
- '@sideway/pinpoint@2.0.0': {}
-
- '@sinclair/typebox@0.27.8': {}
-
- '@sinonjs/commons@3.0.1':
+ '@shikijs/langs@3.6.0':
dependencies:
- type-detect: 4.0.8
+ '@shikijs/types': 3.6.0
- '@sinonjs/fake-timers@10.3.0':
+ '@shikijs/themes@3.6.0':
dependencies:
- '@sinonjs/commons': 3.0.1
+ '@shikijs/types': 3.6.0
+
+ '@shikijs/types@3.6.0':
+ dependencies:
+ '@shikijs/vscode-textmate': 10.0.2
+ '@types/hast': 3.0.4
+
+ '@shikijs/vscode-textmate@10.0.2': {}
'@standard-schema/utils@0.3.0': {}
- '@storybook/addon-a11y@8.6.14(storybook@8.6.14(prettier@3.5.3))':
+ '@stoplight/better-ajv-errors@1.0.3(ajv@8.17.1)':
+ dependencies:
+ ajv: 8.17.1
+ jsonpointer: 5.0.1
+ leven: 3.1.0
+
+ '@stoplight/json-ref-readers@1.2.2':
+ dependencies:
+ node-fetch: 2.7.0
+ tslib: 1.14.1
+ transitivePeerDependencies:
+ - encoding
+
+ '@stoplight/json-ref-resolver@3.1.6':
+ dependencies:
+ '@stoplight/json': 3.21.7
+ '@stoplight/path': 1.3.2
+ '@stoplight/types': 13.6.0
+ '@types/urijs': 1.19.25
+ dependency-graph: 0.11.0
+ fast-memoize: 2.5.2
+ immer: 9.0.21
+ lodash: 4.17.21
+ tslib: 2.8.1
+ urijs: 1.19.11
+
+ '@stoplight/json@3.21.7':
+ dependencies:
+ '@stoplight/ordered-object-literal': 1.0.5
+ '@stoplight/path': 1.3.2
+ '@stoplight/types': 13.20.0
+ jsonc-parser: 2.2.1
+ lodash: 4.17.21
+ safe-stable-stringify: 1.1.1
+
+ '@stoplight/ordered-object-literal@1.0.5': {}
+
+ '@stoplight/path@1.3.2': {}
+
+ '@stoplight/spectral-core@1.20.0':
+ dependencies:
+ '@stoplight/better-ajv-errors': 1.0.3(ajv@8.17.1)
+ '@stoplight/json': 3.21.7
+ '@stoplight/path': 1.3.2
+ '@stoplight/spectral-parsers': 1.0.5
+ '@stoplight/spectral-ref-resolver': 1.0.5
+ '@stoplight/spectral-runtime': 1.1.4
+ '@stoplight/types': 13.6.0
+ '@types/es-aggregate-error': 1.0.6
+ '@types/json-schema': 7.0.15
+ ajv: 8.17.1
+ ajv-errors: 3.0.0(ajv@8.17.1)
+ ajv-formats: 2.1.1(ajv@8.17.1)
+ es-aggregate-error: 1.0.14
+ jsonpath-plus: 10.3.0
+ lodash: 4.17.21
+ lodash.topath: 4.5.2
+ minimatch: 3.1.2
+ nimma: 0.2.3
+ pony-cause: 1.1.1
+ simple-eval: 1.0.1
+ tslib: 2.8.1
+ transitivePeerDependencies:
+ - encoding
+
+ '@stoplight/spectral-formats@1.8.2':
+ dependencies:
+ '@stoplight/json': 3.21.7
+ '@stoplight/spectral-core': 1.20.0
+ '@types/json-schema': 7.0.15
+ tslib: 2.8.1
+ transitivePeerDependencies:
+ - encoding
+
+ '@stoplight/spectral-functions@1.10.1':
+ dependencies:
+ '@stoplight/better-ajv-errors': 1.0.3(ajv@8.17.1)
+ '@stoplight/json': 3.21.7
+ '@stoplight/spectral-core': 1.20.0
+ '@stoplight/spectral-formats': 1.8.2
+ '@stoplight/spectral-runtime': 1.1.4
+ ajv: 8.17.1
+ ajv-draft-04: 1.0.0(ajv@8.17.1)
+ ajv-errors: 3.0.0(ajv@8.17.1)
+ ajv-formats: 2.1.1(ajv@8.17.1)
+ lodash: 4.17.21
+ tslib: 2.8.1
+ transitivePeerDependencies:
+ - encoding
+
+ '@stoplight/spectral-parsers@1.0.5':
+ dependencies:
+ '@stoplight/json': 3.21.7
+ '@stoplight/types': 14.1.1
+ '@stoplight/yaml': 4.3.0
+ tslib: 2.8.1
+
+ '@stoplight/spectral-ref-resolver@1.0.5':
+ dependencies:
+ '@stoplight/json-ref-readers': 1.2.2
+ '@stoplight/json-ref-resolver': 3.1.6
+ '@stoplight/spectral-runtime': 1.1.4
+ dependency-graph: 0.11.0
+ tslib: 2.8.1
+ transitivePeerDependencies:
+ - encoding
+
+ '@stoplight/spectral-rulesets@1.22.0':
+ dependencies:
+ '@asyncapi/specs': 6.8.1
+ '@stoplight/better-ajv-errors': 1.0.3(ajv@8.17.1)
+ '@stoplight/json': 3.21.7
+ '@stoplight/spectral-core': 1.20.0
+ '@stoplight/spectral-formats': 1.8.2
+ '@stoplight/spectral-functions': 1.10.1
+ '@stoplight/spectral-runtime': 1.1.4
+ '@stoplight/types': 13.20.0
+ '@types/json-schema': 7.0.15
+ ajv: 8.17.1
+ ajv-formats: 2.1.1(ajv@8.17.1)
+ json-schema-traverse: 1.0.0
+ leven: 3.1.0
+ lodash: 4.17.21
+ tslib: 2.8.1
+ transitivePeerDependencies:
+ - encoding
+
+ '@stoplight/spectral-runtime@1.1.4':
+ dependencies:
+ '@stoplight/json': 3.21.7
+ '@stoplight/path': 1.3.2
+ '@stoplight/types': 13.20.0
+ abort-controller: 3.0.0
+ lodash: 4.17.21
+ node-fetch: 2.7.0
+ tslib: 2.8.1
+ transitivePeerDependencies:
+ - encoding
+
+ '@stoplight/types@13.20.0':
+ dependencies:
+ '@types/json-schema': 7.0.15
+ utility-types: 3.11.0
+
+ '@stoplight/types@13.6.0':
+ dependencies:
+ '@types/json-schema': 7.0.15
+ utility-types: 3.11.0
+
+ '@stoplight/types@14.1.1':
+ dependencies:
+ '@types/json-schema': 7.0.15
+ utility-types: 3.11.0
+
+ '@stoplight/yaml-ast-parser@0.0.50': {}
+
+ '@stoplight/yaml@4.3.0':
+ dependencies:
+ '@stoplight/ordered-object-literal': 1.0.5
+ '@stoplight/types': 14.1.1
+ '@stoplight/yaml-ast-parser': 0.0.50
+ tslib: 2.8.1
+
+ '@storybook/addon-a11y@9.0.12(storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))':
dependencies:
- '@storybook/addon-highlight': 8.6.14(storybook@8.6.14(prettier@3.5.3))
'@storybook/global': 5.0.0
- '@storybook/test': 8.6.14(storybook@8.6.14(prettier@3.5.3))
axe-core: 4.10.3
- storybook: 8.6.14(prettier@3.5.3)
+ storybook: 9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3)
- '@storybook/addon-actions@8.6.14(storybook@8.6.14(prettier@3.5.3))':
- dependencies:
- '@storybook/global': 5.0.0
- '@types/uuid': 9.0.8
- dequal: 2.0.3
- polished: 4.3.1
- storybook: 8.6.14(prettier@3.5.3)
- uuid: 9.0.1
-
- '@storybook/addon-backgrounds@8.6.14(storybook@8.6.14(prettier@3.5.3))':
- dependencies:
- '@storybook/global': 5.0.0
- memoizerific: 1.11.3
- storybook: 8.6.14(prettier@3.5.3)
- ts-dedent: 2.2.0
-
- '@storybook/addon-controls@8.6.14(storybook@8.6.14(prettier@3.5.3))':
- dependencies:
- '@storybook/global': 5.0.0
- dequal: 2.0.3
- storybook: 8.6.14(prettier@3.5.3)
- ts-dedent: 2.2.0
-
- '@storybook/addon-docs@8.6.14(@types/react@18.3.17)(storybook@8.6.14(prettier@3.5.3))':
+ '@storybook/addon-docs@9.0.12(@types/react@18.3.17)(storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))':
dependencies:
'@mdx-js/react': 3.1.0(@types/react@18.3.17)(react@18.3.1)
- '@storybook/blocks': 8.6.14(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.5.3))
- '@storybook/csf-plugin': 8.6.14(storybook@8.6.14(prettier@3.5.3))
- '@storybook/react-dom-shim': 8.6.14(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.5.3))
- react: 18.3.1
- react-dom: 18.3.1(react@18.3.1)
- storybook: 8.6.14(prettier@3.5.3)
- ts-dedent: 2.2.0
- transitivePeerDependencies:
- - '@types/react'
-
- '@storybook/addon-essentials@8.6.14(@types/react@18.3.17)(storybook@8.6.14(prettier@3.5.3))':
- dependencies:
- '@storybook/addon-actions': 8.6.14(storybook@8.6.14(prettier@3.5.3))
- '@storybook/addon-backgrounds': 8.6.14(storybook@8.6.14(prettier@3.5.3))
- '@storybook/addon-controls': 8.6.14(storybook@8.6.14(prettier@3.5.3))
- '@storybook/addon-docs': 8.6.14(@types/react@18.3.17)(storybook@8.6.14(prettier@3.5.3))
- '@storybook/addon-highlight': 8.6.14(storybook@8.6.14(prettier@3.5.3))
- '@storybook/addon-measure': 8.6.14(storybook@8.6.14(prettier@3.5.3))
- '@storybook/addon-outline': 8.6.14(storybook@8.6.14(prettier@3.5.3))
- '@storybook/addon-toolbars': 8.6.14(storybook@8.6.14(prettier@3.5.3))
- '@storybook/addon-viewport': 8.6.14(storybook@8.6.14(prettier@3.5.3))
- storybook: 8.6.14(prettier@3.5.3)
- ts-dedent: 2.2.0
- transitivePeerDependencies:
- - '@types/react'
-
- '@storybook/addon-highlight@8.6.14(storybook@8.6.14(prettier@3.5.3))':
- dependencies:
- '@storybook/global': 5.0.0
- storybook: 8.6.14(prettier@3.5.3)
-
- '@storybook/addon-interactions@8.6.14(storybook@8.6.14(prettier@3.5.3))':
- dependencies:
- '@storybook/global': 5.0.0
- '@storybook/instrumenter': 8.6.14(storybook@8.6.14(prettier@3.5.3))
- '@storybook/test': 8.6.14(storybook@8.6.14(prettier@3.5.3))
- polished: 4.3.1
- storybook: 8.6.14(prettier@3.5.3)
- ts-dedent: 2.2.0
-
- '@storybook/addon-links@8.6.14(react@18.3.1)(storybook@8.6.14(prettier@3.5.3))':
- dependencies:
- '@storybook/global': 5.0.0
- storybook: 8.6.14(prettier@3.5.3)
- ts-dedent: 2.2.0
- optionalDependencies:
- react: 18.3.1
-
- '@storybook/addon-measure@8.6.14(storybook@8.6.14(prettier@3.5.3))':
- dependencies:
- '@storybook/global': 5.0.0
- storybook: 8.6.14(prettier@3.5.3)
- tiny-invariant: 1.3.3
-
- '@storybook/addon-onboarding@8.6.14(storybook@8.6.14(prettier@3.5.3))':
- dependencies:
- storybook: 8.6.14(prettier@3.5.3)
-
- '@storybook/addon-outline@8.6.14(storybook@8.6.14(prettier@3.5.3))':
- dependencies:
- '@storybook/global': 5.0.0
- storybook: 8.6.14(prettier@3.5.3)
- ts-dedent: 2.2.0
-
- '@storybook/addon-toolbars@8.6.14(storybook@8.6.14(prettier@3.5.3))':
- dependencies:
- storybook: 8.6.14(prettier@3.5.3)
-
- '@storybook/addon-viewport@8.6.14(storybook@8.6.14(prettier@3.5.3))':
- dependencies:
- memoizerific: 1.11.3
- storybook: 8.6.14(prettier@3.5.3)
-
- '@storybook/blocks@8.6.14(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.5.3))':
- dependencies:
+ '@storybook/csf-plugin': 9.0.12(storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))
'@storybook/icons': 1.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- storybook: 8.6.14(prettier@3.5.3)
- ts-dedent: 2.2.0
- optionalDependencies:
+ '@storybook/react-dom-shim': 9.0.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
+ storybook: 9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3)
+ ts-dedent: 2.2.0
+ transitivePeerDependencies:
+ - '@types/react'
- '@storybook/builder-webpack5@8.6.14(@swc/core@1.11.31)(esbuild@0.24.2)(storybook@8.6.14(prettier@3.5.3))(typescript@5.8.3)':
+ '@storybook/addon-links@9.0.12(react@18.3.1)(storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))':
dependencies:
- '@storybook/core-webpack': 8.6.14(storybook@8.6.14(prettier@3.5.3))
- '@types/semver': 7.7.0
- browser-assert: 1.2.1
+ '@storybook/global': 5.0.0
+ storybook: 9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3)
+ optionalDependencies:
+ react: 18.3.1
+
+ '@storybook/addon-onboarding@9.0.12(storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))':
+ dependencies:
+ storybook: 9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3)
+
+ '@storybook/builder-webpack5@9.0.12(esbuild@0.25.5)(storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))(typescript@5.8.3)':
+ dependencies:
+ '@storybook/core-webpack': 9.0.12(storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))
case-sensitive-paths-webpack-plugin: 2.4.0
cjs-module-lexer: 1.4.3
- constants-browserify: 1.0.0
- css-loader: 6.11.0(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2))
+ css-loader: 6.11.0(webpack@5.99.9(esbuild@0.25.5))
es-module-lexer: 1.7.0
- fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.8.3)(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2))
- html-webpack-plugin: 5.6.3(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2))
+ fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.8.3)(webpack@5.99.9(esbuild@0.25.5))
+ html-webpack-plugin: 5.6.3(webpack@5.99.9(esbuild@0.25.5))
magic-string: 0.30.17
- path-browserify: 1.0.1
- process: 0.11.10
- semver: 7.7.2
- storybook: 8.6.14(prettier@3.5.3)
- style-loader: 3.3.4(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2))
- terser-webpack-plugin: 5.3.14(@swc/core@1.11.31)(esbuild@0.24.2)(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2))
+ storybook: 9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3)
+ style-loader: 3.3.4(webpack@5.99.9(esbuild@0.25.5))
+ terser-webpack-plugin: 5.3.14(esbuild@0.25.5)(webpack@5.99.9(esbuild@0.25.5))
ts-dedent: 2.2.0
- url: 0.11.4
- util: 0.12.5
- util-deprecate: 1.0.2
- webpack: 5.99.9(@swc/core@1.11.31)(esbuild@0.24.2)
- webpack-dev-middleware: 6.1.3(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2))
+ webpack: 5.99.9(esbuild@0.25.5)
+ webpack-dev-middleware: 6.1.3(webpack@5.99.9(esbuild@0.25.5))
webpack-hot-middleware: 2.26.1
webpack-virtual-modules: 0.6.2
optionalDependencies:
@@ -10452,45 +9630,16 @@ snapshots:
- uglify-js
- webpack-cli
- '@storybook/components@8.6.14(storybook@8.6.14(prettier@3.5.3))':
+ '@storybook/core-webpack@9.0.12(storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))':
dependencies:
- storybook: 8.6.14(prettier@3.5.3)
-
- '@storybook/core-webpack@8.6.14(storybook@8.6.14(prettier@3.5.3))':
- dependencies:
- storybook: 8.6.14(prettier@3.5.3)
+ storybook: 9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3)
ts-dedent: 2.2.0
- '@storybook/core@8.6.14(prettier@3.5.3)(storybook@8.6.14(prettier@3.5.3))':
+ '@storybook/csf-plugin@9.0.12(storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))':
dependencies:
- '@storybook/theming': 8.6.14(storybook@8.6.14(prettier@3.5.3))
- better-opn: 3.0.2
- browser-assert: 1.2.1
- esbuild: 0.24.2
- esbuild-register: 3.6.0(esbuild@0.24.2)
- jsdoc-type-pratt-parser: 4.1.0
- process: 0.11.10
- recast: 0.23.11
- semver: 7.7.2
- util: 0.12.5
- ws: 8.18.2
- optionalDependencies:
- prettier: 3.5.3
- transitivePeerDependencies:
- - bufferutil
- - storybook
- - supports-color
- - utf-8-validate
-
- '@storybook/csf-plugin@8.6.14(storybook@8.6.14(prettier@3.5.3))':
- dependencies:
- storybook: 8.6.14(prettier@3.5.3)
+ storybook: 9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3)
unplugin: 1.16.1
- '@storybook/csf@0.1.13':
- dependencies:
- type-fest: 2.19.0
-
'@storybook/global@5.0.0': {}
'@storybook/icons@1.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
@@ -10498,17 +9647,7 @@ snapshots:
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- '@storybook/instrumenter@8.6.14(storybook@8.6.14(prettier@3.5.3))':
- dependencies:
- '@storybook/global': 5.0.0
- '@vitest/utils': 2.1.9
- storybook: 8.6.14(prettier@3.5.3)
-
- '@storybook/manager-api@8.6.14(storybook@8.6.14(prettier@3.5.3))':
- dependencies:
- storybook: 8.6.14(prettier@3.5.3)
-
- '@storybook/nextjs@8.6.14(@swc/core@1.11.31)(esbuild@0.24.2)(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(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@8.6.14(prettier@3.5.3))(type-fest@4.41.0)(typescript@5.8.3)(webpack-hot-middleware@2.26.1)(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2))':
+ '@storybook/nextjs@9.0.12(esbuild@0.25.5)(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.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.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))(type-fest@4.41.0)(typescript@5.8.3)(webpack-hot-middleware@2.26.1)(webpack@5.99.9(esbuild@0.25.5))':
dependencies:
'@babel/core': 7.27.4
'@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.27.4)
@@ -10523,38 +9662,33 @@ snapshots:
'@babel/preset-react': 7.27.1(@babel/core@7.27.4)
'@babel/preset-typescript': 7.27.1(@babel/core@7.27.4)
'@babel/runtime': 7.27.6
- '@pmmmwh/react-refresh-webpack-plugin': 0.5.16(react-refresh@0.14.2)(type-fest@4.41.0)(webpack-hot-middleware@2.26.1)(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2))
- '@storybook/builder-webpack5': 8.6.14(@swc/core@1.11.31)(esbuild@0.24.2)(storybook@8.6.14(prettier@3.5.3))(typescript@5.8.3)
- '@storybook/preset-react-webpack': 8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.5.3)))(@swc/core@1.11.31)(esbuild@0.24.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.5.3))(typescript@5.8.3)
- '@storybook/react': 8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.5.3)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.5.3))(typescript@5.8.3)
- '@storybook/test': 8.6.14(storybook@8.6.14(prettier@3.5.3))
+ '@pmmmwh/react-refresh-webpack-plugin': 0.5.16(react-refresh@0.14.2)(type-fest@4.41.0)(webpack-hot-middleware@2.26.1)(webpack@5.99.9(esbuild@0.25.5))
+ '@storybook/builder-webpack5': 9.0.12(esbuild@0.25.5)(storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))(typescript@5.8.3)
+ '@storybook/preset-react-webpack': 9.0.12(esbuild@0.25.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))(typescript@5.8.3)
+ '@storybook/react': 9.0.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))(typescript@5.8.3)
'@types/semver': 7.7.0
- babel-loader: 9.2.1(@babel/core@7.27.4)(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2))
- css-loader: 6.11.0(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2))
- find-up: 5.0.0
- image-size: 1.2.1
+ babel-loader: 9.2.1(@babel/core@7.27.4)(webpack@5.99.9(esbuild@0.25.5))
+ css-loader: 6.11.0(webpack@5.99.9(esbuild@0.25.5))
+ image-size: 2.0.2
loader-utils: 3.3.1
- next: 15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- node-polyfill-webpack-plugin: 2.0.1(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2))
- pnp-webpack-plugin: 1.7.0(typescript@5.8.3)
- postcss: 8.5.4
- postcss-loader: 8.1.1(postcss@8.5.4)(typescript@5.8.3)(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2))
+ next: 15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ node-polyfill-webpack-plugin: 2.0.1(webpack@5.99.9(esbuild@0.25.5))
+ postcss: 8.5.6
+ postcss-loader: 8.1.1(postcss@8.5.6)(typescript@5.8.3)(webpack@5.99.9(esbuild@0.25.5))
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: 14.2.1(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2))
+ sass-loader: 14.2.1(webpack@5.99.9(esbuild@0.25.5))
semver: 7.7.2
- storybook: 8.6.14(prettier@3.5.3)
- style-loader: 3.3.4(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2))
+ storybook: 9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3)
+ style-loader: 3.3.4(webpack@5.99.9(esbuild@0.25.5))
styled-jsx: 5.1.7(@babel/core@7.27.4)(react@18.3.1)
- ts-dedent: 2.2.0
tsconfig-paths: 4.2.0
tsconfig-paths-webpack-plugin: 4.2.0
optionalDependencies:
- sharp: 0.33.5
typescript: 5.8.3
- webpack: 5.99.9(@swc/core@1.11.31)(esbuild@0.24.2)
+ webpack: 5.99.9(esbuild@0.25.5)
transitivePeerDependencies:
- '@rspack/core'
- '@swc/core'
@@ -10573,117 +9707,60 @@ snapshots:
- webpack-hot-middleware
- webpack-plugin-serve
- '@storybook/preset-react-webpack@8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.5.3)))(@swc/core@1.11.31)(esbuild@0.24.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.5.3))(typescript@5.8.3)':
+ '@storybook/preset-react-webpack@9.0.12(esbuild@0.25.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))(typescript@5.8.3)':
dependencies:
- '@storybook/core-webpack': 8.6.14(storybook@8.6.14(prettier@3.5.3))
- '@storybook/react': 8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.5.3)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.5.3))(typescript@5.8.3)
- '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2))
+ '@storybook/core-webpack': 9.0.12(storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))
+ '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.99.9(esbuild@0.25.5))
'@types/semver': 7.7.0
- find-up: 5.0.0
+ find-up: 7.0.0
magic-string: 0.30.17
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
- storybook: 8.6.14(prettier@3.5.3)
+ storybook: 9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3)
tsconfig-paths: 4.2.0
- webpack: 5.99.9(@swc/core@1.11.31)(esbuild@0.24.2)
+ webpack: 5.99.9(esbuild@0.25.5)
optionalDependencies:
typescript: 5.8.3
transitivePeerDependencies:
- - '@storybook/test'
- '@swc/core'
- esbuild
- supports-color
- uglify-js
- webpack-cli
- '@storybook/preview-api@8.6.14(storybook@8.6.14(prettier@3.5.3))':
- dependencies:
- storybook: 8.6.14(prettier@3.5.3)
-
- '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2))':
+ '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.99.9(esbuild@0.25.5))':
dependencies:
debug: 4.4.1
endent: 2.1.0
find-cache-dir: 3.3.2
flat-cache: 3.2.0
micromatch: 4.0.8
- react-docgen-typescript: 2.2.2(typescript@5.8.3)
+ react-docgen-typescript: 2.4.0(typescript@5.8.3)
tslib: 2.8.1
typescript: 5.8.3
- webpack: 5.99.9(@swc/core@1.11.31)(esbuild@0.24.2)
+ webpack: 5.99.9(esbuild@0.25.5)
transitivePeerDependencies:
- supports-color
- '@storybook/react-dom-shim@8.6.14(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.5.3))':
+ '@storybook/react-dom-shim@9.0.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))':
dependencies:
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- storybook: 8.6.14(prettier@3.5.3)
+ storybook: 9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3)
- '@storybook/react@8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.5.3)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.5.3))(typescript@5.8.3)':
+ '@storybook/react@9.0.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))(typescript@5.8.3)':
dependencies:
- '@storybook/components': 8.6.14(storybook@8.6.14(prettier@3.5.3))
'@storybook/global': 5.0.0
- '@storybook/manager-api': 8.6.14(storybook@8.6.14(prettier@3.5.3))
- '@storybook/preview-api': 8.6.14(storybook@8.6.14(prettier@3.5.3))
- '@storybook/react-dom-shim': 8.6.14(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.5.3))
- '@storybook/theming': 8.6.14(storybook@8.6.14(prettier@3.5.3))
+ '@storybook/react-dom-shim': 9.0.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- storybook: 8.6.14(prettier@3.5.3)
+ storybook: 9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3)
optionalDependencies:
- '@storybook/test': 8.6.14(storybook@8.6.14(prettier@3.5.3))
typescript: 5.8.3
- '@storybook/test-runner@0.22.1(@types/node@22.15.30)(storybook@8.6.14(prettier@3.5.3))':
- dependencies:
- '@babel/core': 7.27.4
- '@babel/generator': 7.27.5
- '@babel/template': 7.27.2
- '@babel/types': 7.27.6
- '@jest/types': 29.6.3
- '@storybook/csf': 0.1.13
- '@swc/core': 1.11.31
- '@swc/jest': 0.2.38(@swc/core@1.11.31)
- expect-playwright: 0.8.0
- jest: 29.7.0(@types/node@22.15.30)
- jest-circus: 29.7.0
- jest-environment-node: 29.7.0
- jest-junit: 16.0.0
- jest-playwright-preset: 4.0.0(jest-circus@29.7.0)(jest-environment-node@29.7.0)(jest-runner@29.7.0)(jest@29.7.0(@types/node@22.15.30))
- jest-runner: 29.7.0
- jest-serializer-html: 7.1.0
- jest-watch-typeahead: 2.2.2(jest@29.7.0(@types/node@22.15.30))
- nyc: 15.1.0
- playwright: 1.52.0
- storybook: 8.6.14(prettier@3.5.3)
- transitivePeerDependencies:
- - '@swc/helpers'
- - '@types/node'
- - babel-plugin-macros
- - debug
- - node-notifier
- - supports-color
- - ts-node
-
- '@storybook/test@8.6.14(storybook@8.6.14(prettier@3.5.3))':
- dependencies:
- '@storybook/global': 5.0.0
- '@storybook/instrumenter': 8.6.14(storybook@8.6.14(prettier@3.5.3))
- '@testing-library/dom': 10.4.0
- '@testing-library/jest-dom': 6.5.0
- '@testing-library/user-event': 14.5.2(@testing-library/dom@10.4.0)
- '@vitest/expect': 2.0.5
- '@vitest/spy': 2.0.5
- storybook: 8.6.14(prettier@3.5.3)
-
- '@storybook/theming@8.6.14(storybook@8.6.14(prettier@3.5.3))':
- dependencies:
- storybook: 8.6.14(prettier@3.5.3)
-
'@supabase/auth-js@2.70.0':
dependencies:
'@supabase/node-fetch': 2.6.15
@@ -10731,68 +9808,34 @@ snapshots:
- bufferutil
- utf-8-validate
- '@swc/core-darwin-arm64@1.11.31':
- optional: true
-
- '@swc/core-darwin-x64@1.11.31':
- optional: true
-
- '@swc/core-linux-arm-gnueabihf@1.11.31':
- optional: true
-
- '@swc/core-linux-arm64-gnu@1.11.31':
- optional: true
-
- '@swc/core-linux-arm64-musl@1.11.31':
- optional: true
-
- '@swc/core-linux-x64-gnu@1.11.31':
- optional: true
-
- '@swc/core-linux-x64-musl@1.11.31':
- optional: true
-
- '@swc/core-win32-arm64-msvc@1.11.31':
- optional: true
-
- '@swc/core-win32-ia32-msvc@1.11.31':
- optional: true
-
- '@swc/core-win32-x64-msvc@1.11.31':
- optional: true
-
- '@swc/core@1.11.31':
- dependencies:
- '@swc/counter': 0.1.3
- '@swc/types': 0.1.22
- optionalDependencies:
- '@swc/core-darwin-arm64': 1.11.31
- '@swc/core-darwin-x64': 1.11.31
- '@swc/core-linux-arm-gnueabihf': 1.11.31
- '@swc/core-linux-arm64-gnu': 1.11.31
- '@swc/core-linux-arm64-musl': 1.11.31
- '@swc/core-linux-x64-gnu': 1.11.31
- '@swc/core-linux-x64-musl': 1.11.31
- '@swc/core-win32-arm64-msvc': 1.11.31
- '@swc/core-win32-ia32-msvc': 1.11.31
- '@swc/core-win32-x64-msvc': 1.11.31
-
'@swc/counter@0.1.3': {}
'@swc/helpers@0.5.15':
dependencies:
tslib: 2.8.1
- '@swc/jest@0.2.38(@swc/core@1.11.31)':
+ '@tanstack/eslint-plugin-query@5.78.0(eslint@8.57.1)(typescript@5.8.3)':
dependencies:
- '@jest/create-cache-key-function': 29.7.0
- '@swc/core': 1.11.31
- '@swc/counter': 0.1.3
- jsonc-parser: 3.3.1
+ '@typescript-eslint/utils': 8.34.1(eslint@8.57.1)(typescript@5.8.3)
+ eslint: 8.57.1
+ transitivePeerDependencies:
+ - supports-color
+ - typescript
- '@swc/types@0.1.22':
+ '@tanstack/query-core@5.80.7': {}
+
+ '@tanstack/query-devtools@5.80.0': {}
+
+ '@tanstack/react-query-devtools@5.80.10(@tanstack/react-query@5.80.7(react@18.3.1))(react@18.3.1)':
dependencies:
- '@swc/counter': 0.1.3
+ '@tanstack/query-devtools': 5.80.0
+ '@tanstack/react-query': 5.80.7(react@18.3.1)
+ react: 18.3.1
+
+ '@tanstack/react-query@5.80.7(react@18.3.1)':
+ dependencies:
+ '@tanstack/query-core': 5.80.7
+ react: 18.3.1
'@tanstack/react-table@8.21.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
@@ -10813,7 +9856,7 @@ snapshots:
lz-string: 1.5.0
pretty-format: 27.5.1
- '@testing-library/jest-dom@6.5.0':
+ '@testing-library/jest-dom@6.6.3':
dependencies:
'@adobe/css-tools': 4.4.3
aria-query: 5.3.2
@@ -10823,7 +9866,7 @@ snapshots:
lodash: 4.17.21
redent: 3.0.0
- '@testing-library/user-event@14.5.2(@testing-library/dom@10.4.0)':
+ '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.0)':
dependencies:
'@testing-library/dom': 10.4.0
@@ -10908,6 +9951,10 @@ snapshots:
'@types/doctrine@0.0.9': {}
+ '@types/es-aggregate-error@1.0.6':
+ dependencies:
+ '@types/node': 22.15.30
+
'@types/eslint-scope@3.7.7':
dependencies:
'@types/eslint': 9.6.1
@@ -10920,34 +9967,18 @@ snapshots:
'@types/estree-jsx@1.0.5':
dependencies:
- '@types/estree': 1.0.7
+ '@types/estree': 1.0.8
'@types/estree@1.0.6': {}
- '@types/estree@1.0.7': {}
-
'@types/estree@1.0.8': {}
- '@types/graceful-fs@4.1.9':
- dependencies:
- '@types/node': 22.15.30
-
'@types/hast@3.0.4':
dependencies:
'@types/unist': 3.0.3
'@types/html-minifier-terser@6.1.0': {}
- '@types/istanbul-lib-coverage@2.0.6': {}
-
- '@types/istanbul-lib-report@3.0.3':
- dependencies:
- '@types/istanbul-lib-coverage': 2.0.6
-
- '@types/istanbul-reports@3.0.4':
- dependencies:
- '@types/istanbul-lib-report': 3.0.3
-
'@types/jaro-winkler@0.2.4': {}
'@types/json-schema@7.0.15': {}
@@ -10956,7 +9987,7 @@ snapshots:
'@types/junit-report-builder@3.0.2': {}
- '@types/lodash@4.17.17': {}
+ '@types/lodash@4.17.18': {}
'@types/mdast@4.0.4':
dependencies:
@@ -10990,7 +10021,7 @@ snapshots:
'@types/phoenix@1.6.6': {}
- '@types/prop-types@15.7.14': {}
+ '@types/prop-types@15.7.15': {}
'@types/react-dom@18.3.5(@types/react@18.3.17)':
dependencies:
@@ -11002,7 +10033,7 @@ snapshots:
'@types/react@18.3.17':
dependencies:
- '@types/prop-types': 15.7.14
+ '@types/prop-types': 15.7.15
csstype: 3.1.3
'@types/resolve@1.20.6': {}
@@ -11011,8 +10042,6 @@ snapshots:
'@types/shimmer@1.2.0': {}
- '@types/stack-utils@2.0.3': {}
-
'@types/statuses@2.0.6': {}
'@types/stylis@4.2.5': {}
@@ -11027,30 +10056,20 @@ snapshots:
'@types/unist@3.0.3': {}
- '@types/uuid@9.0.8': {}
-
- '@types/wait-on@5.3.4':
- dependencies:
- '@types/node': 22.15.30
+ '@types/urijs@1.19.25': {}
'@types/ws@8.18.1':
dependencies:
'@types/node': 22.15.30
- '@types/yargs-parser@21.0.3': {}
-
- '@types/yargs@17.0.33':
- dependencies:
- '@types/yargs-parser': 21.0.3
-
- '@typescript-eslint/eslint-plugin@8.33.1(@typescript-eslint/parser@8.33.1(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3)':
+ '@typescript-eslint/eslint-plugin@8.34.1(@typescript-eslint/parser@8.34.1(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3)':
dependencies:
'@eslint-community/regexpp': 4.12.1
- '@typescript-eslint/parser': 8.33.1(eslint@8.57.1)(typescript@5.8.3)
- '@typescript-eslint/scope-manager': 8.33.1
- '@typescript-eslint/type-utils': 8.33.1(eslint@8.57.1)(typescript@5.8.3)
- '@typescript-eslint/utils': 8.33.1(eslint@8.57.1)(typescript@5.8.3)
- '@typescript-eslint/visitor-keys': 8.33.1
+ '@typescript-eslint/parser': 8.34.1(eslint@8.57.1)(typescript@5.8.3)
+ '@typescript-eslint/scope-manager': 8.34.1
+ '@typescript-eslint/type-utils': 8.34.1(eslint@8.57.1)(typescript@5.8.3)
+ '@typescript-eslint/utils': 8.34.1(eslint@8.57.1)(typescript@5.8.3)
+ '@typescript-eslint/visitor-keys': 8.34.1
eslint: 8.57.1
graphemer: 1.4.0
ignore: 7.0.5
@@ -11060,40 +10079,40 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/parser@8.33.1(eslint@8.57.1)(typescript@5.8.3)':
+ '@typescript-eslint/parser@8.34.1(eslint@8.57.1)(typescript@5.8.3)':
dependencies:
- '@typescript-eslint/scope-manager': 8.33.1
- '@typescript-eslint/types': 8.33.1
- '@typescript-eslint/typescript-estree': 8.33.1(typescript@5.8.3)
- '@typescript-eslint/visitor-keys': 8.33.1
+ '@typescript-eslint/scope-manager': 8.34.1
+ '@typescript-eslint/types': 8.34.1
+ '@typescript-eslint/typescript-estree': 8.34.1(typescript@5.8.3)
+ '@typescript-eslint/visitor-keys': 8.34.1
debug: 4.4.1
eslint: 8.57.1
typescript: 5.8.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/project-service@8.33.1(typescript@5.8.3)':
+ '@typescript-eslint/project-service@8.34.1(typescript@5.8.3)':
dependencies:
- '@typescript-eslint/tsconfig-utils': 8.33.1(typescript@5.8.3)
- '@typescript-eslint/types': 8.33.1
+ '@typescript-eslint/tsconfig-utils': 8.34.1(typescript@5.8.3)
+ '@typescript-eslint/types': 8.34.1
debug: 4.4.1
typescript: 5.8.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/scope-manager@8.33.1':
+ '@typescript-eslint/scope-manager@8.34.1':
dependencies:
- '@typescript-eslint/types': 8.33.1
- '@typescript-eslint/visitor-keys': 8.33.1
+ '@typescript-eslint/types': 8.34.1
+ '@typescript-eslint/visitor-keys': 8.34.1
- '@typescript-eslint/tsconfig-utils@8.33.1(typescript@5.8.3)':
+ '@typescript-eslint/tsconfig-utils@8.34.1(typescript@5.8.3)':
dependencies:
typescript: 5.8.3
- '@typescript-eslint/type-utils@8.33.1(eslint@8.57.1)(typescript@5.8.3)':
+ '@typescript-eslint/type-utils@8.34.1(eslint@8.57.1)(typescript@5.8.3)':
dependencies:
- '@typescript-eslint/typescript-estree': 8.33.1(typescript@5.8.3)
- '@typescript-eslint/utils': 8.33.1(eslint@8.57.1)(typescript@5.8.3)
+ '@typescript-eslint/typescript-estree': 8.34.1(typescript@5.8.3)
+ '@typescript-eslint/utils': 8.34.1(eslint@8.57.1)(typescript@5.8.3)
debug: 4.4.1
eslint: 8.57.1
ts-api-utils: 2.1.0(typescript@5.8.3)
@@ -11101,14 +10120,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/types@8.33.1': {}
+ '@typescript-eslint/types@8.34.1': {}
- '@typescript-eslint/typescript-estree@8.33.1(typescript@5.8.3)':
+ '@typescript-eslint/typescript-estree@8.34.1(typescript@5.8.3)':
dependencies:
- '@typescript-eslint/project-service': 8.33.1(typescript@5.8.3)
- '@typescript-eslint/tsconfig-utils': 8.33.1(typescript@5.8.3)
- '@typescript-eslint/types': 8.33.1
- '@typescript-eslint/visitor-keys': 8.33.1
+ '@typescript-eslint/project-service': 8.34.1(typescript@5.8.3)
+ '@typescript-eslint/tsconfig-utils': 8.34.1(typescript@5.8.3)
+ '@typescript-eslint/types': 8.34.1
+ '@typescript-eslint/visitor-keys': 8.34.1
debug: 4.4.1
fast-glob: 3.3.3
is-glob: 4.0.3
@@ -11119,108 +10138,103 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/utils@8.33.1(eslint@8.57.1)(typescript@5.8.3)':
+ '@typescript-eslint/utils@8.34.1(eslint@8.57.1)(typescript@5.8.3)':
dependencies:
'@eslint-community/eslint-utils': 4.7.0(eslint@8.57.1)
- '@typescript-eslint/scope-manager': 8.33.1
- '@typescript-eslint/types': 8.33.1
- '@typescript-eslint/typescript-estree': 8.33.1(typescript@5.8.3)
+ '@typescript-eslint/scope-manager': 8.34.1
+ '@typescript-eslint/types': 8.34.1
+ '@typescript-eslint/typescript-estree': 8.34.1(typescript@5.8.3)
eslint: 8.57.1
typescript: 5.8.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/visitor-keys@8.33.1':
+ '@typescript-eslint/visitor-keys@8.34.1':
dependencies:
- '@typescript-eslint/types': 8.33.1
- eslint-visitor-keys: 4.2.0
+ '@typescript-eslint/types': 8.34.1
+ eslint-visitor-keys: 4.2.1
'@ungap/structured-clone@1.3.0': {}
- '@unrs/resolver-binding-darwin-arm64@1.7.10':
+ '@unrs/resolver-binding-android-arm-eabi@1.9.0':
optional: true
- '@unrs/resolver-binding-darwin-x64@1.7.10':
+ '@unrs/resolver-binding-android-arm64@1.9.0':
optional: true
- '@unrs/resolver-binding-freebsd-x64@1.7.10':
+ '@unrs/resolver-binding-darwin-arm64@1.9.0':
optional: true
- '@unrs/resolver-binding-linux-arm-gnueabihf@1.7.10':
+ '@unrs/resolver-binding-darwin-x64@1.9.0':
optional: true
- '@unrs/resolver-binding-linux-arm-musleabihf@1.7.10':
+ '@unrs/resolver-binding-freebsd-x64@1.9.0':
optional: true
- '@unrs/resolver-binding-linux-arm64-gnu@1.7.10':
+ '@unrs/resolver-binding-linux-arm-gnueabihf@1.9.0':
optional: true
- '@unrs/resolver-binding-linux-arm64-musl@1.7.10':
+ '@unrs/resolver-binding-linux-arm-musleabihf@1.9.0':
optional: true
- '@unrs/resolver-binding-linux-ppc64-gnu@1.7.10':
+ '@unrs/resolver-binding-linux-arm64-gnu@1.9.0':
optional: true
- '@unrs/resolver-binding-linux-riscv64-gnu@1.7.10':
+ '@unrs/resolver-binding-linux-arm64-musl@1.9.0':
optional: true
- '@unrs/resolver-binding-linux-riscv64-musl@1.7.10':
+ '@unrs/resolver-binding-linux-ppc64-gnu@1.9.0':
optional: true
- '@unrs/resolver-binding-linux-s390x-gnu@1.7.10':
+ '@unrs/resolver-binding-linux-riscv64-gnu@1.9.0':
optional: true
- '@unrs/resolver-binding-linux-x64-gnu@1.7.10':
+ '@unrs/resolver-binding-linux-riscv64-musl@1.9.0':
optional: true
- '@unrs/resolver-binding-linux-x64-musl@1.7.10':
+ '@unrs/resolver-binding-linux-s390x-gnu@1.9.0':
optional: true
- '@unrs/resolver-binding-wasm32-wasi@1.7.10':
+ '@unrs/resolver-binding-linux-x64-gnu@1.9.0':
+ optional: true
+
+ '@unrs/resolver-binding-linux-x64-musl@1.9.0':
+ optional: true
+
+ '@unrs/resolver-binding-wasm32-wasi@1.9.0':
dependencies:
- '@napi-rs/wasm-runtime': 0.2.10
+ '@napi-rs/wasm-runtime': 0.2.11
optional: true
- '@unrs/resolver-binding-win32-arm64-msvc@1.7.10':
+ '@unrs/resolver-binding-win32-arm64-msvc@1.9.0':
optional: true
- '@unrs/resolver-binding-win32-ia32-msvc@1.7.10':
+ '@unrs/resolver-binding-win32-ia32-msvc@1.9.0':
optional: true
- '@unrs/resolver-binding-win32-x64-msvc@1.7.10':
+ '@unrs/resolver-binding-win32-x64-msvc@1.9.0':
optional: true
- '@vitest/expect@2.0.5':
+ '@vitest/expect@3.0.9':
dependencies:
- '@vitest/spy': 2.0.5
- '@vitest/utils': 2.0.5
+ '@vitest/spy': 3.0.9
+ '@vitest/utils': 3.0.9
chai: 5.2.0
- tinyrainbow: 1.2.0
+ tinyrainbow: 2.0.0
- '@vitest/pretty-format@2.0.5':
+ '@vitest/pretty-format@3.0.9':
dependencies:
- tinyrainbow: 1.2.0
+ tinyrainbow: 2.0.0
- '@vitest/pretty-format@2.1.9':
- dependencies:
- tinyrainbow: 1.2.0
-
- '@vitest/spy@2.0.5':
+ '@vitest/spy@3.0.9':
dependencies:
tinyspy: 3.0.2
- '@vitest/utils@2.0.5':
+ '@vitest/utils@3.0.9':
dependencies:
- '@vitest/pretty-format': 2.0.5
- estree-walker: 3.0.3
- loupe: 3.1.3
- tinyrainbow: 1.2.0
-
- '@vitest/utils@2.1.9':
- dependencies:
- '@vitest/pretty-format': 2.1.9
- loupe: 3.1.3
- tinyrainbow: 1.2.0
+ '@vitest/pretty-format': 3.0.9
+ loupe: 3.1.4
+ tinyrainbow: 2.0.0
'@webassemblyjs/ast@1.14.1':
dependencies:
@@ -11302,13 +10316,13 @@ snapshots:
'@xtuc/long@4.2.2': {}
- '@xyflow/react@12.6.4(@types/react@18.3.17)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@xyflow/react@12.6.4(@types/react@18.3.17)(immer@9.0.21)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@xyflow/system': 0.0.61
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)(react@18.3.1)
+ zustand: 4.5.7(@types/react@18.3.17)(immer@9.0.21)(react@18.3.1)
transitivePeerDependencies:
- '@types/react'
- immer
@@ -11331,11 +10345,9 @@ snapshots:
dependencies:
acorn: 8.15.0
- acorn-jsx@5.3.2(acorn@8.14.1):
+ acorn-jsx@5.3.2(acorn@8.15.0):
dependencies:
- acorn: 8.14.1
-
- acorn@8.14.1: {}
+ acorn: 8.15.0
acorn@8.15.0: {}
@@ -11350,10 +10362,13 @@ snapshots:
transitivePeerDependencies:
- supports-color
- aggregate-error@3.1.0:
+ ajv-draft-04@1.0.0(ajv@8.17.1):
+ optionalDependencies:
+ ajv: 8.17.1
+
+ ajv-errors@3.0.0(ajv@8.17.1):
dependencies:
- clean-stack: 2.2.0
- indent-string: 4.0.0
+ ajv: 8.17.1
ajv-formats@2.1.1(ajv@8.17.1):
optionalDependencies:
@@ -11382,12 +10397,12 @@ snapshots:
json-schema-traverse: 1.0.0
require-from-string: 2.0.2
+ ansi-colors@4.1.3: {}
+
ansi-escapes@4.3.2:
dependencies:
type-fest: 0.21.3
- ansi-escapes@6.2.1: {}
-
ansi-html-community@0.0.8: {}
ansi-html@0.0.9: {}
@@ -11396,10 +10411,6 @@ snapshots:
ansi-regex@6.1.0: {}
- ansi-styles@3.2.1:
- dependencies:
- color-convert: 1.9.3
-
ansi-styles@4.3.0:
dependencies:
color-convert: 2.0.1
@@ -11415,18 +10426,8 @@ snapshots:
normalize-path: 3.0.0
picomatch: 2.3.1
- append-transform@2.0.0:
- dependencies:
- default-require-extensions: 3.0.1
-
- archy@1.0.0: {}
-
arg@5.0.2: {}
- argparse@1.0.10:
- dependencies:
- sprintf-js: 1.0.3
-
argparse@2.0.1: {}
aria-hidden@1.2.6:
@@ -11455,6 +10456,8 @@ snapshots:
is-string: 1.1.1
math-intrinsics: 1.1.0
+ array-union@2.1.0: {}
+
array.prototype.findlast@1.2.5:
dependencies:
call-bind: 1.0.8
@@ -11528,9 +10531,9 @@ snapshots:
dependencies:
tslib: 2.8.1
- async-function@1.0.0: {}
+ astring@1.9.0: {}
- asynckit@0.4.0: {}
+ async-function@1.0.0: {}
available-typed-arrays@1.0.7:
dependencies:
@@ -11543,61 +10546,23 @@ snapshots:
axe-core: 4.10.3
mustache: 4.2.0
- axe-playwright@2.1.0(playwright@1.52.0):
+ axe-playwright@2.1.0(playwright@1.53.1):
dependencies:
'@types/junit-report-builder': 3.0.2
axe-core: 4.10.3
axe-html-reporter: 2.2.11(axe-core@4.10.3)
junit-report-builder: 5.1.1
picocolors: 1.1.1
- playwright: 1.52.0
-
- axios@1.9.0:
- dependencies:
- follow-redirects: 1.15.9
- form-data: 4.0.3
- proxy-from-env: 1.1.0
- transitivePeerDependencies:
- - debug
+ playwright: 1.53.1
axobject-query@4.1.0: {}
- babel-jest@29.7.0(@babel/core@7.27.4):
- dependencies:
- '@babel/core': 7.27.4
- '@jest/transform': 29.7.0
- '@types/babel__core': 7.20.5
- babel-plugin-istanbul: 6.1.1
- babel-preset-jest: 29.6.3(@babel/core@7.27.4)
- chalk: 4.1.2
- graceful-fs: 4.2.11
- slash: 3.0.0
- transitivePeerDependencies:
- - supports-color
-
- babel-loader@9.2.1(@babel/core@7.27.4)(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2)):
+ babel-loader@9.2.1(@babel/core@7.27.4)(webpack@5.99.9(esbuild@0.25.5)):
dependencies:
'@babel/core': 7.27.4
find-cache-dir: 4.0.0
schema-utils: 4.3.2
- webpack: 5.99.9(@swc/core@1.11.31)(esbuild@0.24.2)
-
- babel-plugin-istanbul@6.1.1:
- dependencies:
- '@babel/helper-plugin-utils': 7.27.1
- '@istanbuljs/load-nyc-config': 1.1.0
- '@istanbuljs/schema': 0.1.3
- istanbul-lib-instrument: 5.2.1
- test-exclude: 6.0.0
- transitivePeerDependencies:
- - supports-color
-
- babel-plugin-jest-hoist@29.6.3:
- dependencies:
- '@babel/template': 7.27.2
- '@babel/types': 7.27.6
- '@types/babel__core': 7.20.5
- '@types/babel__traverse': 7.20.7
+ webpack: 5.99.9(esbuild@0.25.5)
babel-plugin-polyfill-corejs2@0.4.13(@babel/core@7.27.4):
dependencies:
@@ -11612,7 +10577,7 @@ snapshots:
dependencies:
'@babel/core': 7.27.4
'@babel/helper-define-polyfill-provider': 0.6.4(@babel/core@7.27.4)
- core-js-compat: 3.42.0
+ core-js-compat: 3.43.0
transitivePeerDependencies:
- supports-color
@@ -11623,31 +10588,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- babel-preset-current-node-syntax@1.1.0(@babel/core@7.27.4):
- dependencies:
- '@babel/core': 7.27.4
- '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.27.4)
- '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.27.4)
- '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.27.4)
- '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.27.4)
- '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.27.4)
- '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.27.4)
- '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.27.4)
- '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.27.4)
- '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.27.4)
- '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.27.4)
- '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.27.4)
- '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.27.4)
- '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.27.4)
- '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.27.4)
- '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.27.4)
-
- babel-preset-jest@29.6.3(@babel/core@7.27.4):
- dependencies:
- '@babel/core': 7.27.4
- babel-plugin-jest-hoist: 29.6.3
- babel-preset-current-node-syntax: 1.1.0(@babel/core@7.27.4)
-
bail@2.0.2: {}
balanced-match@1.0.2: {}
@@ -11670,12 +10610,12 @@ snapshots:
boring-avatars@1.11.2: {}
- brace-expansion@1.1.11:
+ brace-expansion@1.1.12:
dependencies:
balanced-match: 1.0.2
concat-map: 0.0.1
- brace-expansion@2.0.1:
+ brace-expansion@2.0.2:
dependencies:
balanced-match: 1.0.2
@@ -11685,8 +10625,6 @@ snapshots:
brorand@1.1.0: {}
- browser-assert@1.2.1: {}
-
browserify-aes@1.2.0:
dependencies:
buffer-xor: 1.0.3
@@ -11734,15 +10672,11 @@ snapshots:
browserslist@4.25.0:
dependencies:
- caniuse-lite: 1.0.30001721
- electron-to-chromium: 1.5.165
+ caniuse-lite: 1.0.30001723
+ electron-to-chromium: 1.5.169
node-releases: 2.0.19
update-browserslist-db: 1.1.3(browserslist@4.25.0)
- bser@2.1.1:
- dependencies:
- node-int64: 0.4.0
-
buffer-from@1.1.2: {}
buffer-xor@1.0.3: {}
@@ -11758,12 +10692,7 @@ snapshots:
dependencies:
streamsearch: 1.1.0
- caching-transform@4.0.0:
- dependencies:
- hasha: 5.2.2
- make-dir: 3.1.0
- package-hash: 4.0.0
- write-file-atomic: 3.0.3
+ cac@6.7.14: {}
call-bind-apply-helpers@1.0.2:
dependencies:
@@ -11782,6 +10711,8 @@ snapshots:
call-bind-apply-helpers: 1.0.2
get-intrinsic: 1.3.0
+ call-me-maybe@1.0.2: {}
+
callsites@3.1.0: {}
camel-case@4.1.2:
@@ -11791,13 +10722,9 @@ snapshots:
camelcase-css@2.0.1: {}
- camelcase@5.3.1: {}
-
- camelcase@6.3.0: {}
-
camelize@1.0.1: {}
- caniuse-lite@1.0.30001721: {}
+ caniuse-lite@1.0.30001723: {}
case-sensitive-paths-webpack-plugin@2.4.0: {}
@@ -11808,15 +10735,9 @@ snapshots:
assertion-error: 2.0.1
check-error: 2.1.1
deep-eql: 5.0.2
- loupe: 3.1.3
+ loupe: 3.1.4
pathval: 2.0.0
- chalk@2.4.2:
- dependencies:
- ansi-styles: 3.2.1
- escape-string-regexp: 1.0.5
- supports-color: 5.5.0
-
chalk@3.0.0:
dependencies:
ansi-styles: 4.3.0
@@ -11827,12 +10748,6 @@ snapshots:
ansi-styles: 4.3.0
supports-color: 7.2.0
- chalk@5.4.1: {}
-
- char-regex@1.0.2: {}
-
- char-regex@2.0.2: {}
-
character-entities-html4@2.1.0: {}
character-entities-legacy@3.0.0: {}
@@ -11855,11 +10770,15 @@ snapshots:
optionalDependencies:
fsevents: 2.3.3
+ chokidar@4.0.3:
+ dependencies:
+ readdirp: 4.1.2
+
chromatic@11.25.2: {}
- chrome-trace-event@1.0.4: {}
+ chromatic@12.2.0: {}
- ci-info@3.9.0: {}
+ chrome-trace-event@1.0.4: {}
cipher-base@1.0.6:
dependencies:
@@ -11878,18 +10797,10 @@ snapshots:
dependencies:
source-map: 0.6.1
- clean-stack@2.2.0: {}
-
cli-width@4.1.0: {}
client-only@0.0.1: {}
- cliui@6.0.0:
- dependencies:
- string-width: 4.2.3
- strip-ansi: 6.0.1
- wrap-ansi: 6.2.0
-
cliui@8.0.1:
dependencies:
string-width: 4.2.3
@@ -11910,20 +10821,10 @@ snapshots:
- '@types/react'
- '@types/react-dom'
- co@4.6.0: {}
-
- collect-v8-coverage@1.0.2: {}
-
- color-convert@1.9.3:
- dependencies:
- color-name: 1.1.3
-
color-convert@2.0.1:
dependencies:
color-name: 1.1.4
- color-name@1.1.3: {}
-
color-name@1.1.4: {}
color-string@1.9.1:
@@ -11940,18 +10841,10 @@ snapshots:
colorette@2.0.20: {}
- combined-stream@1.0.8:
- dependencies:
- delayed-stream: 1.0.0
-
comma-separated-tokens@2.0.3: {}
- commander@12.1.0: {}
-
commander@2.20.3: {}
- commander@3.0.2: {}
-
commander@4.1.1: {}
commander@8.3.0: {}
@@ -11960,6 +10853,8 @@ snapshots:
commondir@1.0.1: {}
+ compare-versions@6.1.1: {}
+
concat-map@0.0.1: {}
concurrently@9.1.2:
@@ -11984,11 +10879,11 @@ snapshots:
cookie@1.0.2: {}
- core-js-compat@3.42.0:
+ core-js-compat@3.43.0:
dependencies:
browserslist: 4.25.0
- core-js-pure@3.42.0: {}
+ core-js-pure@3.43.0: {}
core-util-is@1.0.3: {}
@@ -12031,21 +10926,6 @@ snapshots:
safe-buffer: 5.2.1
sha.js: 2.4.11
- create-jest@29.7.0(@types/node@22.15.30):
- dependencies:
- '@jest/types': 29.6.3
- chalk: 4.1.2
- exit: 0.1.2
- graceful-fs: 4.2.11
- jest-config: 29.7.0(@types/node@22.15.30)
- jest-util: 29.7.0
- prompts: 2.4.2
- transitivePeerDependencies:
- - '@types/node'
- - babel-plugin-macros
- - supports-color
- - ts-node
-
cross-spawn@7.0.6:
dependencies:
path-key: 3.1.1
@@ -12069,18 +10949,18 @@ snapshots:
css-color-keywords@1.0.0: {}
- css-loader@6.11.0(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2)):
+ css-loader@6.11.0(webpack@5.99.9(esbuild@0.25.5)):
dependencies:
- icss-utils: 5.1.0(postcss@8.5.4)
- postcss: 8.5.4
- postcss-modules-extract-imports: 3.1.0(postcss@8.5.4)
- postcss-modules-local-by-default: 4.2.0(postcss@8.5.4)
- postcss-modules-scope: 3.2.1(postcss@8.5.4)
- postcss-modules-values: 4.0.0(postcss@8.5.4)
+ icss-utils: 5.1.0(postcss@8.5.6)
+ postcss: 8.5.6
+ postcss-modules-extract-imports: 3.1.0(postcss@8.5.6)
+ postcss-modules-local-by-default: 4.2.0(postcss@8.5.6)
+ 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
optionalDependencies:
- webpack: 5.99.9(@swc/core@1.11.31)(esbuild@0.24.2)
+ webpack: 5.99.9(esbuild@0.25.5)
css-select@4.3.0:
dependencies:
@@ -12104,11 +10984,6 @@ snapshots:
csstype@3.1.3: {}
- cwd@0.10.0:
- dependencies:
- find-pkg: 0.1.2
- fs-exists-sync: 0.1.0
-
d3-array@3.2.4:
dependencies:
internmap: 2.0.3
@@ -12205,18 +11080,14 @@ snapshots:
dependencies:
ms: 2.1.3
- decamelize@1.2.0: {}
-
decimal.js-light@2.5.1: {}
- decode-named-character-reference@1.1.0:
+ decode-named-character-reference@1.2.0:
dependencies:
character-entities: 2.0.2
dedent@0.7.0: {}
- dedent@1.6.0: {}
-
deep-eql@5.0.2: {}
deep-is@0.1.4: {}
@@ -12225,10 +11096,6 @@ snapshots:
deepmerge@4.3.1: {}
- default-require-extensions@3.0.1:
- dependencies:
- strip-bom: 4.0.0
-
define-data-property@1.1.4:
dependencies:
es-define-property: 1.0.1
@@ -12243,7 +11110,7 @@ snapshots:
has-property-descriptors: 1.0.2
object-keys: 1.1.1
- delayed-stream@1.0.0: {}
+ dependency-graph@0.11.0: {}
dequal@2.0.3: {}
@@ -12255,8 +11122,6 @@ snapshots:
detect-libc@2.0.4:
optional: true
- detect-newline@3.1.0: {}
-
detect-node-es@1.1.0: {}
devlop@1.1.0:
@@ -12265,18 +11130,16 @@ snapshots:
didyoumean@1.2.2: {}
- diff-sequences@29.6.3: {}
-
- diffable-html@4.1.0:
- dependencies:
- htmlparser2: 3.10.1
-
diffie-hellman@5.0.3:
dependencies:
bn.js: 4.12.2
miller-rabin: 4.0.1
randombytes: 2.1.0
+ dir-glob@3.0.1:
+ dependencies:
+ path-type: 4.0.0
+
dlv@1.1.3: {}
doctrine@2.1.0:
@@ -12300,11 +11163,6 @@ snapshots:
'@babel/runtime': 7.27.6
csstype: 3.1.3
- dom-serializer@0.2.2:
- dependencies:
- domelementtype: 2.3.0
- entities: 2.2.0
-
dom-serializer@1.4.1:
dependencies:
domelementtype: 2.3.0
@@ -12313,23 +11171,12 @@ snapshots:
domain-browser@4.23.0: {}
- domelementtype@1.3.1: {}
-
domelementtype@2.3.0: {}
- domhandler@2.4.2:
- dependencies:
- domelementtype: 1.3.1
-
domhandler@4.3.1:
dependencies:
domelementtype: 2.3.0
- domutils@1.7.0:
- dependencies:
- dom-serializer: 0.2.2
- domelementtype: 1.3.1
-
domutils@2.8.0:
dependencies:
dom-serializer: 1.4.1
@@ -12351,7 +11198,7 @@ snapshots:
eastasianwidth@0.2.0: {}
- electron-to-chromium@1.5.165: {}
+ electron-to-chromium@1.5.169: {}
elliptic@6.6.1:
dependencies:
@@ -12375,8 +11222,6 @@ snapshots:
embla-carousel@8.6.0: {}
- emittery@0.13.1: {}
-
emoji-regex@8.0.0: {}
emoji-regex@9.2.2: {}
@@ -12394,10 +11239,15 @@ snapshots:
graceful-fs: 4.2.11
tapable: 2.2.2
- entities@1.1.2: {}
+ enquirer@2.4.1:
+ dependencies:
+ ansi-colors: 4.1.3
+ strip-ansi: 6.0.1
entities@2.2.0: {}
+ entities@4.5.0: {}
+
env-paths@2.2.1: {}
error-ex@1.3.2:
@@ -12465,6 +11315,17 @@ snapshots:
unbox-primitive: 1.1.0
which-typed-array: 1.1.19
+ es-aggregate-error@1.0.14:
+ dependencies:
+ define-data-property: 1.1.4
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+ globalthis: 1.0.4
+ has-property-descriptors: 1.0.2
+ set-function-name: 2.0.2
+
es-define-property@1.0.1: {}
es-errors@1.3.0: {}
@@ -12511,61 +11372,57 @@ snapshots:
is-date-object: 1.1.0
is-symbol: 1.1.1
- es6-error@4.1.1: {}
+ es6-promise@3.3.1: {}
- esbuild-register@3.6.0(esbuild@0.24.2):
+ esbuild-register@3.6.0(esbuild@0.25.5):
dependencies:
debug: 4.4.1
- esbuild: 0.24.2
+ esbuild: 0.25.5
transitivePeerDependencies:
- supports-color
- esbuild@0.24.2:
+ esbuild@0.25.5:
optionalDependencies:
- '@esbuild/aix-ppc64': 0.24.2
- '@esbuild/android-arm': 0.24.2
- '@esbuild/android-arm64': 0.24.2
- '@esbuild/android-x64': 0.24.2
- '@esbuild/darwin-arm64': 0.24.2
- '@esbuild/darwin-x64': 0.24.2
- '@esbuild/freebsd-arm64': 0.24.2
- '@esbuild/freebsd-x64': 0.24.2
- '@esbuild/linux-arm': 0.24.2
- '@esbuild/linux-arm64': 0.24.2
- '@esbuild/linux-ia32': 0.24.2
- '@esbuild/linux-loong64': 0.24.2
- '@esbuild/linux-mips64el': 0.24.2
- '@esbuild/linux-ppc64': 0.24.2
- '@esbuild/linux-riscv64': 0.24.2
- '@esbuild/linux-s390x': 0.24.2
- '@esbuild/linux-x64': 0.24.2
- '@esbuild/netbsd-arm64': 0.24.2
- '@esbuild/netbsd-x64': 0.24.2
- '@esbuild/openbsd-arm64': 0.24.2
- '@esbuild/openbsd-x64': 0.24.2
- '@esbuild/sunos-x64': 0.24.2
- '@esbuild/win32-arm64': 0.24.2
- '@esbuild/win32-ia32': 0.24.2
- '@esbuild/win32-x64': 0.24.2
+ '@esbuild/aix-ppc64': 0.25.5
+ '@esbuild/android-arm': 0.25.5
+ '@esbuild/android-arm64': 0.25.5
+ '@esbuild/android-x64': 0.25.5
+ '@esbuild/darwin-arm64': 0.25.5
+ '@esbuild/darwin-x64': 0.25.5
+ '@esbuild/freebsd-arm64': 0.25.5
+ '@esbuild/freebsd-x64': 0.25.5
+ '@esbuild/linux-arm': 0.25.5
+ '@esbuild/linux-arm64': 0.25.5
+ '@esbuild/linux-ia32': 0.25.5
+ '@esbuild/linux-loong64': 0.25.5
+ '@esbuild/linux-mips64el': 0.25.5
+ '@esbuild/linux-ppc64': 0.25.5
+ '@esbuild/linux-riscv64': 0.25.5
+ '@esbuild/linux-s390x': 0.25.5
+ '@esbuild/linux-x64': 0.25.5
+ '@esbuild/netbsd-arm64': 0.25.5
+ '@esbuild/netbsd-x64': 0.25.5
+ '@esbuild/openbsd-arm64': 0.25.5
+ '@esbuild/openbsd-x64': 0.25.5
+ '@esbuild/sunos-x64': 0.25.5
+ '@esbuild/win32-arm64': 0.25.5
+ '@esbuild/win32-ia32': 0.25.5
+ '@esbuild/win32-x64': 0.25.5
escalade@3.2.0: {}
- escape-string-regexp@1.0.5: {}
-
- escape-string-regexp@2.0.0: {}
-
escape-string-regexp@4.0.0: {}
- eslint-config-next@15.3.3(eslint@8.57.1)(typescript@5.8.3):
+ eslint-config-next@15.3.4(eslint@8.57.1)(typescript@5.8.3):
dependencies:
- '@next/eslint-plugin-next': 15.3.3
+ '@next/eslint-plugin-next': 15.3.4
'@rushstack/eslint-patch': 1.11.0
- '@typescript-eslint/eslint-plugin': 8.33.1(@typescript-eslint/parser@8.33.1(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3)
- '@typescript-eslint/parser': 8.33.1(eslint@8.57.1)(typescript@5.8.3)
+ '@typescript-eslint/eslint-plugin': 8.34.1(@typescript-eslint/parser@8.34.1(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3)
+ '@typescript-eslint/parser': 8.34.1(eslint@8.57.1)(typescript@5.8.3)
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.1)
- eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.33.1(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
+ eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.34.1(eslint@8.57.1)(typescript@5.8.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)
@@ -12593,24 +11450,24 @@ snapshots:
is-bun-module: 2.0.0
stable-hash: 0.0.5
tinyglobby: 0.2.14
- unrs-resolver: 1.7.10
+ unrs-resolver: 1.9.0
optionalDependencies:
- eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.33.1(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
+ eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.34.1(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
transitivePeerDependencies:
- supports-color
- eslint-module-utils@2.12.0(@typescript-eslint/parser@8.33.1(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1):
+ eslint-module-utils@2.12.0(@typescript-eslint/parser@8.34.1(eslint@8.57.1)(typescript@5.8.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.33.1(eslint@8.57.1)(typescript@5.8.3)
+ '@typescript-eslint/parser': 8.34.1(eslint@8.57.1)(typescript@5.8.3)
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.1)
transitivePeerDependencies:
- supports-color
- eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.33.1(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1):
+ eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.34.1(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1):
dependencies:
'@rtsao/scc': 1.1.0
array-includes: 3.1.9
@@ -12621,7 +11478,7 @@ snapshots:
doctrine: 2.1.0
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
- eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.33.1(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
+ eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.34.1(eslint@8.57.1)(typescript@5.8.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
@@ -12633,7 +11490,7 @@ snapshots:
string.prototype.trimend: 1.0.9
tsconfig-paths: 3.15.0
optionalDependencies:
- '@typescript-eslint/parser': 8.33.1(eslint@8.57.1)(typescript@5.8.3)
+ '@typescript-eslint/parser': 8.34.1(eslint@8.57.1)(typescript@5.8.3)
transitivePeerDependencies:
- eslint-import-resolver-typescript
- eslint-import-resolver-webpack
@@ -12684,12 +11541,11 @@ snapshots:
string.prototype.matchall: 4.0.12
string.prototype.repeat: 1.0.0
- eslint-plugin-storybook@0.12.0(eslint@8.57.1)(typescript@5.8.3):
+ eslint-plugin-storybook@9.0.12(eslint@8.57.1)(storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3))(typescript@5.8.3):
dependencies:
- '@storybook/csf': 0.1.13
- '@typescript-eslint/utils': 8.33.1(eslint@8.57.1)(typescript@5.8.3)
+ '@typescript-eslint/utils': 8.34.1(eslint@8.57.1)(typescript@5.8.3)
eslint: 8.57.1
- ts-dedent: 2.2.0
+ storybook: 9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3)
transitivePeerDependencies:
- supports-color
- typescript
@@ -12706,7 +11562,7 @@ snapshots:
eslint-visitor-keys@3.4.3: {}
- eslint-visitor-keys@4.2.0: {}
+ eslint-visitor-keys@4.2.1: {}
eslint@8.57.1:
dependencies:
@@ -12753,8 +11609,8 @@ snapshots:
espree@9.6.1:
dependencies:
- acorn: 8.14.1
- acorn-jsx: 5.3.2(acorn@8.14.1)
+ acorn: 8.15.0
+ acorn-jsx: 5.3.2(acorn@8.15.0)
eslint-visitor-keys: 3.4.3
esprima@4.0.1: {}
@@ -12775,10 +11631,6 @@ snapshots:
estree-walker@2.0.2: {}
- estree-walker@3.0.3:
- dependencies:
- '@types/estree': 1.0.8
-
esutils@2.0.3: {}
event-target-shim@5.0.1: {}
@@ -12806,22 +11658,6 @@ snapshots:
exenv@1.2.2: {}
- exit@0.1.2: {}
-
- expand-tilde@1.2.2:
- dependencies:
- os-homedir: 1.0.2
-
- expect-playwright@0.8.0: {}
-
- expect@29.7.0:
- dependencies:
- '@jest/expect-utils': 29.7.0
- jest-get-type: 29.6.3
- jest-matcher-utils: 29.7.0
- jest-message-util: 29.7.0
- jest-util: 29.7.0
-
extend@3.0.2: {}
fast-deep-equal@2.0.1: {}
@@ -12852,17 +11688,17 @@ snapshots:
fast-levenshtein@2.0.6: {}
+ fast-memoize@2.5.2: {}
+
+ fast-safe-stringify@2.1.1: {}
+
fast-uri@3.0.6: {}
fastq@1.19.1:
dependencies:
reusify: 1.1.0
- fb-watchman@2.0.2:
- dependencies:
- bser: 2.1.1
-
- fdir@6.4.5(picomatch@4.0.2):
+ fdir@6.4.6(picomatch@4.0.2):
optionalDependencies:
picomatch: 4.0.2
@@ -12889,21 +11725,6 @@ snapshots:
common-path-prefix: 3.0.0
pkg-dir: 7.0.0
- find-file-up@0.1.3:
- dependencies:
- fs-exists-sync: 0.1.0
- resolve-dir: 0.1.1
-
- find-pkg@0.1.2:
- dependencies:
- find-file-up: 0.1.3
-
- find-process@1.4.10:
- dependencies:
- chalk: 4.1.2
- commander: 12.1.0
- loglevel: 1.9.2
-
find-up@4.1.0:
dependencies:
locate-path: 5.0.0
@@ -12919,6 +11740,12 @@ snapshots:
locate-path: 7.2.0
path-exists: 5.0.0
+ find-up@7.0.0:
+ dependencies:
+ locate-path: 7.2.0
+ path-exists: 5.0.0
+ unicorn-magic: 0.1.0
+
flat-cache@3.2.0:
dependencies:
flatted: 3.3.3
@@ -12927,23 +11754,16 @@ snapshots:
flatted@3.3.3: {}
- follow-redirects@1.15.9: {}
-
for-each@0.3.5:
dependencies:
is-callable: 1.2.7
- foreground-child@2.0.0:
- dependencies:
- cross-spawn: 7.0.6
- signal-exit: 3.0.7
-
foreground-child@3.3.1:
dependencies:
cross-spawn: 7.0.6
signal-exit: 4.1.0
- fork-ts-checker-webpack-plugin@8.0.0(typescript@5.8.3)(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2)):
+ fork-ts-checker-webpack-plugin@8.0.0(typescript@5.8.3)(webpack@5.99.9(esbuild@0.25.5)):
dependencies:
'@babel/code-frame': 7.27.1
chalk: 4.1.2
@@ -12958,38 +11778,32 @@ snapshots:
semver: 7.7.2
tapable: 2.2.2
typescript: 5.8.3
- webpack: 5.99.9(@swc/core@1.11.31)(esbuild@0.24.2)
-
- form-data@4.0.3:
- dependencies:
- asynckit: 0.4.0
- combined-stream: 1.0.8
- es-set-tostringtag: 2.1.0
- hasown: 2.0.2
- mime-types: 2.1.35
+ webpack: 5.99.9(esbuild@0.25.5)
forwarded-parse@2.1.2: {}
framer-motion@12.16.0(@emotion/is-prop-valid@1.2.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
- motion-dom: 12.16.0
- motion-utils: 12.12.1
+ motion-dom: 12.18.1
+ motion-utils: 12.18.1
tslib: 2.8.1
optionalDependencies:
'@emotion/is-prop-valid': 1.2.2
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- fromentries@1.3.2: {}
-
- fs-exists-sync@0.1.0: {}
-
fs-extra@10.1.0:
dependencies:
graceful-fs: 4.2.11
jsonfile: 6.1.0
universalify: 2.0.1
+ fs-extra@11.3.0:
+ dependencies:
+ graceful-fs: 4.2.11
+ jsonfile: 6.1.0
+ universalify: 2.0.1
+
fs-monkey@1.0.6: {}
fs.realpath@1.0.0: {}
@@ -13013,9 +11827,9 @@ snapshots:
functions-have-names@1.2.3: {}
- geist@1.4.2(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)):
+ geist@1.4.2(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)):
dependencies:
- next: 15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ next: 15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
gensync@1.0.0-beta.2: {}
@@ -13036,8 +11850,6 @@ snapshots:
get-nonce@1.0.1: {}
- get-package-type@0.1.0: {}
-
get-proto@1.0.1:
dependencies:
dunder-proto: 1.0.1
@@ -13090,18 +11902,6 @@ snapshots:
minipass: 4.2.8
path-scurry: 1.11.1
- global-modules@0.2.3:
- dependencies:
- global-prefix: 0.1.5
- is-windows: 0.2.0
-
- global-prefix@0.1.5:
- dependencies:
- homedir-polyfill: 1.0.3
- ini: 1.3.8
- is-windows: 0.2.0
- which: 1.3.1
-
globals@11.12.0: {}
globals@13.24.0:
@@ -13113,6 +11913,15 @@ snapshots:
define-properties: 1.2.1
gopd: 1.2.0
+ globby@11.1.0:
+ dependencies:
+ array-union: 2.1.0
+ dir-glob: 3.0.1
+ fast-glob: 3.3.3
+ ignore: 5.3.2
+ merge2: 1.4.1
+ slash: 3.0.0
+
gopd@1.2.0: {}
graceful-fs@4.2.11: {}
@@ -13123,8 +11932,6 @@ snapshots:
has-bigints@1.1.0: {}
- has-flag@3.0.0: {}
-
has-flag@4.0.0: {}
has-property-descriptors@1.0.2:
@@ -13151,18 +11958,13 @@ snapshots:
inherits: 2.0.4
minimalistic-assert: 1.0.1
- hasha@5.2.2:
- dependencies:
- is-stream: 2.0.1
- type-fest: 0.8.1
-
hasown@2.0.2:
dependencies:
function-bind: 1.1.2
hast-util-to-jsx-runtime@2.3.6:
dependencies:
- '@types/estree': 1.0.7
+ '@types/estree': 1.0.8
'@types/hast': 3.0.4
'@types/unist': 3.0.3
comma-separated-tokens: 2.0.3
@@ -13174,7 +11976,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.16
+ style-to-js: 1.1.17
unist-util-position: 5.0.0
vfile-message: 4.0.2
transitivePeerDependencies:
@@ -13198,14 +12000,8 @@ snapshots:
dependencies:
react-is: 16.13.1
- homedir-polyfill@1.0.3:
- dependencies:
- parse-passwd: 1.0.0
-
html-entities@2.6.0: {}
- html-escaper@2.0.2: {}
-
html-minifier-terser@6.1.0:
dependencies:
camel-case: 4.1.2
@@ -13214,11 +12010,11 @@ snapshots:
he: 1.2.0
param-case: 3.0.4
relateurl: 0.2.7
- terser: 5.41.0
+ terser: 5.42.0
html-url-attributes@3.0.1: {}
- html-webpack-plugin@5.6.3(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2)):
+ html-webpack-plugin@5.6.3(webpack@5.99.9(esbuild@0.25.5)):
dependencies:
'@types/html-minifier-terser': 6.1.0
html-minifier-terser: 6.1.0
@@ -13226,16 +12022,7 @@ snapshots:
pretty-error: 4.0.0
tapable: 2.2.2
optionalDependencies:
- webpack: 5.99.9(@swc/core@1.11.31)(esbuild@0.24.2)
-
- htmlparser2@3.10.1:
- dependencies:
- domelementtype: 1.3.1
- domhandler: 2.4.2
- domutils: 1.7.0
- entities: 1.1.2
- inherits: 2.0.4
- readable-stream: 3.6.2
+ webpack: 5.99.9(esbuild@0.25.5)
htmlparser2@6.1.0:
dependencies:
@@ -13244,6 +12031,8 @@ snapshots:
domutils: 2.8.0
entities: 2.2.0
+ http2-client@1.3.5: {}
+
https-browserify@1.0.0: {}
https-proxy-agent@5.0.1:
@@ -13255,9 +12044,9 @@ snapshots:
human-signals@2.1.0: {}
- icss-utils@5.1.0(postcss@8.5.4):
+ icss-utils@5.1.0(postcss@8.5.6):
dependencies:
- postcss: 8.5.4
+ postcss: 8.5.6
ieee754@1.2.1: {}
@@ -13265,27 +12054,22 @@ snapshots:
ignore@7.0.5: {}
- image-size@1.2.1:
- dependencies:
- queue: 6.0.2
+ image-size@2.0.2: {}
+
+ immer@9.0.21: {}
import-fresh@3.3.1:
dependencies:
parent-module: 1.0.1
resolve-from: 4.0.0
- import-in-the-middle@1.14.0:
+ import-in-the-middle@1.14.2:
dependencies:
acorn: 8.15.0
acorn-import-attributes: 1.9.5(acorn@8.15.0)
cjs-module-lexer: 1.4.3
module-details-from-path: 1.0.4
- import-local@3.2.0:
- dependencies:
- pkg-dir: 4.2.0
- resolve-cwd: 3.0.0
-
imurmurhash@0.1.4: {}
indent-string@4.0.0: {}
@@ -13297,8 +12081,6 @@ snapshots:
inherits@2.0.4: {}
- ini@1.3.8: {}
-
inline-style-parser@0.2.4: {}
internal-slot@1.1.0:
@@ -13386,8 +12168,6 @@ snapshots:
is-fullwidth-code-point@3.0.0: {}
- is-generator-fn@2.1.0: {}
-
is-generator-function@1.1.0:
dependencies:
call-bound: 1.0.4
@@ -13457,8 +12237,6 @@ snapshots:
dependencies:
which-typed-array: 1.1.19
- is-typedarray@1.0.0: {}
-
is-weakmap@2.0.2: {}
is-weakref@1.1.1:
@@ -13470,10 +12248,6 @@ snapshots:
call-bound: 1.0.4
get-intrinsic: 1.3.0
- is-windows@0.2.0: {}
-
- is-windows@1.0.2: {}
-
is-wsl@2.2.0:
dependencies:
is-docker: 2.2.1
@@ -13484,69 +12258,6 @@ snapshots:
isexe@2.0.0: {}
- istanbul-lib-coverage@3.2.2: {}
-
- istanbul-lib-hook@3.0.0:
- dependencies:
- append-transform: 2.0.0
-
- istanbul-lib-instrument@4.0.3:
- dependencies:
- '@babel/core': 7.27.4
- '@istanbuljs/schema': 0.1.3
- istanbul-lib-coverage: 3.2.2
- semver: 6.3.1
- transitivePeerDependencies:
- - supports-color
-
- istanbul-lib-instrument@5.2.1:
- dependencies:
- '@babel/core': 7.27.4
- '@babel/parser': 7.27.5
- '@istanbuljs/schema': 0.1.3
- istanbul-lib-coverage: 3.2.2
- semver: 6.3.1
- transitivePeerDependencies:
- - supports-color
-
- istanbul-lib-instrument@6.0.3:
- dependencies:
- '@babel/core': 7.27.4
- '@babel/parser': 7.27.5
- '@istanbuljs/schema': 0.1.3
- istanbul-lib-coverage: 3.2.2
- semver: 7.7.2
- transitivePeerDependencies:
- - supports-color
-
- istanbul-lib-processinfo@2.0.3:
- dependencies:
- archy: 1.0.0
- cross-spawn: 7.0.6
- istanbul-lib-coverage: 3.2.2
- p-map: 3.0.0
- rimraf: 3.0.2
- uuid: 8.3.2
-
- istanbul-lib-report@3.0.1:
- dependencies:
- istanbul-lib-coverage: 3.2.2
- make-dir: 4.0.0
- supports-color: 7.2.0
-
- istanbul-lib-source-maps@4.0.1:
- dependencies:
- debug: 4.4.1
- istanbul-lib-coverage: 3.2.2
- source-map: 0.6.1
- transitivePeerDependencies:
- - supports-color
-
- istanbul-reports@3.1.7:
- dependencies:
- html-escaper: 2.0.2
- istanbul-lib-report: 3.0.1
-
iterator.prototype@1.1.5:
dependencies:
define-data-property: 1.1.4
@@ -13564,396 +12275,21 @@ snapshots:
jaro-winkler@0.2.8: {}
- jest-changed-files@29.7.0:
- dependencies:
- execa: 5.1.1
- jest-util: 29.7.0
- p-limit: 3.1.0
-
- jest-circus@29.7.0:
- dependencies:
- '@jest/environment': 29.7.0
- '@jest/expect': 29.7.0
- '@jest/test-result': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 22.15.30
- chalk: 4.1.2
- co: 4.6.0
- dedent: 1.6.0
- is-generator-fn: 2.1.0
- jest-each: 29.7.0
- jest-matcher-utils: 29.7.0
- jest-message-util: 29.7.0
- jest-runtime: 29.7.0
- jest-snapshot: 29.7.0
- jest-util: 29.7.0
- p-limit: 3.1.0
- pretty-format: 29.7.0
- pure-rand: 6.1.0
- slash: 3.0.0
- stack-utils: 2.0.6
- transitivePeerDependencies:
- - babel-plugin-macros
- - supports-color
-
- jest-cli@29.7.0(@types/node@22.15.30):
- dependencies:
- '@jest/core': 29.7.0
- '@jest/test-result': 29.7.0
- '@jest/types': 29.6.3
- chalk: 4.1.2
- create-jest: 29.7.0(@types/node@22.15.30)
- exit: 0.1.2
- import-local: 3.2.0
- jest-config: 29.7.0(@types/node@22.15.30)
- jest-util: 29.7.0
- jest-validate: 29.7.0
- yargs: 17.7.2
- transitivePeerDependencies:
- - '@types/node'
- - babel-plugin-macros
- - supports-color
- - ts-node
-
- jest-config@29.7.0(@types/node@22.15.30):
- dependencies:
- '@babel/core': 7.27.4
- '@jest/test-sequencer': 29.7.0
- '@jest/types': 29.6.3
- babel-jest: 29.7.0(@babel/core@7.27.4)
- chalk: 4.1.2
- ci-info: 3.9.0
- deepmerge: 4.3.1
- glob: 7.2.3
- graceful-fs: 4.2.11
- jest-circus: 29.7.0
- jest-environment-node: 29.7.0
- jest-get-type: 29.6.3
- jest-regex-util: 29.6.3
- jest-resolve: 29.7.0
- jest-runner: 29.7.0
- jest-util: 29.7.0
- jest-validate: 29.7.0
- micromatch: 4.0.8
- parse-json: 5.2.0
- pretty-format: 29.7.0
- slash: 3.0.0
- strip-json-comments: 3.1.1
- optionalDependencies:
- '@types/node': 22.15.30
- transitivePeerDependencies:
- - babel-plugin-macros
- - supports-color
-
- jest-diff@29.7.0:
- dependencies:
- chalk: 4.1.2
- diff-sequences: 29.6.3
- jest-get-type: 29.6.3
- pretty-format: 29.7.0
-
- jest-docblock@29.7.0:
- dependencies:
- detect-newline: 3.1.0
-
- jest-each@29.7.0:
- dependencies:
- '@jest/types': 29.6.3
- chalk: 4.1.2
- jest-get-type: 29.6.3
- jest-util: 29.7.0
- pretty-format: 29.7.0
-
- jest-environment-node@29.7.0:
- dependencies:
- '@jest/environment': 29.7.0
- '@jest/fake-timers': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 22.15.30
- jest-mock: 29.7.0
- jest-util: 29.7.0
-
- jest-get-type@29.6.3: {}
-
- jest-haste-map@29.7.0:
- dependencies:
- '@jest/types': 29.6.3
- '@types/graceful-fs': 4.1.9
- '@types/node': 22.15.30
- anymatch: 3.1.3
- fb-watchman: 2.0.2
- graceful-fs: 4.2.11
- jest-regex-util: 29.6.3
- jest-util: 29.7.0
- jest-worker: 29.7.0
- micromatch: 4.0.8
- walker: 1.0.8
- optionalDependencies:
- fsevents: 2.3.3
-
- jest-junit@16.0.0:
- dependencies:
- mkdirp: 1.0.4
- strip-ansi: 6.0.1
- uuid: 8.3.2
- xml: 1.0.1
-
- jest-leak-detector@29.7.0:
- dependencies:
- jest-get-type: 29.6.3
- pretty-format: 29.7.0
-
- jest-matcher-utils@29.7.0:
- dependencies:
- chalk: 4.1.2
- jest-diff: 29.7.0
- jest-get-type: 29.6.3
- pretty-format: 29.7.0
-
- jest-message-util@29.7.0:
- dependencies:
- '@babel/code-frame': 7.27.1
- '@jest/types': 29.6.3
- '@types/stack-utils': 2.0.3
- chalk: 4.1.2
- graceful-fs: 4.2.11
- micromatch: 4.0.8
- pretty-format: 29.7.0
- slash: 3.0.0
- stack-utils: 2.0.6
-
- jest-mock@29.7.0:
- dependencies:
- '@jest/types': 29.6.3
- '@types/node': 22.15.30
- jest-util: 29.7.0
-
- jest-playwright-preset@4.0.0(jest-circus@29.7.0)(jest-environment-node@29.7.0)(jest-runner@29.7.0)(jest@29.7.0(@types/node@22.15.30)):
- dependencies:
- expect-playwright: 0.8.0
- jest: 29.7.0(@types/node@22.15.30)
- jest-circus: 29.7.0
- jest-environment-node: 29.7.0
- jest-process-manager: 0.4.0
- jest-runner: 29.7.0
- nyc: 15.1.0
- playwright-core: 1.52.0
- rimraf: 3.0.2
- uuid: 8.3.2
- transitivePeerDependencies:
- - debug
- - supports-color
-
- jest-pnp-resolver@1.2.3(jest-resolve@29.7.0):
- optionalDependencies:
- jest-resolve: 29.7.0
-
- jest-process-manager@0.4.0:
- dependencies:
- '@types/wait-on': 5.3.4
- chalk: 4.1.2
- cwd: 0.10.0
- exit: 0.1.2
- find-process: 1.4.10
- prompts: 2.4.2
- signal-exit: 3.0.7
- spawnd: 5.0.0
- tree-kill: 1.2.2
- wait-on: 7.2.0
- transitivePeerDependencies:
- - debug
- - supports-color
-
- jest-regex-util@29.6.3: {}
-
- jest-resolve-dependencies@29.7.0:
- dependencies:
- jest-regex-util: 29.6.3
- jest-snapshot: 29.7.0
- transitivePeerDependencies:
- - supports-color
-
- jest-resolve@29.7.0:
- dependencies:
- chalk: 4.1.2
- graceful-fs: 4.2.11
- jest-haste-map: 29.7.0
- jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0)
- jest-util: 29.7.0
- jest-validate: 29.7.0
- resolve: 1.22.10
- resolve.exports: 2.0.3
- slash: 3.0.0
-
- jest-runner@29.7.0:
- dependencies:
- '@jest/console': 29.7.0
- '@jest/environment': 29.7.0
- '@jest/test-result': 29.7.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 22.15.30
- chalk: 4.1.2
- emittery: 0.13.1
- graceful-fs: 4.2.11
- jest-docblock: 29.7.0
- jest-environment-node: 29.7.0
- jest-haste-map: 29.7.0
- jest-leak-detector: 29.7.0
- jest-message-util: 29.7.0
- jest-resolve: 29.7.0
- jest-runtime: 29.7.0
- jest-util: 29.7.0
- jest-watcher: 29.7.0
- jest-worker: 29.7.0
- p-limit: 3.1.0
- source-map-support: 0.5.13
- transitivePeerDependencies:
- - supports-color
-
- jest-runtime@29.7.0:
- dependencies:
- '@jest/environment': 29.7.0
- '@jest/fake-timers': 29.7.0
- '@jest/globals': 29.7.0
- '@jest/source-map': 29.6.3
- '@jest/test-result': 29.7.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 22.15.30
- chalk: 4.1.2
- cjs-module-lexer: 1.4.3
- collect-v8-coverage: 1.0.2
- glob: 7.2.3
- graceful-fs: 4.2.11
- jest-haste-map: 29.7.0
- jest-message-util: 29.7.0
- jest-mock: 29.7.0
- jest-regex-util: 29.6.3
- jest-resolve: 29.7.0
- jest-snapshot: 29.7.0
- jest-util: 29.7.0
- slash: 3.0.0
- strip-bom: 4.0.0
- transitivePeerDependencies:
- - supports-color
-
- jest-serializer-html@7.1.0:
- dependencies:
- diffable-html: 4.1.0
-
- jest-snapshot@29.7.0:
- dependencies:
- '@babel/core': 7.27.4
- '@babel/generator': 7.27.5
- '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.27.4)
- '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.27.4)
- '@babel/types': 7.27.6
- '@jest/expect-utils': 29.7.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- babel-preset-current-node-syntax: 1.1.0(@babel/core@7.27.4)
- chalk: 4.1.2
- expect: 29.7.0
- graceful-fs: 4.2.11
- jest-diff: 29.7.0
- jest-get-type: 29.6.3
- jest-matcher-utils: 29.7.0
- jest-message-util: 29.7.0
- jest-util: 29.7.0
- natural-compare: 1.4.0
- pretty-format: 29.7.0
- semver: 7.7.2
- transitivePeerDependencies:
- - supports-color
-
- jest-util@29.7.0:
- dependencies:
- '@jest/types': 29.6.3
- '@types/node': 22.15.30
- chalk: 4.1.2
- ci-info: 3.9.0
- graceful-fs: 4.2.11
- picomatch: 2.3.1
-
- jest-validate@29.7.0:
- dependencies:
- '@jest/types': 29.6.3
- camelcase: 6.3.0
- chalk: 4.1.2
- jest-get-type: 29.6.3
- leven: 3.1.0
- pretty-format: 29.7.0
-
- jest-watch-typeahead@2.2.2(jest@29.7.0(@types/node@22.15.30)):
- dependencies:
- ansi-escapes: 6.2.1
- chalk: 5.4.1
- jest: 29.7.0(@types/node@22.15.30)
- jest-regex-util: 29.6.3
- jest-watcher: 29.7.0
- slash: 5.1.0
- string-length: 5.0.1
- strip-ansi: 7.1.0
-
- jest-watcher@29.7.0:
- dependencies:
- '@jest/test-result': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 22.15.30
- ansi-escapes: 4.3.2
- chalk: 4.1.2
- emittery: 0.13.1
- jest-util: 29.7.0
- string-length: 4.0.2
-
jest-worker@27.5.1:
dependencies:
'@types/node': 22.15.30
merge-stream: 2.0.0
supports-color: 8.1.1
- jest-worker@29.7.0:
- dependencies:
- '@types/node': 22.15.30
- jest-util: 29.7.0
- merge-stream: 2.0.0
- supports-color: 8.1.1
-
- jest@29.7.0(@types/node@22.15.30):
- dependencies:
- '@jest/core': 29.7.0
- '@jest/types': 29.6.3
- import-local: 3.2.0
- jest-cli: 29.7.0(@types/node@22.15.30)
- transitivePeerDependencies:
- - '@types/node'
- - babel-plugin-macros
- - supports-color
- - ts-node
-
jiti@1.21.7: {}
- joi@17.13.3:
- dependencies:
- '@hapi/hoek': 9.3.0
- '@hapi/topo': 5.1.0
- '@sideway/address': 4.1.5
- '@sideway/formula': 3.0.1
- '@sideway/pinpoint': 2.0.0
-
js-tokens@4.0.0: {}
- js-yaml@3.14.1:
- dependencies:
- argparse: 1.0.10
- esprima: 4.0.1
-
js-yaml@4.1.0:
dependencies:
argparse: 2.0.1
- jsdoc-type-pratt-parser@4.1.0: {}
+ jsep@1.4.0: {}
jsesc@3.0.2: {}
@@ -13975,7 +12311,7 @@ snapshots:
json5@2.2.3: {}
- jsonc-parser@3.3.1: {}
+ jsonc-parser@2.2.1: {}
jsonfile@6.1.0:
dependencies:
@@ -13983,6 +12319,16 @@ snapshots:
optionalDependencies:
graceful-fs: 4.2.11
+ jsonpath-plus@10.3.0:
+ dependencies:
+ '@jsep-plugin/assignment': 1.3.0(jsep@1.4.0)
+ '@jsep-plugin/regex': 1.0.4(jsep@1.4.0)
+ jsep: 1.4.0
+
+ jsonpointer@5.0.1: {}
+
+ jsonschema@1.5.0: {}
+
jsx-ast-utils@3.3.5:
dependencies:
array-includes: 3.1.9
@@ -14000,8 +12346,6 @@ snapshots:
dependencies:
json-buffer: 3.0.1
- kleur@3.0.3: {}
-
language-subtag-registry@0.3.23: {}
language-tags@1.0.9:
@@ -14038,6 +12382,10 @@ snapshots:
lines-and-columns@1.2.4: {}
+ linkify-it@5.0.0:
+ dependencies:
+ uc.micro: 2.1.0
+
loader-runner@4.3.0: {}
loader-utils@2.0.4:
@@ -14064,12 +12412,24 @@ snapshots:
lodash.debounce@4.0.8: {}
- lodash.flattendeep@4.4.0: {}
+ lodash.isempty@4.4.0: {}
lodash.merge@4.6.2: {}
+ lodash.omitby@4.6.0: {}
+
+ lodash.topath@4.5.2: {}
+
+ lodash.uniq@4.5.0: {}
+
+ lodash.uniqby@4.7.0: {}
+
+ lodash.uniqwith@4.5.0: {}
+
lodash@4.17.21: {}
+ loglevel-plugin-prefix@0.8.4: {}
+
loglevel@1.9.2: {}
longest-streak@3.1.0: {}
@@ -14078,7 +12438,7 @@ snapshots:
dependencies:
js-tokens: 4.0.0
- loupe@3.1.3: {}
+ loupe@3.1.4: {}
lower-case@2.0.2:
dependencies:
@@ -14094,6 +12454,8 @@ snapshots:
dependencies:
react: 18.3.1
+ lunr@2.3.9: {}
+
lz-string@1.5.0: {}
magic-string@0.30.17:
@@ -14108,15 +12470,14 @@ snapshots:
dependencies:
semver: 6.3.1
- make-dir@4.0.0:
+ markdown-it@14.1.0:
dependencies:
- semver: 7.7.2
-
- makeerror@1.0.12:
- dependencies:
- tmpl: 1.0.5
-
- map-or-similar@1.5.0: {}
+ argparse: 2.0.1
+ entities: 4.5.0
+ linkify-it: 5.0.0
+ mdurl: 2.0.0
+ punycode.js: 2.3.1
+ uc.micro: 2.1.0
math-intrinsics@1.1.0: {}
@@ -14130,7 +12491,7 @@ snapshots:
dependencies:
'@types/mdast': 4.0.4
'@types/unist': 3.0.3
- decode-named-character-reference: 1.1.0
+ decode-named-character-reference: 1.2.0
devlop: 1.1.0
mdast-util-to-string: 4.0.0
micromark: 4.0.2
@@ -14215,21 +12576,19 @@ snapshots:
dependencies:
'@types/mdast': 4.0.4
+ mdurl@2.0.0: {}
+
memfs@3.5.3:
dependencies:
fs-monkey: 1.0.6
- memoizerific@1.11.3:
- dependencies:
- map-or-similar: 1.5.0
-
merge-stream@2.0.0: {}
merge2@1.4.1: {}
micromark-core-commonmark@2.0.3:
dependencies:
- decode-named-character-reference: 1.1.0
+ decode-named-character-reference: 1.2.0
devlop: 1.1.0
micromark-factory-destination: 2.0.1
micromark-factory-label: 2.0.1
@@ -14304,7 +12663,7 @@ snapshots:
micromark-util-decode-string@2.0.1:
dependencies:
- decode-named-character-reference: 1.1.0
+ decode-named-character-reference: 1.2.0
micromark-util-character: 2.1.1
micromark-util-decode-numeric-character-reference: 2.0.2
micromark-util-symbol: 2.0.1
@@ -14342,7 +12701,7 @@ snapshots:
dependencies:
'@types/debug': 4.1.12
debug: 4.4.1
- decode-named-character-reference: 1.1.0
+ decode-named-character-reference: 1.2.0
devlop: 1.1.0
micromark-core-commonmark: 2.0.3
micromark-factory-space: 2.0.1
@@ -14386,15 +12745,19 @@ snapshots:
minimatch@3.1.2:
dependencies:
- brace-expansion: 1.1.11
+ brace-expansion: 1.1.12
+
+ minimatch@6.2.0:
+ dependencies:
+ brace-expansion: 2.0.2
minimatch@8.0.4:
dependencies:
- brace-expansion: 2.0.1
+ brace-expansion: 2.0.2
minimatch@9.0.5:
dependencies:
- brace-expansion: 2.0.1
+ brace-expansion: 2.0.2
minimist@1.2.8: {}
@@ -14402,17 +12765,15 @@ snapshots:
minipass@7.1.2: {}
- mkdirp@1.0.4: {}
-
module-details-from-path@1.0.4: {}
moment@2.30.1: {}
- motion-dom@12.16.0:
+ motion-dom@12.18.1:
dependencies:
- motion-utils: 12.12.1
+ motion-utils: 12.18.1
- motion-utils@12.12.1: {}
+ motion-utils@12.18.1: {}
ms@2.1.3: {}
@@ -14469,13 +12830,13 @@ snapshots:
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
+ next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@next/env': 15.3.3
'@swc/counter': 0.1.3
'@swc/helpers': 0.5.15
busboy: 1.6.0
- caniuse-lite: 1.0.30001721
+ caniuse-lite: 1.0.30001723
postcss: 8.4.31
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
@@ -14490,12 +12851,22 @@ snapshots:
'@next/swc-win32-arm64-msvc': 15.3.3
'@next/swc-win32-x64-msvc': 15.3.3
'@opentelemetry/api': 1.9.0
- '@playwright/test': 1.52.0
+ '@playwright/test': 1.53.1
sharp: 0.34.2
transitivePeerDependencies:
- '@babel/core'
- babel-plugin-macros
+ nimma@0.2.3:
+ dependencies:
+ '@jsep-plugin/regex': 1.0.4(jsep@1.4.0)
+ '@jsep-plugin/ternary': 1.1.4(jsep@1.4.0)
+ astring: 1.9.0
+ jsep: 1.4.0
+ optionalDependencies:
+ jsonpath-plus: 10.3.0
+ lodash.topath: 4.5.2
+
no-case@3.0.4:
dependencies:
lower-case: 2.0.2
@@ -14503,13 +12874,15 @@ snapshots:
node-abort-controller@3.1.1: {}
+ node-fetch-h2@2.3.0:
+ dependencies:
+ http2-client: 1.3.5
+
node-fetch@2.7.0:
dependencies:
whatwg-url: 5.0.0
- node-int64@0.4.0: {}
-
- node-polyfill-webpack-plugin@2.0.1(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2)):
+ node-polyfill-webpack-plugin@2.0.1(webpack@5.99.9(esbuild@0.25.5)):
dependencies:
assert: 2.1.0
browserify-zlib: 0.2.0
@@ -14536,11 +12909,11 @@ snapshots:
url: 0.11.4
util: 0.12.5
vm-browserify: 1.1.2
- webpack: 5.99.9(@swc/core@1.11.31)(esbuild@0.24.2)
+ webpack: 5.99.9(esbuild@0.25.5)
- node-preload@0.2.1:
+ node-readfiles@0.2.0:
dependencies:
- process-on-spawn: 1.1.0
+ es6-promise: 3.3.1
node-releases@2.0.19: {}
@@ -14554,37 +12927,36 @@ snapshots:
dependencies:
boolbase: 1.0.0
- nyc@15.1.0:
+ oas-kit-common@1.0.8:
dependencies:
- '@istanbuljs/load-nyc-config': 1.1.0
- '@istanbuljs/schema': 0.1.3
- caching-transform: 4.0.0
- convert-source-map: 1.9.0
- decamelize: 1.2.0
- find-cache-dir: 3.3.2
- find-up: 4.1.0
- foreground-child: 2.0.0
- get-package-type: 0.1.0
- glob: 7.2.3
- istanbul-lib-coverage: 3.2.2
- istanbul-lib-hook: 3.0.0
- istanbul-lib-instrument: 4.0.3
- istanbul-lib-processinfo: 2.0.3
- istanbul-lib-report: 3.0.1
- istanbul-lib-source-maps: 4.0.1
- istanbul-reports: 3.1.7
- make-dir: 3.1.0
- node-preload: 0.2.1
- p-map: 3.0.0
- process-on-spawn: 1.1.0
- resolve-from: 5.0.0
- rimraf: 3.0.2
- signal-exit: 3.0.7
- spawn-wrap: 2.0.0
- test-exclude: 6.0.0
- yargs: 15.4.1
- transitivePeerDependencies:
- - supports-color
+ fast-safe-stringify: 2.1.1
+
+ oas-linter@3.2.2:
+ dependencies:
+ '@exodus/schemasafe': 1.3.0
+ should: 13.2.3
+ yaml: 1.10.2
+
+ oas-resolver@2.5.6:
+ dependencies:
+ node-fetch-h2: 2.3.0
+ oas-kit-common: 1.0.8
+ reftools: 1.1.9
+ yaml: 1.10.2
+ yargs: 17.7.2
+
+ oas-schema-walker@1.1.5: {}
+
+ oas-validator@5.0.8:
+ dependencies:
+ call-me-maybe: 1.0.2
+ oas-kit-common: 1.0.8
+ oas-linter: 3.2.2
+ oas-resolver: 2.5.6
+ oas-schema-walker: 1.1.5
+ reftools: 1.1.9
+ should: 13.2.3
+ yaml: 1.10.2
object-assign@4.1.1: {}
@@ -14651,6 +13023,16 @@ snapshots:
is-docker: 2.2.1
is-wsl: 2.2.0
+ openapi-types@12.1.3: {}
+
+ openapi3-ts@4.2.2:
+ dependencies:
+ yaml: 2.8.0
+
+ openapi3-ts@4.4.0:
+ dependencies:
+ yaml: 2.8.0
+
optionator@0.9.4:
dependencies:
deep-is: 0.1.4
@@ -14660,9 +13042,40 @@ snapshots:
type-check: 0.4.0
word-wrap: 1.2.5
- os-browserify@0.3.0: {}
+ orval@7.10.0(openapi-types@12.1.3):
+ dependencies:
+ '@apidevtools/swagger-parser': 10.1.1(openapi-types@12.1.3)
+ '@orval/angular': 7.10.0(openapi-types@12.1.3)
+ '@orval/axios': 7.10.0(openapi-types@12.1.3)
+ '@orval/core': 7.10.0(openapi-types@12.1.3)
+ '@orval/fetch': 7.10.0(openapi-types@12.1.3)
+ '@orval/hono': 7.10.0(openapi-types@12.1.3)
+ '@orval/mcp': 7.10.0(openapi-types@12.1.3)
+ '@orval/mock': 7.10.0(openapi-types@12.1.3)
+ '@orval/query': 7.10.0(openapi-types@12.1.3)
+ '@orval/swr': 7.10.0(openapi-types@12.1.3)
+ '@orval/zod': 7.10.0(openapi-types@12.1.3)
+ ajv: 8.17.1
+ cac: 6.7.14
+ chalk: 4.1.2
+ chokidar: 4.0.3
+ enquirer: 2.4.1
+ execa: 5.1.1
+ find-up: 5.0.0
+ fs-extra: 11.3.0
+ lodash.uniq: 4.5.0
+ openapi3-ts: 4.2.2
+ string-argv: 0.3.2
+ tsconfck: 2.1.2(typescript@5.8.3)
+ typedoc: 0.28.5(typescript@5.8.3)
+ typedoc-plugin-markdown: 4.6.4(typedoc@0.28.5(typescript@5.8.3))
+ typescript: 5.8.3
+ transitivePeerDependencies:
+ - encoding
+ - openapi-types
+ - supports-color
- os-homedir@1.0.2: {}
+ os-browserify@0.3.0: {}
outvariant@1.4.3: {}
@@ -14696,19 +13109,8 @@ snapshots:
dependencies:
p-limit: 4.0.0
- p-map@3.0.0:
- dependencies:
- aggregate-error: 3.1.0
-
p-try@2.2.0: {}
- package-hash@4.0.0:
- dependencies:
- graceful-fs: 4.2.11
- hasha: 5.2.2
- lodash.flattendeep: 4.4.0
- release-zalgo: 1.0.0
-
package-json-from-dist@1.0.1: {}
pako@1.0.11: {}
@@ -14736,7 +13138,7 @@ snapshots:
'@types/unist': 2.0.11
character-entities-legacy: 3.0.0
character-reference-invalid: 2.0.1
- decode-named-character-reference: 1.1.0
+ decode-named-character-reference: 1.2.0
is-alphanumerical: 2.0.1
is-decimal: 2.0.1
is-hexadecimal: 2.0.1
@@ -14748,8 +13150,6 @@ snapshots:
json-parse-even-better-errors: 2.3.1
lines-and-columns: 1.2.4
- parse-passwd@1.0.0: {}
-
party-js@2.2.0: {}
pascal-case@3.1.2:
@@ -14818,80 +13218,72 @@ snapshots:
dependencies:
find-up: 6.3.0
- playwright-core@1.52.0: {}
+ playwright-core@1.53.1: {}
- playwright@1.52.0:
+ playwright@1.53.1:
dependencies:
- playwright-core: 1.52.0
+ playwright-core: 1.53.1
optionalDependencies:
fsevents: 2.3.2
- pnp-webpack-plugin@1.7.0(typescript@5.8.3):
- dependencies:
- ts-pnp: 1.2.0(typescript@5.8.3)
- transitivePeerDependencies:
- - typescript
-
- polished@4.3.1:
- dependencies:
- '@babel/runtime': 7.27.6
+ pony-cause@1.1.1: {}
possible-typed-array-names@1.1.0: {}
- postcss-import@15.1.0(postcss@8.5.4):
+ postcss-import@15.1.0(postcss@8.5.6):
dependencies:
- postcss: 8.5.4
+ postcss: 8.5.6
postcss-value-parser: 4.2.0
read-cache: 1.0.0
resolve: 1.22.10
- postcss-js@4.0.1(postcss@8.5.4):
+ postcss-js@4.0.1(postcss@8.5.6):
dependencies:
camelcase-css: 2.0.1
- postcss: 8.5.4
+ postcss: 8.5.6
- postcss-load-config@4.0.2(postcss@8.5.4):
+ postcss-load-config@4.0.2(postcss@8.5.6):
dependencies:
lilconfig: 3.1.3
yaml: 2.8.0
optionalDependencies:
- postcss: 8.5.4
+ postcss: 8.5.6
- postcss-loader@8.1.1(postcss@8.5.4)(typescript@5.8.3)(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2)):
+ postcss-loader@8.1.1(postcss@8.5.6)(typescript@5.8.3)(webpack@5.99.9(esbuild@0.25.5)):
dependencies:
cosmiconfig: 9.0.0(typescript@5.8.3)
jiti: 1.21.7
- postcss: 8.5.4
+ postcss: 8.5.6
semver: 7.7.2
optionalDependencies:
- webpack: 5.99.9(@swc/core@1.11.31)(esbuild@0.24.2)
+ webpack: 5.99.9(esbuild@0.25.5)
transitivePeerDependencies:
- typescript
- postcss-modules-extract-imports@3.1.0(postcss@8.5.4):
+ postcss-modules-extract-imports@3.1.0(postcss@8.5.6):
dependencies:
- postcss: 8.5.4
+ postcss: 8.5.6
- postcss-modules-local-by-default@4.2.0(postcss@8.5.4):
+ postcss-modules-local-by-default@4.2.0(postcss@8.5.6):
dependencies:
- icss-utils: 5.1.0(postcss@8.5.4)
- postcss: 8.5.4
+ icss-utils: 5.1.0(postcss@8.5.6)
+ postcss: 8.5.6
postcss-selector-parser: 7.1.0
postcss-value-parser: 4.2.0
- postcss-modules-scope@3.2.1(postcss@8.5.4):
+ postcss-modules-scope@3.2.1(postcss@8.5.6):
dependencies:
- postcss: 8.5.4
+ postcss: 8.5.6
postcss-selector-parser: 7.1.0
- postcss-modules-values@4.0.0(postcss@8.5.4):
+ postcss-modules-values@4.0.0(postcss@8.5.6):
dependencies:
- icss-utils: 5.1.0(postcss@8.5.4)
- postcss: 8.5.4
+ icss-utils: 5.1.0(postcss@8.5.6)
+ postcss: 8.5.6
- postcss-nested@6.2.0(postcss@8.5.4):
+ postcss-nested@6.2.0(postcss@8.5.6):
dependencies:
- postcss: 8.5.4
+ postcss: 8.5.6
postcss-selector-parser: 6.1.2
postcss-selector-parser@6.1.2:
@@ -14918,7 +13310,7 @@ snapshots:
picocolors: 1.1.1
source-map-js: 1.2.1
- postcss@8.5.4:
+ postcss@8.5.6:
dependencies:
nanoid: 3.3.11
picocolors: 1.1.1
@@ -14953,27 +13345,12 @@ snapshots:
ansi-styles: 5.2.0
react-is: 17.0.2
- pretty-format@29.7.0:
- dependencies:
- '@jest/schemas': 29.6.3
- ansi-styles: 5.2.0
- react-is: 18.3.1
-
process-nextick-args@2.0.1: {}
- process-on-spawn@1.1.0:
- dependencies:
- fromentries: 1.3.2
-
process@0.11.10: {}
progress@2.0.3: {}
- prompts@2.4.2:
- dependencies:
- kleur: 3.0.3
- sisteransi: 1.0.5
-
prop-types@15.8.1:
dependencies:
loose-envify: 1.4.0
@@ -14997,12 +13374,12 @@ snapshots:
randombytes: 2.1.0
safe-buffer: 5.2.1
+ punycode.js@2.3.1: {}
+
punycode@1.4.1: {}
punycode@2.3.1: {}
- pure-rand@6.1.0: {}
-
qs@6.14.0:
dependencies:
side-channel: 1.1.0
@@ -15013,10 +13390,6 @@ snapshots:
queue-microtask@1.2.3: {}
- queue@6.0.2:
- dependencies:
- inherits: 2.0.4
-
randombytes@2.1.0:
dependencies:
safe-buffer: 5.2.1
@@ -15028,11 +13401,6 @@ snapshots:
range-parser@1.2.1: {}
- react-confetti@6.4.0(react@18.3.1):
- dependencies:
- react: 18.3.1
- tween-functions: 1.2.0
-
react-day-picker@9.7.0(react@18.3.1):
dependencies:
'@date-fns/tz': 1.2.0
@@ -15040,7 +13408,7 @@ snapshots:
date-fns-jalali: 4.1.0-0
react: 18.3.1
- react-docgen-typescript@2.2.2(typescript@5.8.3):
+ react-docgen-typescript@2.4.0(typescript@5.8.3):
dependencies:
typescript: 5.8.3
@@ -15070,7 +13438,7 @@ snapshots:
prop-types: 15.8.1
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- styled-components: 6.1.18(react-dom@18.3.1(react@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.57.0(react@18.3.1):
dependencies:
@@ -15203,6 +13571,8 @@ snapshots:
dependencies:
picomatch: 2.3.1
+ readdirp@4.1.2: {}
+
recast@0.23.11:
dependencies:
ast-types: 0.16.1
@@ -15244,6 +13614,8 @@ snapshots:
get-proto: 1.0.1
which-builtin-type: 1.2.1
+ reftools@1.1.9: {}
+
regenerate-unicode-properties@10.2.0:
dependencies:
regenerate: 1.4.2
@@ -15278,10 +13650,6 @@ snapshots:
relateurl@0.2.7: {}
- release-zalgo@1.0.0:
- dependencies:
- es6-error: 4.1.1
-
remark-parse@11.0.0:
dependencies:
'@types/mdast': 4.0.4
@@ -15319,23 +13687,10 @@ snapshots:
transitivePeerDependencies:
- supports-color
- require-main-filename@2.0.0: {}
-
requires-port@1.0.0: {}
- resolve-cwd@3.0.0:
- dependencies:
- resolve-from: 5.0.0
-
- resolve-dir@0.1.1:
- dependencies:
- expand-tilde: 1.2.2
- global-modules: 0.2.3
-
resolve-from@4.0.0: {}
- resolve-from@5.0.0: {}
-
resolve-pkg-maps@1.0.0: {}
resolve-url-loader@5.0.0:
@@ -15343,11 +13698,9 @@ snapshots:
adjust-sourcemap-loader: 4.0.0
convert-source-map: 1.9.0
loader-utils: 2.0.4
- postcss: 8.5.4
+ postcss: 8.5.6
source-map: 0.6.1
- resolve.exports@2.0.3: {}
-
resolve@1.22.10:
dependencies:
is-core-module: 2.16.1
@@ -15433,11 +13786,13 @@ snapshots:
es-errors: 1.3.0
is-regex: 1.2.1
- sass-loader@14.2.1(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2)):
+ safe-stable-stringify@1.1.1: {}
+
+ sass-loader@14.2.1(webpack@5.99.9(esbuild@0.25.5)):
dependencies:
neo-async: 2.6.2
optionalDependencies:
- webpack: 5.99.9(@swc/core@1.11.31)(esbuild@0.24.2)
+ webpack: 5.99.9(esbuild@0.25.5)
scheduler@0.23.2:
dependencies:
@@ -15464,8 +13819,6 @@ snapshots:
dependencies:
randombytes: 2.1.0
- set-blocking@2.0.0: {}
-
set-function-length@1.2.2:
dependencies:
define-data-property: 1.1.4
@@ -15497,33 +13850,6 @@ snapshots:
shallowequal@1.1.0: {}
- sharp@0.33.5:
- dependencies:
- color: 4.2.3
- detect-libc: 2.0.4
- semver: 7.7.2
- optionalDependencies:
- '@img/sharp-darwin-arm64': 0.33.5
- '@img/sharp-darwin-x64': 0.33.5
- '@img/sharp-libvips-darwin-arm64': 1.0.4
- '@img/sharp-libvips-darwin-x64': 1.0.4
- '@img/sharp-libvips-linux-arm': 1.0.5
- '@img/sharp-libvips-linux-arm64': 1.0.4
- '@img/sharp-libvips-linux-s390x': 1.0.4
- '@img/sharp-libvips-linux-x64': 1.0.4
- '@img/sharp-libvips-linuxmusl-arm64': 1.0.4
- '@img/sharp-libvips-linuxmusl-x64': 1.0.4
- '@img/sharp-linux-arm': 0.33.5
- '@img/sharp-linux-arm64': 0.33.5
- '@img/sharp-linux-s390x': 0.33.5
- '@img/sharp-linux-x64': 0.33.5
- '@img/sharp-linuxmusl-arm64': 0.33.5
- '@img/sharp-linuxmusl-x64': 0.33.5
- '@img/sharp-wasm32': 0.33.5
- '@img/sharp-win32-ia32': 0.33.5
- '@img/sharp-win32-x64': 0.33.5
- optional: true
-
sharp@0.34.2:
dependencies:
color: 4.2.3
@@ -15569,6 +13895,32 @@ snapshots:
shimmer@1.2.1: {}
+ should-equal@2.0.0:
+ dependencies:
+ should-type: 1.4.0
+
+ should-format@3.0.3:
+ dependencies:
+ should-type: 1.4.0
+ should-type-adaptors: 1.1.0
+
+ should-type-adaptors@1.1.0:
+ dependencies:
+ should-type: 1.4.0
+ should-util: 1.0.1
+
+ should-type@1.4.0: {}
+
+ should-util@1.0.1: {}
+
+ should@13.2.3:
+ dependencies:
+ should-equal: 2.0.0
+ should-format: 3.0.3
+ should-type: 1.4.0
+ should-type-adaptors: 1.1.0
+ should-util: 1.0.1
+
side-channel-list@1.0.0:
dependencies:
es-errors: 1.3.0
@@ -15601,24 +13953,19 @@ snapshots:
signal-exit@4.1.0: {}
+ simple-eval@1.0.1:
+ dependencies:
+ jsep: 1.4.0
+
simple-swizzle@0.2.2:
dependencies:
is-arrayish: 0.3.2
optional: true
- sisteransi@1.0.5: {}
-
slash@3.0.0: {}
- slash@5.1.0: {}
-
source-map-js@1.2.1: {}
- source-map-support@0.5.13:
- dependencies:
- buffer-from: 1.1.2
- source-map: 0.6.1
-
source-map-support@0.5.21:
dependencies:
buffer-from: 1.1.2
@@ -15630,32 +13977,8 @@ snapshots:
space-separated-tokens@2.0.2: {}
- spawn-wrap@2.0.0:
- dependencies:
- foreground-child: 2.0.0
- is-windows: 1.0.2
- make-dir: 3.1.0
- rimraf: 3.0.2
- signal-exit: 3.0.7
- which: 2.0.2
-
- spawnd@5.0.0:
- dependencies:
- exit: 0.1.2
- signal-exit: 3.0.7
- tree-kill: 1.2.2
- wait-port: 0.2.14
- transitivePeerDependencies:
- - supports-color
-
- sprintf-js@1.0.3: {}
-
stable-hash@0.0.5: {}
- stack-utils@2.0.6:
- dependencies:
- escape-string-regexp: 2.0.0
-
stackframe@1.3.4: {}
stacktrace-parser@0.1.11:
@@ -15669,12 +13992,23 @@ snapshots:
es-errors: 1.3.0
internal-slot: 1.1.0
- storybook@8.6.14(prettier@3.5.3):
+ storybook@9.0.12(@testing-library/dom@10.4.0)(prettier@3.5.3):
dependencies:
- '@storybook/core': 8.6.14(prettier@3.5.3)(storybook@8.6.14(prettier@3.5.3))
+ '@storybook/global': 5.0.0
+ '@testing-library/jest-dom': 6.6.3
+ '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.0)
+ '@vitest/expect': 3.0.9
+ '@vitest/spy': 3.0.9
+ better-opn: 3.0.2
+ esbuild: 0.25.5
+ esbuild-register: 3.6.0(esbuild@0.25.5)
+ recast: 0.23.11
+ semver: 7.7.2
+ ws: 8.18.2
optionalDependencies:
prettier: 3.5.3
transitivePeerDependencies:
+ - '@testing-library/dom'
- bufferutil
- supports-color
- utf-8-validate
@@ -15695,15 +14029,7 @@ snapshots:
strict-event-emitter@0.5.1: {}
- string-length@4.0.2:
- dependencies:
- char-regex: 1.0.2
- strip-ansi: 6.0.1
-
- string-length@5.0.1:
- dependencies:
- char-regex: 2.0.2
- strip-ansi: 7.1.0
+ string-argv@0.3.2: {}
string-width@4.2.3:
dependencies:
@@ -15790,8 +14116,6 @@ snapshots:
strip-bom@3.0.0: {}
- strip-bom@4.0.0: {}
-
strip-final-newline@2.0.0: {}
strip-indent@3.0.0:
@@ -15804,19 +14128,19 @@ snapshots:
strip-json-comments@3.1.1: {}
- style-loader@3.3.4(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2)):
+ style-loader@3.3.4(webpack@5.99.9(esbuild@0.25.5)):
dependencies:
- webpack: 5.99.9(@swc/core@1.11.31)(esbuild@0.24.2)
+ webpack: 5.99.9(esbuild@0.25.5)
- style-to-js@1.1.16:
+ style-to-js@1.1.17:
dependencies:
- style-to-object: 1.0.8
+ style-to-object: 1.0.9
- style-to-object@1.0.8:
+ style-to-object@1.0.9:
dependencies:
inline-style-parser: 0.2.4
- styled-components@6.1.18(react-dom@18.3.1(react@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):
dependencies:
'@emotion/is-prop-valid': 1.2.2
'@emotion/unitless': 0.8.1
@@ -15856,10 +14180,6 @@ snapshots:
pirates: 4.0.7
ts-interface-checker: 0.1.13
- supports-color@5.5.0:
- dependencies:
- has-flag: 3.0.0
-
supports-color@7.2.0:
dependencies:
has-flag: 4.0.0
@@ -15870,6 +14190,22 @@ snapshots:
supports-preserve-symlinks-flag@1.0.0: {}
+ swagger2openapi@7.0.8:
+ dependencies:
+ call-me-maybe: 1.0.2
+ node-fetch: 2.7.0
+ node-fetch-h2: 2.3.0
+ node-readfiles: 0.2.0
+ oas-kit-common: 1.0.8
+ oas-resolver: 2.5.6
+ oas-schema-walker: 1.1.5
+ oas-validator: 5.0.8
+ reftools: 1.1.9
+ yaml: 1.10.2
+ yargs: 17.7.2
+ transitivePeerDependencies:
+ - encoding
+
tailwind-merge@2.6.0: {}
tailwindcss-animate@1.0.7(tailwindcss@3.4.17):
@@ -15892,11 +14228,11 @@ snapshots:
normalize-path: 3.0.0
object-hash: 3.0.0
picocolors: 1.1.1
- postcss: 8.5.4
- postcss-import: 15.1.0(postcss@8.5.4)
- postcss-js: 4.0.1(postcss@8.5.4)
- postcss-load-config: 4.0.2(postcss@8.5.4)
- postcss-nested: 6.2.0(postcss@8.5.4)
+ postcss: 8.5.6
+ postcss-import: 15.1.0(postcss@8.5.6)
+ postcss-js: 4.0.1(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
@@ -15905,31 +14241,24 @@ snapshots:
tapable@2.2.2: {}
- terser-webpack-plugin@5.3.14(@swc/core@1.11.31)(esbuild@0.24.2)(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2)):
+ terser-webpack-plugin@5.3.14(esbuild@0.25.5)(webpack@5.99.9(esbuild@0.25.5)):
dependencies:
'@jridgewell/trace-mapping': 0.3.25
jest-worker: 27.5.1
schema-utils: 4.3.2
serialize-javascript: 6.0.2
- terser: 5.41.0
- webpack: 5.99.9(@swc/core@1.11.31)(esbuild@0.24.2)
+ terser: 5.42.0
+ webpack: 5.99.9(esbuild@0.25.5)
optionalDependencies:
- '@swc/core': 1.11.31
- esbuild: 0.24.2
+ esbuild: 0.25.5
- terser@5.41.0:
+ terser@5.42.0:
dependencies:
'@jridgewell/source-map': 0.3.6
acorn: 8.15.0
commander: 2.20.3
source-map-support: 0.5.21
- test-exclude@6.0.0:
- dependencies:
- '@istanbuljs/schema': 0.1.3
- glob: 7.2.3
- minimatch: 3.1.2
-
text-table@0.2.0: {}
thenify-all@1.6.0:
@@ -15950,15 +14279,13 @@ snapshots:
tinyglobby@0.2.14:
dependencies:
- fdir: 6.4.5(picomatch@4.0.2)
+ fdir: 6.4.6(picomatch@4.0.2)
picomatch: 4.0.2
- tinyrainbow@1.2.0: {}
+ tinyrainbow@2.0.0: {}
tinyspy@3.0.2: {}
- tmpl@1.0.5: {}
-
to-regex-range@5.0.1:
dependencies:
is-number: 7.0.0
@@ -15986,7 +14313,7 @@ snapshots:
ts-interface-checker@0.1.13: {}
- ts-pnp@1.2.0(typescript@5.8.3):
+ tsconfck@2.1.2(typescript@5.8.3):
optionalDependencies:
typescript: 5.8.3
@@ -16010,28 +14337,24 @@ snapshots:
minimist: 1.2.8
strip-bom: 3.0.0
+ tslib@1.14.1: {}
+
tslib@2.6.2: {}
tslib@2.8.1: {}
tty-browserify@0.0.1: {}
- tween-functions@1.2.0: {}
-
type-check@0.4.0:
dependencies:
prelude-ls: 1.2.1
- type-detect@4.0.8: {}
-
type-fest@0.20.2: {}
type-fest@0.21.3: {}
type-fest@0.7.1: {}
- type-fest@0.8.1: {}
-
type-fest@2.19.0: {}
type-fest@4.41.0: {}
@@ -16069,12 +14392,23 @@ snapshots:
possible-typed-array-names: 1.1.0
reflect.getprototypeof: 1.0.10
- typedarray-to-buffer@3.1.5:
+ typedoc-plugin-markdown@4.6.4(typedoc@0.28.5(typescript@5.8.3)):
dependencies:
- is-typedarray: 1.0.0
+ typedoc: 0.28.5(typescript@5.8.3)
+
+ typedoc@0.28.5(typescript@5.8.3):
+ dependencies:
+ '@gerrit0/mini-shiki': 3.6.0
+ lunr: 2.3.9
+ markdown-it: 14.1.0
+ minimatch: 9.0.5
+ typescript: 5.8.3
+ yaml: 2.8.0
typescript@5.8.3: {}
+ uc.micro@2.1.0: {}
+
unbox-primitive@1.1.0:
dependencies:
call-bound: 1.0.4
@@ -16095,6 +14429,8 @@ snapshots:
unicode-property-aliases-ecmascript@2.1.0: {}
+ unicorn-magic@0.1.0: {}
+
unified@11.0.5:
dependencies:
'@types/unist': 3.0.3
@@ -16141,30 +14477,32 @@ snapshots:
unplugin@1.16.1:
dependencies:
- acorn: 8.14.1
+ acorn: 8.15.0
webpack-virtual-modules: 0.6.2
- unrs-resolver@1.7.10:
+ unrs-resolver@1.9.0:
dependencies:
napi-postinstall: 0.2.4
optionalDependencies:
- '@unrs/resolver-binding-darwin-arm64': 1.7.10
- '@unrs/resolver-binding-darwin-x64': 1.7.10
- '@unrs/resolver-binding-freebsd-x64': 1.7.10
- '@unrs/resolver-binding-linux-arm-gnueabihf': 1.7.10
- '@unrs/resolver-binding-linux-arm-musleabihf': 1.7.10
- '@unrs/resolver-binding-linux-arm64-gnu': 1.7.10
- '@unrs/resolver-binding-linux-arm64-musl': 1.7.10
- '@unrs/resolver-binding-linux-ppc64-gnu': 1.7.10
- '@unrs/resolver-binding-linux-riscv64-gnu': 1.7.10
- '@unrs/resolver-binding-linux-riscv64-musl': 1.7.10
- '@unrs/resolver-binding-linux-s390x-gnu': 1.7.10
- '@unrs/resolver-binding-linux-x64-gnu': 1.7.10
- '@unrs/resolver-binding-linux-x64-musl': 1.7.10
- '@unrs/resolver-binding-wasm32-wasi': 1.7.10
- '@unrs/resolver-binding-win32-arm64-msvc': 1.7.10
- '@unrs/resolver-binding-win32-ia32-msvc': 1.7.10
- '@unrs/resolver-binding-win32-x64-msvc': 1.7.10
+ '@unrs/resolver-binding-android-arm-eabi': 1.9.0
+ '@unrs/resolver-binding-android-arm64': 1.9.0
+ '@unrs/resolver-binding-darwin-arm64': 1.9.0
+ '@unrs/resolver-binding-darwin-x64': 1.9.0
+ '@unrs/resolver-binding-freebsd-x64': 1.9.0
+ '@unrs/resolver-binding-linux-arm-gnueabihf': 1.9.0
+ '@unrs/resolver-binding-linux-arm-musleabihf': 1.9.0
+ '@unrs/resolver-binding-linux-arm64-gnu': 1.9.0
+ '@unrs/resolver-binding-linux-arm64-musl': 1.9.0
+ '@unrs/resolver-binding-linux-ppc64-gnu': 1.9.0
+ '@unrs/resolver-binding-linux-riscv64-gnu': 1.9.0
+ '@unrs/resolver-binding-linux-riscv64-musl': 1.9.0
+ '@unrs/resolver-binding-linux-s390x-gnu': 1.9.0
+ '@unrs/resolver-binding-linux-x64-gnu': 1.9.0
+ '@unrs/resolver-binding-linux-x64-musl': 1.9.0
+ '@unrs/resolver-binding-wasm32-wasi': 1.9.0
+ '@unrs/resolver-binding-win32-arm64-msvc': 1.9.0
+ '@unrs/resolver-binding-win32-ia32-msvc': 1.9.0
+ '@unrs/resolver-binding-win32-x64-msvc': 1.9.0
update-browserslist-db@1.1.3(browserslist@4.25.0):
dependencies:
@@ -16176,6 +14514,8 @@ snapshots:
dependencies:
punycode: 2.3.1
+ urijs@1.19.11: {}
+
url-parse@1.5.10:
dependencies:
querystringify: 2.2.0
@@ -16217,17 +14557,15 @@ snapshots:
utila@0.4.0: {}
+ utility-types@3.11.0: {}
+
uuid@11.1.0: {}
uuid@8.3.2: {}
uuid@9.0.1: {}
- v8-to-istanbul@9.3.0:
- dependencies:
- '@jridgewell/trace-mapping': 0.3.25
- '@types/istanbul-lib-coverage': 2.0.6
- convert-source-map: 2.0.0
+ validator@13.15.15: {}
vfile-message@4.0.2:
dependencies:
@@ -16258,28 +14596,6 @@ snapshots:
vm-browserify@1.1.2: {}
- wait-on@7.2.0:
- dependencies:
- axios: 1.9.0
- joi: 17.13.3
- lodash: 4.17.21
- minimist: 1.2.8
- rxjs: 7.8.2
- transitivePeerDependencies:
- - debug
-
- wait-port@0.2.14:
- dependencies:
- chalk: 2.4.2
- commander: 3.0.2
- debug: 4.4.1
- transitivePeerDependencies:
- - supports-color
-
- walker@1.0.8:
- dependencies:
- makeerror: 1.0.12
-
warning@4.0.3:
dependencies:
loose-envify: 1.4.0
@@ -16291,7 +14607,7 @@ snapshots:
webidl-conversions@3.0.1: {}
- webpack-dev-middleware@6.1.3(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2)):
+ webpack-dev-middleware@6.1.3(webpack@5.99.9(esbuild@0.25.5)):
dependencies:
colorette: 2.0.20
memfs: 3.5.3
@@ -16299,7 +14615,7 @@ snapshots:
range-parser: 1.2.1
schema-utils: 4.3.2
optionalDependencies:
- webpack: 5.99.9(@swc/core@1.11.31)(esbuild@0.24.2)
+ webpack: 5.99.9(esbuild@0.25.5)
webpack-hot-middleware@2.26.1:
dependencies:
@@ -16313,7 +14629,7 @@ snapshots:
webpack-virtual-modules@0.6.2: {}
- webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2):
+ webpack@5.99.9(esbuild@0.25.5):
dependencies:
'@types/eslint-scope': 3.7.7
'@types/estree': 1.0.8
@@ -16321,7 +14637,7 @@ snapshots:
'@webassemblyjs/ast': 1.14.1
'@webassemblyjs/wasm-edit': 1.14.1
'@webassemblyjs/wasm-parser': 1.14.1
- acorn: 8.14.1
+ acorn: 8.15.0
browserslist: 4.25.0
chrome-trace-event: 1.0.4
enhanced-resolve: 5.18.1
@@ -16336,7 +14652,7 @@ snapshots:
neo-async: 2.6.2
schema-utils: 4.3.2
tapable: 2.2.2
- terser-webpack-plugin: 5.3.14(@swc/core@1.11.31)(esbuild@0.24.2)(webpack@5.99.9(@swc/core@1.11.31)(esbuild@0.24.2))
+ terser-webpack-plugin: 5.3.14(esbuild@0.25.5)(webpack@5.99.9(esbuild@0.25.5))
watchpack: 2.4.4
webpack-sources: 3.3.2
transitivePeerDependencies:
@@ -16380,8 +14696,6 @@ snapshots:
is-weakmap: 2.0.2
is-weakset: 2.0.4
- which-module@2.0.1: {}
-
which-typed-array@1.1.19:
dependencies:
available-typed-arrays: 1.0.7
@@ -16392,10 +14706,6 @@ snapshots:
gopd: 1.2.0
has-tostringtag: 1.0.2
- which@1.3.1:
- dependencies:
- isexe: 2.0.0
-
which@2.0.2:
dependencies:
isexe: 2.0.0
@@ -16422,28 +14732,12 @@ snapshots:
wrappy@1.0.2: {}
- write-file-atomic@3.0.3:
- dependencies:
- imurmurhash: 0.1.4
- is-typedarray: 1.0.0
- signal-exit: 3.0.7
- typedarray-to-buffer: 3.1.5
-
- write-file-atomic@4.0.2:
- dependencies:
- imurmurhash: 0.1.4
- signal-exit: 3.0.7
-
ws@8.18.2: {}
- xml@1.0.1: {}
-
xmlbuilder@15.1.1: {}
xtend@4.0.2: {}
- y18n@4.0.3: {}
-
y18n@5.0.8: {}
yallist@3.1.1: {}
@@ -16452,27 +14746,8 @@ snapshots:
yaml@2.8.0: {}
- yargs-parser@18.1.3:
- dependencies:
- camelcase: 5.3.1
- decamelize: 1.2.0
-
yargs-parser@21.1.1: {}
- yargs@15.4.1:
- dependencies:
- cliui: 6.0.0
- decamelize: 1.2.0
- find-up: 4.1.0
- get-caller-file: 2.0.5
- require-directory: 2.1.1
- require-main-filename: 2.0.0
- set-blocking: 2.0.0
- string-width: 4.2.3
- which-module: 2.0.1
- y18n: 4.0.3
- yargs-parser: 18.1.3
-
yargs@17.7.2:
dependencies:
cliui: 8.0.1
@@ -16491,11 +14766,12 @@ snapshots:
zod@3.25.56: {}
- zustand@4.5.7(@types/react@18.3.17)(react@18.3.1):
+ zustand@4.5.7(@types/react@18.3.17)(immer@9.0.21)(react@18.3.1):
dependencies:
use-sync-external-store: 1.5.0(react@18.3.1)
optionalDependencies:
'@types/react': 18.3.17
+ immer: 9.0.21
react: 18.3.1
zwitch@2.0.4: {}
diff --git a/autogpt_platform/frontend/src/api/mutators/custom-mutator.ts b/autogpt_platform/frontend/src/api/mutators/custom-mutator.ts
new file mode 100644
index 0000000000..dc7dd1065c
--- /dev/null
+++ b/autogpt_platform/frontend/src/api/mutators/custom-mutator.ts
@@ -0,0 +1,81 @@
+import { getSupabaseClient } from "@/lib/supabase/getSupabaseClient";
+
+const BASE_URL =
+ process.env.NEXT_PUBLIC_AGPT_SERVER_BASE_URL || "http://localhost:8006";
+
+const getBody = (c: Response | Request): Promise => {
+ const contentType = c.headers.get("content-type");
+
+ if (contentType && contentType.includes("application/json")) {
+ return c.json();
+ }
+
+ if (contentType && contentType.includes("application/pdf")) {
+ return c.blob() as Promise;
+ }
+
+ return c.text() as Promise;
+};
+
+const getSupabaseToken = async () => {
+ const supabase = await getSupabaseClient();
+
+ const {
+ data: { session },
+ } = (await supabase?.auth.getSession()) || {
+ data: { session: null },
+ };
+
+ return session?.access_token;
+};
+
+export const customMutator = async (
+ url: string,
+ options: RequestInit & {
+ params?: any;
+ } = {},
+): Promise => {
+ const { params, ...requestOptions } = options;
+ const method = (requestOptions.method || "GET") as
+ | "GET"
+ | "POST"
+ | "PUT"
+ | "DELETE"
+ | "PATCH";
+ const data = requestOptions.body;
+ const headers: Record = {
+ ...((requestOptions.headers as Record) || {}),
+ };
+
+ const token = await getSupabaseToken();
+
+ if (token) {
+ headers["Authorization"] = `Bearer ${token}`;
+ }
+
+ const isFormData = data instanceof FormData;
+
+ // Currently, only two content types are handled here: application/json and multipart/form-data
+ if (!isFormData && data && !headers["Content-Type"]) {
+ headers["Content-Type"] = "application/json";
+ }
+
+ const queryString = params
+ ? "?" + new URLSearchParams(params).toString()
+ : "";
+
+ const response = await fetch(`${BASE_URL}${url}${queryString}`, {
+ ...requestOptions,
+ method,
+ headers,
+ body: data,
+ });
+
+ const response_data = await getBody(response);
+
+ return {
+ status: response.status,
+ response_data,
+ headers: response.headers,
+ } as T;
+};
diff --git a/autogpt_platform/frontend/src/api/openapi.json b/autogpt_platform/frontend/src/api/openapi.json
new file mode 100644
index 0000000000..40a88952b1
--- /dev/null
+++ b/autogpt_platform/frontend/src/api/openapi.json
@@ -0,0 +1,6093 @@
+{
+ "openapi": "3.1.0",
+ "info": {
+ "title": "AutoGPT Agent Server",
+ "summary": "AutoGPT Agent Server",
+ "description": "This server is used to execute agents that are created by the AutoGPT system.",
+ "version": "0.1"
+ },
+ "paths": {
+ "/api/integrations/{provider}/login": {
+ "get": {
+ "tags": ["v1", "integrations"],
+ "summary": "Login",
+ "operationId": "getV1Login",
+ "parameters": [
+ {
+ "name": "provider",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/ProviderName",
+ "title": "The provider to initiate an OAuth flow for"
+ }
+ },
+ {
+ "name": "scopes",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string",
+ "title": "Comma-separated list of authorization scopes",
+ "default": ""
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/LoginResponse" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/integrations/{provider}/callback": {
+ "post": {
+ "tags": ["v1", "integrations"],
+ "summary": "Callback",
+ "operationId": "postV1Callback",
+ "parameters": [
+ {
+ "name": "provider",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/ProviderName",
+ "title": "The target provider for this OAuth exchange"
+ }
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/Body_postV1Callback" }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/CredentialsMetaResponse"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/integrations/credentials": {
+ "get": {
+ "tags": ["v1", "integrations"],
+ "summary": "List Credentials",
+ "operationId": "getV1ListCredentials",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "items": {
+ "$ref": "#/components/schemas/CredentialsMetaResponse"
+ },
+ "type": "array",
+ "title": "Response Getv1Listcredentials"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/integrations/{provider}/credentials": {
+ "get": {
+ "tags": ["v1", "integrations"],
+ "summary": "List Credentials By Provider",
+ "operationId": "getV1ListCredentialsByProvider",
+ "parameters": [
+ {
+ "name": "provider",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/ProviderName",
+ "title": "The provider to list credentials for"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/CredentialsMetaResponse"
+ },
+ "title": "Response Getv1Listcredentialsbyprovider"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": ["v1", "integrations"],
+ "summary": "Create Credentials",
+ "operationId": "postV1CreateCredentials",
+ "parameters": [
+ {
+ "name": "provider",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/ProviderName",
+ "title": "The provider to create credentials for"
+ }
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "oneOf": [
+ { "$ref": "#/components/schemas/OAuth2Credentials" },
+ { "$ref": "#/components/schemas/APIKeyCredentials" },
+ { "$ref": "#/components/schemas/UserPasswordCredentials" }
+ ],
+ "discriminator": {
+ "propertyName": "type",
+ "mapping": {
+ "oauth2": "#/components/schemas/OAuth2Credentials",
+ "api_key": "#/components/schemas/APIKeyCredentials",
+ "user_password": "#/components/schemas/UserPasswordCredentials"
+ }
+ },
+ "title": "Credentials"
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "oneOf": [
+ { "$ref": "#/components/schemas/OAuth2Credentials" },
+ { "$ref": "#/components/schemas/APIKeyCredentials" },
+ { "$ref": "#/components/schemas/UserPasswordCredentials" }
+ ],
+ "discriminator": {
+ "propertyName": "type",
+ "mapping": {
+ "oauth2": "#/components/schemas/OAuth2Credentials",
+ "api_key": "#/components/schemas/APIKeyCredentials",
+ "user_password": "#/components/schemas/UserPasswordCredentials"
+ }
+ },
+ "title": "Response Postv1Createcredentials"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/integrations/{provider}/credentials/{cred_id}": {
+ "get": {
+ "tags": ["v1", "integrations"],
+ "summary": "Get Credential",
+ "operationId": "getV1GetCredential",
+ "parameters": [
+ {
+ "name": "provider",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/ProviderName",
+ "title": "The provider to retrieve credentials for"
+ }
+ },
+ {
+ "name": "cred_id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "title": "The ID of the credentials to retrieve"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "oneOf": [
+ { "$ref": "#/components/schemas/OAuth2Credentials" },
+ { "$ref": "#/components/schemas/APIKeyCredentials" },
+ { "$ref": "#/components/schemas/UserPasswordCredentials" }
+ ],
+ "discriminator": {
+ "propertyName": "type",
+ "mapping": {
+ "oauth2": "#/components/schemas/OAuth2Credentials",
+ "api_key": "#/components/schemas/APIKeyCredentials",
+ "user_password": "#/components/schemas/UserPasswordCredentials"
+ }
+ },
+ "title": "Response Getv1Getcredential"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "tags": ["v1", "integrations"],
+ "summary": "Delete Credentials",
+ "operationId": "deleteV1DeleteCredentials",
+ "parameters": [
+ {
+ "name": "provider",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/ProviderName",
+ "title": "The provider to delete credentials for"
+ }
+ },
+ {
+ "name": "cred_id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "title": "The ID of the credentials to delete"
+ }
+ },
+ {
+ "name": "force",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "boolean",
+ "title": "Whether to proceed if any linked webhooks are still in use",
+ "default": false
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/CredentialsDeletionResponse"
+ },
+ {
+ "$ref": "#/components/schemas/CredentialsDeletionNeedsConfirmationResponse"
+ }
+ ],
+ "title": "Response Deletev1Deletecredentials"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/integrations/{provider}/webhooks/{webhook_id}/ingress": {
+ "post": {
+ "tags": ["v1", "integrations"],
+ "summary": "Webhook Ingress Generic",
+ "operationId": "postV1WebhookIngressGeneric",
+ "parameters": [
+ {
+ "name": "provider",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/ProviderName",
+ "title": "Provider where the webhook was registered"
+ }
+ },
+ {
+ "name": "webhook_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Our ID for the webhook" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": { "application/json": { "schema": {} } }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/integrations/webhooks/{webhook_id}/ping": {
+ "post": {
+ "tags": ["v1", "integrations"],
+ "summary": "Webhook Ping",
+ "operationId": "postV1WebhookPing",
+ "parameters": [
+ {
+ "name": "webhook_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Our ID for the webhook" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": { "application/json": { "schema": {} } }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/analytics/log_raw_metric": {
+ "post": {
+ "tags": ["v1", "analytics"],
+ "summary": "Log Raw Metric",
+ "operationId": "postV1LogRawMetric",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_postV1LogRawMetric"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": { "application/json": { "schema": {} } }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/analytics/log_raw_analytics": {
+ "post": {
+ "tags": ["v1", "analytics"],
+ "summary": "Log Raw Analytics",
+ "operationId": "postV1LogRawAnalytics",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_postV1LogRawAnalytics"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": { "application/json": { "schema": {} } }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/auth/user": {
+ "post": {
+ "tags": ["v1", "auth"],
+ "summary": "Get or create user",
+ "operationId": "postV1Get or create user",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": { "application/json": { "schema": {} } }
+ }
+ }
+ }
+ },
+ "/api/auth/user/email": {
+ "post": {
+ "tags": ["v1", "auth"],
+ "summary": "Update user email",
+ "operationId": "postV1Update user email",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": { "type": "string", "title": "Email" }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "additionalProperties": { "type": "string" },
+ "type": "object",
+ "title": "Response Postv1Update User Email"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/auth/user/preferences": {
+ "get": {
+ "tags": ["v1", "auth"],
+ "summary": "Get notification preferences",
+ "operationId": "getV1Get notification preferences",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotificationPreference"
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": ["v1", "auth"],
+ "summary": "Update notification preferences",
+ "operationId": "postV1Update notification preferences",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotificationPreferenceDTO"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotificationPreference"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/onboarding": {
+ "get": {
+ "tags": ["v1", "onboarding"],
+ "summary": "Get onboarding status",
+ "operationId": "getV1Get onboarding status",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": { "application/json": { "schema": {} } }
+ }
+ }
+ },
+ "patch": {
+ "tags": ["v1", "onboarding"],
+ "summary": "Update onboarding progress",
+ "operationId": "patchV1Update onboarding progress",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/UserOnboardingUpdate" }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": { "application/json": { "schema": {} } }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/onboarding/agents": {
+ "get": {
+ "tags": ["v1", "onboarding"],
+ "summary": "Get recommended agents",
+ "operationId": "getV1Get recommended agents",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": { "application/json": { "schema": {} } }
+ }
+ }
+ }
+ },
+ "/api/onboarding/enabled": {
+ "get": {
+ "tags": ["v1", "onboarding", "public"],
+ "summary": "Check onboarding enabled",
+ "operationId": "getV1Check onboarding enabled",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": { "application/json": { "schema": {} } }
+ }
+ }
+ }
+ },
+ "/api/blocks": {
+ "get": {
+ "tags": ["v1", "blocks"],
+ "summary": "List available blocks",
+ "operationId": "getV1List available blocks",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "items": { "additionalProperties": true, "type": "object" },
+ "type": "array",
+ "title": "Response Getv1List Available Blocks"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/blocks/{block_id}/execute": {
+ "post": {
+ "tags": ["v1", "blocks"],
+ "summary": "Execute graph block",
+ "operationId": "postV1Execute graph block",
+ "parameters": [
+ {
+ "name": "block_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Block Id" }
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "additionalProperties": true,
+ "title": "Data"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "additionalProperties": { "type": "array", "items": {} },
+ "title": "Response Postv1Execute Graph Block"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/credits": {
+ "get": {
+ "tags": ["v1", "credits"],
+ "summary": "Get user credits",
+ "operationId": "getV1Get user credits",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "additionalProperties": { "type": "integer" },
+ "type": "object",
+ "title": "Response Getv1Get User Credits"
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": ["v1", "credits"],
+ "summary": "Request credit top up",
+ "operationId": "postV1Request credit top up",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/RequestTopUp" }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": { "application/json": { "schema": {} } }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ },
+ "patch": {
+ "tags": ["v1", "credits"],
+ "summary": "Fulfill checkout session",
+ "operationId": "patchV1Fulfill checkout session",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": { "application/json": { "schema": {} } }
+ }
+ }
+ }
+ },
+ "/api/credits/{transaction_key}/refund": {
+ "post": {
+ "tags": ["v1", "credits"],
+ "summary": "Refund credit transaction",
+ "operationId": "postV1Refund credit transaction",
+ "parameters": [
+ {
+ "name": "transaction_key",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Transaction Key" }
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "additionalProperties": { "type": "string" },
+ "title": "Metadata"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "integer",
+ "title": "Response Postv1Refund Credit Transaction"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/credits/auto-top-up": {
+ "get": {
+ "tags": ["v1", "credits"],
+ "summary": "Get auto top up",
+ "operationId": "getV1Get auto top up",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/AutoTopUpConfig" }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": ["v1", "credits"],
+ "summary": "Configure auto top up",
+ "operationId": "postV1Configure auto top up",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/AutoTopUpConfig" }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "string",
+ "title": "Response Postv1Configure Auto Top Up"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/credits/stripe_webhook": {
+ "post": {
+ "tags": ["v1", "credits"],
+ "summary": "Handle Stripe webhooks",
+ "operationId": "postV1Handle stripe webhooks",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": { "application/json": { "schema": {} } }
+ }
+ }
+ }
+ },
+ "/api/credits/manage": {
+ "get": {
+ "tags": ["v1", "credits"],
+ "summary": "Manage payment methods",
+ "operationId": "getV1Manage payment methods",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "additionalProperties": { "type": "string" },
+ "type": "object",
+ "title": "Response Getv1Manage Payment Methods"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/credits/transactions": {
+ "get": {
+ "tags": ["v1", "credits"],
+ "summary": "Get credit history",
+ "operationId": "getV1Get credit history",
+ "parameters": [
+ {
+ "name": "transaction_time",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "anyOf": [
+ { "type": "string", "format": "date-time" },
+ { "type": "null" }
+ ],
+ "title": "Transaction Time"
+ }
+ },
+ {
+ "name": "transaction_type",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Transaction Type"
+ }
+ },
+ {
+ "name": "transaction_count_limit",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "default": 100,
+ "title": "Transaction Count Limit"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/TransactionHistory" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/credits/refunds": {
+ "get": {
+ "tags": ["v1", "credits"],
+ "summary": "Get refund requests",
+ "operationId": "getV1Get refund requests",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "items": { "$ref": "#/components/schemas/RefundRequest" },
+ "type": "array",
+ "title": "Response Getv1Get Refund Requests"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/graphs": {
+ "get": {
+ "tags": ["v1", "graphs"],
+ "summary": "List user graphs",
+ "operationId": "getV1List user graphs",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "items": { "$ref": "#/components/schemas/GraphModel" },
+ "type": "array",
+ "title": "Response Getv1List User Graphs"
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": ["v1", "graphs"],
+ "summary": "Create new graph",
+ "operationId": "postV1Create new graph",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/CreateGraph" }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/GraphModel" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/graphs/{graph_id}/versions/{version}": {
+ "get": {
+ "tags": ["v1", "graphs"],
+ "summary": "Get graph version",
+ "operationId": "getV1Get graph version",
+ "parameters": [
+ {
+ "name": "graph_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Graph Id" }
+ },
+ {
+ "name": "version",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "anyOf": [{ "type": "integer" }, { "type": "null" }],
+ "title": "Version"
+ }
+ },
+ {
+ "name": "for_export",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "boolean",
+ "default": false,
+ "title": "For Export"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/GraphModel" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/graphs/{graph_id}": {
+ "get": {
+ "tags": ["v1", "graphs"],
+ "summary": "Get specific graph",
+ "operationId": "getV1Get specific graph",
+ "parameters": [
+ {
+ "name": "graph_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Graph Id" }
+ },
+ {
+ "name": "version",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "anyOf": [{ "type": "integer" }, { "type": "null" }],
+ "title": "Version"
+ }
+ },
+ {
+ "name": "for_export",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "boolean",
+ "default": false,
+ "title": "For Export"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/GraphModel" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "tags": ["v1", "graphs"],
+ "summary": "Delete graph permanently",
+ "operationId": "deleteV1Delete graph permanently",
+ "parameters": [
+ {
+ "name": "graph_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Graph Id" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/DeleteGraphResponse" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ },
+ "put": {
+ "tags": ["v1", "graphs"],
+ "summary": "Update graph version",
+ "operationId": "putV1Update graph version",
+ "parameters": [
+ {
+ "name": "graph_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Graph Id" }
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/Graph" }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/GraphModel" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/graphs/{graph_id}/versions": {
+ "get": {
+ "tags": ["v1", "graphs"],
+ "summary": "Get all graph versions",
+ "operationId": "getV1Get all graph versions",
+ "parameters": [
+ {
+ "name": "graph_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Graph Id" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": { "$ref": "#/components/schemas/GraphModel" },
+ "title": "Response Getv1Get All Graph Versions"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/graphs/{graph_id}/versions/active": {
+ "put": {
+ "tags": ["v1", "graphs"],
+ "summary": "Set active graph version",
+ "operationId": "putV1Set active graph version",
+ "parameters": [
+ {
+ "name": "graph_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Graph Id" }
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/SetGraphActiveVersion" }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": { "application/json": { "schema": {} } }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/graphs/{graph_id}/execute/{graph_version}": {
+ "post": {
+ "tags": ["v1", "graphs"],
+ "summary": "Execute graph agent",
+ "operationId": "postV1Execute graph agent",
+ "parameters": [
+ {
+ "name": "graph_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Graph Id" }
+ },
+ {
+ "name": "graph_version",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "anyOf": [{ "type": "integer" }, { "type": "null" }],
+ "title": "Graph Version"
+ }
+ },
+ {
+ "name": "preset_id",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Preset Id"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_postV1Execute_graph_agent"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ExecuteGraphResponse"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/graphs/{graph_id}/executions/{graph_exec_id}/stop": {
+ "post": {
+ "tags": ["v1", "graphs"],
+ "summary": "Stop graph execution",
+ "operationId": "postV1Stop graph execution",
+ "parameters": [
+ {
+ "name": "graph_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Graph Id" }
+ },
+ {
+ "name": "graph_exec_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Graph Exec Id" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/GraphExecution" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/executions": {
+ "get": {
+ "tags": ["v1", "graphs"],
+ "summary": "Get all executions",
+ "operationId": "getV1Get all executions",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "items": {
+ "$ref": "#/components/schemas/GraphExecutionMeta"
+ },
+ "type": "array",
+ "title": "Response Getv1Get All Executions"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/graphs/{graph_id}/executions": {
+ "get": {
+ "tags": ["v1", "graphs"],
+ "summary": "Get graph executions",
+ "operationId": "getV1Get graph executions",
+ "parameters": [
+ {
+ "name": "graph_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Graph Id" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/GraphExecutionMeta"
+ },
+ "title": "Response Getv1Get Graph Executions"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/graphs/{graph_id}/executions/{graph_exec_id}": {
+ "get": {
+ "tags": ["v1", "graphs"],
+ "summary": "Get execution details",
+ "operationId": "getV1Get execution details",
+ "parameters": [
+ {
+ "name": "graph_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Graph Id" }
+ },
+ {
+ "name": "graph_exec_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Graph Exec Id" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "anyOf": [
+ { "$ref": "#/components/schemas/GraphExecution" },
+ { "$ref": "#/components/schemas/GraphExecutionWithNodes" }
+ ],
+ "title": "Response Getv1Get Execution Details"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/executions/{graph_exec_id}": {
+ "delete": {
+ "tags": ["v1", "graphs"],
+ "summary": "Delete graph execution",
+ "operationId": "deleteV1Delete graph execution",
+ "parameters": [
+ {
+ "name": "graph_exec_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Graph Exec Id" }
+ }
+ ],
+ "responses": {
+ "204": { "description": "Successful Response" },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/schedules": {
+ "post": {
+ "tags": ["v1", "schedules"],
+ "summary": "Create execution schedule",
+ "operationId": "postV1Create execution schedule",
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ScheduleCreationRequest"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/GraphExecutionJobInfo"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ },
+ "get": {
+ "tags": ["v1", "schedules"],
+ "summary": "List execution schedules",
+ "operationId": "getV1List execution schedules",
+ "parameters": [
+ {
+ "name": "graph_id",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Graph Id"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/GraphExecutionJobInfo"
+ },
+ "title": "Response Getv1List Execution Schedules"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/schedules/{schedule_id}": {
+ "delete": {
+ "tags": ["v1", "schedules"],
+ "summary": "Delete execution schedule",
+ "operationId": "deleteV1Delete execution schedule",
+ "parameters": [
+ {
+ "name": "schedule_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Schedule Id" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "additionalProperties": true,
+ "title": "Response Deletev1Delete Execution Schedule"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/api-keys": {
+ "get": {
+ "tags": ["v1", "api-keys"],
+ "summary": "List user API keys",
+ "description": "List all API keys for the user",
+ "operationId": "getV1List user api keys",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "anyOf": [
+ {
+ "items": {
+ "$ref": "#/components/schemas/APIKeyWithoutHash"
+ },
+ "type": "array"
+ },
+ {
+ "additionalProperties": { "type": "string" },
+ "type": "object"
+ }
+ ],
+ "title": "Response Getv1List User Api Keys"
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": ["v1", "api-keys"],
+ "summary": "Create new API key",
+ "description": "Create a new API key",
+ "operationId": "postV1Create new api key",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/CreateAPIKeyRequest" }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/CreateAPIKeyResponse"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/api-keys/{key_id}": {
+ "get": {
+ "tags": ["v1", "api-keys"],
+ "summary": "Get specific API key",
+ "description": "Get a specific API key",
+ "operationId": "getV1Get specific api key",
+ "parameters": [
+ {
+ "name": "key_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Key Id" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/APIKeyWithoutHash" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "tags": ["v1", "api-keys"],
+ "summary": "Revoke API key",
+ "description": "Revoke an API key",
+ "operationId": "deleteV1Revoke api key",
+ "parameters": [
+ {
+ "name": "key_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Key Id" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/APIKeyWithoutHash" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/api-keys/{key_id}/suspend": {
+ "post": {
+ "tags": ["v1", "api-keys"],
+ "summary": "Suspend API key",
+ "description": "Suspend an API key",
+ "operationId": "postV1Suspend api key",
+ "parameters": [
+ {
+ "name": "key_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Key Id" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/APIKeyWithoutHash" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/api-keys/{key_id}/permissions": {
+ "put": {
+ "tags": ["v1", "api-keys"],
+ "summary": "Update key permissions",
+ "description": "Update API key permissions",
+ "operationId": "putV1Update key permissions",
+ "parameters": [
+ {
+ "name": "key_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Key Id" }
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UpdatePermissionsRequest"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/APIKeyWithoutHash" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/store/profile": {
+ "get": {
+ "tags": ["v2", "store", "private"],
+ "summary": "Get user profile",
+ "description": "Get the profile details for the authenticated user.",
+ "operationId": "getV2Get user profile",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/ProfileDetails" }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": ["v2", "store", "private"],
+ "summary": "Update user profile",
+ "description": "Update the store profile for the authenticated user.\n\nArgs:\n profile (Profile): The updated profile details\n user_id (str): ID of the authenticated user\n\nReturns:\n CreatorDetails: The updated profile\n\nRaises:\n HTTPException: If there is an error updating the profile",
+ "operationId": "postV2Update user profile",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/Profile" }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/CreatorDetails" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/store/agents": {
+ "get": {
+ "tags": ["v2", "store", "public"],
+ "summary": "List store agents",
+ "description": "Get a paginated list of agents from the store with optional filtering and sorting.\n\nArgs:\n featured (bool, optional): Filter to only show featured agents. Defaults to False.\n creator (str | None, optional): Filter agents by creator username. Defaults to None.\n sorted_by (str | None, optional): Sort agents by \"runs\" or \"rating\". Defaults to None.\n search_query (str | None, optional): Search agents by name, subheading and description. Defaults to None.\n category (str | None, optional): Filter agents by category. Defaults to None.\n page (int, optional): Page number for pagination. Defaults to 1.\n page_size (int, optional): Number of agents per page. Defaults to 20.\n\nReturns:\n StoreAgentsResponse: Paginated list of agents matching the filters\n\nRaises:\n HTTPException: If page or page_size are less than 1\n\nUsed for:\n- Home Page Featured Agents\n- Home Page Top Agents\n- Search Results\n- Agent Details - Other Agents By Creator\n- Agent Details - Similar Agents\n- Creator Details - Agents By Creator",
+ "operationId": "getV2List store agents",
+ "parameters": [
+ {
+ "name": "featured",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "boolean",
+ "default": false,
+ "title": "Featured"
+ }
+ },
+ {
+ "name": "creator",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Creator"
+ }
+ },
+ {
+ "name": "sorted_by",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Sorted By"
+ }
+ },
+ {
+ "name": "search_query",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Search Query"
+ }
+ },
+ {
+ "name": "category",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Category"
+ }
+ },
+ {
+ "name": "page",
+ "in": "query",
+ "required": false,
+ "schema": { "type": "integer", "default": 1, "title": "Page" }
+ },
+ {
+ "name": "page_size",
+ "in": "query",
+ "required": false,
+ "schema": { "type": "integer", "default": 20, "title": "Page Size" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/StoreAgentsResponse" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/store/agents/{username}/{agent_name}": {
+ "get": {
+ "tags": ["v2", "store", "public"],
+ "summary": "Get specific agent",
+ "description": "This is only used on the AgentDetails Page\n\nIt returns the store listing agents details.",
+ "operationId": "getV2Get specific agent",
+ "parameters": [
+ {
+ "name": "username",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Username" }
+ },
+ {
+ "name": "agent_name",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Agent Name" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/StoreAgentDetails" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/store/graph/{store_listing_version_id}": {
+ "get": {
+ "tags": ["v2", "store"],
+ "summary": "Get agent graph",
+ "description": "Get Agent Graph from Store Listing Version ID.",
+ "operationId": "getV2Get agent graph",
+ "parameters": [
+ {
+ "name": "store_listing_version_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Store Listing Version Id" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": { "application/json": { "schema": {} } }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/store/agents/{store_listing_version_id}": {
+ "get": {
+ "tags": ["v2", "store"],
+ "summary": "Get agent by version",
+ "description": "Get Store Agent Details from Store Listing Version ID.",
+ "operationId": "getV2Get agent by version",
+ "parameters": [
+ {
+ "name": "store_listing_version_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Store Listing Version Id" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/StoreAgentDetails" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/store/agents/{username}/{agent_name}/review": {
+ "post": {
+ "tags": ["v2", "store"],
+ "summary": "Create agent review",
+ "description": "Create a review for a store agent.\n\nArgs:\n username: Creator's username\n agent_name: Name/slug of the agent\n review: Review details including score and optional comments\n user_id: ID of authenticated user creating the review\n\nReturns:\n The created review",
+ "operationId": "postV2Create agent review",
+ "parameters": [
+ {
+ "name": "username",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Username" }
+ },
+ {
+ "name": "agent_name",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Agent Name" }
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/StoreReviewCreate" }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/StoreReview" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/store/creators": {
+ "get": {
+ "tags": ["v2", "store", "public"],
+ "summary": "List store creators",
+ "description": "This is needed for:\n- Home Page Featured Creators\n- Search Results Page\n\n---\n\nTo support this functionality we need:\n- featured: bool - to limit the list to just featured agents\n- search_query: str - vector search based on the creators profile description.\n- sorted_by: [agent_rating, agent_runs] -",
+ "operationId": "getV2List store creators",
+ "parameters": [
+ {
+ "name": "featured",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "boolean",
+ "default": false,
+ "title": "Featured"
+ }
+ },
+ {
+ "name": "search_query",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Search Query"
+ }
+ },
+ {
+ "name": "sorted_by",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Sorted By"
+ }
+ },
+ {
+ "name": "page",
+ "in": "query",
+ "required": false,
+ "schema": { "type": "integer", "default": 1, "title": "Page" }
+ },
+ {
+ "name": "page_size",
+ "in": "query",
+ "required": false,
+ "schema": { "type": "integer", "default": 20, "title": "Page Size" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/CreatorsResponse" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/store/creator/{username}": {
+ "get": {
+ "tags": ["v2", "store", "public"],
+ "summary": "Get creator details",
+ "description": "Get the details of a creator\n- Creator Details Page",
+ "operationId": "getV2Get creator details",
+ "parameters": [
+ {
+ "name": "username",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Username" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/CreatorDetails" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/store/myagents": {
+ "get": {
+ "tags": ["v2", "store", "private"],
+ "summary": "Get my agents",
+ "operationId": "getV2Get my agents",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/MyAgentsResponse" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/store/submissions/{submission_id}": {
+ "delete": {
+ "tags": ["v2", "store", "private"],
+ "summary": "Delete store submission",
+ "description": "Delete a store listing submission.\n\nArgs:\n user_id (str): ID of the authenticated user\n submission_id (str): ID of the submission to be deleted\n\nReturns:\n bool: True if the submission was successfully deleted, False otherwise",
+ "operationId": "deleteV2Delete store submission",
+ "parameters": [
+ {
+ "name": "submission_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Submission Id" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "boolean",
+ "title": "Response Deletev2Delete Store Submission"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/store/submissions": {
+ "get": {
+ "tags": ["v2", "store", "private"],
+ "summary": "List my submissions",
+ "description": "Get a paginated list of store submissions for the authenticated user.\n\nArgs:\n user_id (str): ID of the authenticated user\n page (int, optional): Page number for pagination. Defaults to 1.\n page_size (int, optional): Number of submissions per page. Defaults to 20.\n\nReturns:\n StoreListingsResponse: Paginated list of store submissions\n\nRaises:\n HTTPException: If page or page_size are less than 1",
+ "operationId": "getV2List my submissions",
+ "parameters": [
+ {
+ "name": "page",
+ "in": "query",
+ "required": false,
+ "schema": { "type": "integer", "default": 1, "title": "Page" }
+ },
+ {
+ "name": "page_size",
+ "in": "query",
+ "required": false,
+ "schema": { "type": "integer", "default": 20, "title": "Page Size" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/StoreSubmissionsResponse"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": ["v2", "store", "private"],
+ "summary": "Create store submission",
+ "description": "Create a new store listing submission.\n\nArgs:\n submission_request (StoreSubmissionRequest): The submission details\n user_id (str): ID of the authenticated user submitting the listing\n\nReturns:\n StoreSubmission: The created store submission\n\nRaises:\n HTTPException: If there is an error creating the submission",
+ "operationId": "postV2Create store submission",
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/StoreSubmissionRequest"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/StoreSubmission" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/store/submissions/media": {
+ "post": {
+ "tags": ["v2", "store", "private"],
+ "summary": "Upload submission media",
+ "description": "Upload media (images/videos) for a store listing submission.\n\nArgs:\n file (UploadFile): The media file to upload\n user_id (str): ID of the authenticated user uploading the media\n\nReturns:\n str: URL of the uploaded media file\n\nRaises:\n HTTPException: If there is an error uploading the media",
+ "operationId": "postV2Upload submission media",
+ "requestBody": {
+ "content": {
+ "multipart/form-data": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_postV2Upload_submission_media"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": { "application/json": { "schema": {} } }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/store/submissions/generate_image": {
+ "post": {
+ "tags": ["v2", "store", "private"],
+ "summary": "Generate submission image",
+ "description": "Generate an image for a store listing submission.\n\nArgs:\n agent_id (str): ID of the agent to generate an image for\n user_id (str): ID of the authenticated user\n\nReturns:\n JSONResponse: JSON containing the URL of the generated image",
+ "operationId": "postV2Generate submission image",
+ "parameters": [
+ {
+ "name": "agent_id",
+ "in": "query",
+ "required": true,
+ "schema": { "type": "string", "title": "Agent Id" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": { "application/json": { "schema": {} } }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/store/download/agents/{store_listing_version_id}": {
+ "get": {
+ "tags": ["v2", "store", "public"],
+ "summary": "Download agent file",
+ "description": "Download the agent file by streaming its content.\n\nArgs:\n store_listing_version_id (str): The ID of the agent to download\n\nReturns:\n StreamingResponse: A streaming response containing the agent's graph data.\n\nRaises:\n HTTPException: If the agent is not found or an unexpected error occurs.",
+ "operationId": "getV2Download agent file",
+ "parameters": [
+ {
+ "name": "store_listing_version_id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "description": "The ID of the agent to download",
+ "title": "Store Listing Version Id"
+ },
+ "description": "The ID of the agent to download"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": { "application/json": { "schema": {} } }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/store/admin/listings": {
+ "get": {
+ "tags": ["v2", "admin", "store", "admin"],
+ "summary": "Get Admin Listings History",
+ "description": "Get store listings with their version history for admins.\n\nThis provides a consolidated view of listings with their versions,\nallowing for an expandable UI in the admin dashboard.\n\nArgs:\n status: Filter by submission status (PENDING, APPROVED, REJECTED)\n search: Search by name, description, or user email\n page: Page number for pagination\n page_size: Number of items per page\n\nReturns:\n StoreListingsWithVersionsResponse with listings and their versions",
+ "operationId": "getV2Get admin listings history",
+ "parameters": [
+ {
+ "name": "status",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "anyOf": [
+ { "$ref": "#/components/schemas/SubmissionStatus" },
+ { "type": "null" }
+ ],
+ "title": "Status"
+ }
+ },
+ {
+ "name": "search",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Search"
+ }
+ },
+ {
+ "name": "page",
+ "in": "query",
+ "required": false,
+ "schema": { "type": "integer", "default": 1, "title": "Page" }
+ },
+ {
+ "name": "page_size",
+ "in": "query",
+ "required": false,
+ "schema": { "type": "integer", "default": 20, "title": "Page Size" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/StoreListingsWithVersionsResponse"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/store/admin/submissions/{store_listing_version_id}/review": {
+ "post": {
+ "tags": ["v2", "admin", "store", "admin"],
+ "summary": "Review Store Submission",
+ "description": "Review a store listing submission.\n\nArgs:\n store_listing_version_id: ID of the submission to review\n request: Review details including approval status and comments\n user: Authenticated admin user performing the review\n\nReturns:\n StoreSubmission with updated review information",
+ "operationId": "postV2Review store submission",
+ "parameters": [
+ {
+ "name": "store_listing_version_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Store Listing Version Id" }
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ReviewSubmissionRequest"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/StoreSubmission" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/store/admin/submissions/download/{store_listing_version_id}": {
+ "get": {
+ "tags": ["v2", "admin", "store", "admin", "store", "admin"],
+ "summary": "Admin Download Agent File",
+ "description": "Download the agent file by streaming its content.\n\nArgs:\n store_listing_version_id (str): The ID of the agent to download\n\nReturns:\n StreamingResponse: A streaming response containing the agent's graph data.\n\nRaises:\n HTTPException: If the agent is not found or an unexpected error occurs.",
+ "operationId": "getV2Admin download agent file",
+ "parameters": [
+ {
+ "name": "store_listing_version_id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "description": "The ID of the agent to download",
+ "title": "Store Listing Version Id"
+ },
+ "description": "The ID of the agent to download"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": { "application/json": { "schema": {} } }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/credits/admin/add_credits": {
+ "post": {
+ "tags": ["v2", "admin", "credits", "admin"],
+ "summary": "Add Credits to User",
+ "operationId": "postV2Add credits to user",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_postV2Add_credits_to_user"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AddUserCreditsResponse"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/credits/admin/users_history": {
+ "get": {
+ "tags": ["v2", "admin", "credits", "admin"],
+ "summary": "Get All Users History",
+ "operationId": "getV2Get all users history",
+ "parameters": [
+ {
+ "name": "search",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Search"
+ }
+ },
+ {
+ "name": "page",
+ "in": "query",
+ "required": false,
+ "schema": { "type": "integer", "default": 1, "title": "Page" }
+ },
+ {
+ "name": "page_size",
+ "in": "query",
+ "required": false,
+ "schema": { "type": "integer", "default": 20, "title": "Page Size" }
+ },
+ {
+ "name": "transaction_filter",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "anyOf": [
+ { "$ref": "#/components/schemas/CreditTransactionType" },
+ { "type": "null" }
+ ],
+ "title": "Transaction Filter"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/UserHistoryResponse" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/library/presets": {
+ "get": {
+ "tags": ["v2", "presets"],
+ "summary": "List presets",
+ "description": "Retrieve a paginated list of presets for the current user.",
+ "operationId": "getV2List presets",
+ "parameters": [
+ {
+ "name": "page",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "minimum": 1,
+ "default": 1,
+ "title": "Page"
+ }
+ },
+ {
+ "name": "page_size",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "minimum": 1,
+ "default": 10,
+ "title": "Page Size"
+ }
+ },
+ {
+ "name": "graph_id",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "description": "Allows to filter presets by a specific agent graph",
+ "title": "Graph Id"
+ },
+ "description": "Allows to filter presets by a specific agent graph"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/LibraryAgentPresetResponse"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": ["v2", "presets"],
+ "summary": "Create a new preset",
+ "description": "Create a new preset for the current user.",
+ "operationId": "postV2Create a new preset",
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "anyOf": [
+ {
+ "$ref": "#/components/schemas/LibraryAgentPresetCreatable"
+ },
+ {
+ "$ref": "#/components/schemas/LibraryAgentPresetCreatableFromGraphExecution"
+ }
+ ],
+ "title": "Preset"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/LibraryAgentPreset" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/library/presets/{preset_id}": {
+ "get": {
+ "tags": ["v2", "presets"],
+ "summary": "Get a specific preset",
+ "description": "Retrieve details for a specific preset by its ID.",
+ "operationId": "getV2Get a specific preset",
+ "parameters": [
+ {
+ "name": "preset_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Preset Id" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/LibraryAgentPreset" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ },
+ "patch": {
+ "tags": ["v2", "presets"],
+ "summary": "Update an existing preset",
+ "description": "Update an existing preset by its ID.",
+ "operationId": "patchV2Update an existing preset",
+ "parameters": [
+ {
+ "name": "preset_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Preset Id" }
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/LibraryAgentPresetUpdatable"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/LibraryAgentPreset" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "tags": ["v2", "presets"],
+ "summary": "Delete a preset",
+ "description": "Delete an existing preset by its ID.",
+ "operationId": "deleteV2Delete a preset",
+ "parameters": [
+ {
+ "name": "preset_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Preset Id" }
+ }
+ ],
+ "responses": {
+ "204": { "description": "Successful Response" },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/library/presets/{preset_id}/execute": {
+ "post": {
+ "tags": ["v2", "presets", "presets"],
+ "summary": "Execute a preset",
+ "description": "Execute a preset with the given graph and node input for the current user.",
+ "operationId": "postV2Execute a preset",
+ "parameters": [
+ {
+ "name": "preset_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Preset Id" }
+ },
+ {
+ "name": "graph_id",
+ "in": "query",
+ "required": true,
+ "schema": { "type": "string", "title": "Graph Id" }
+ },
+ {
+ "name": "graph_version",
+ "in": "query",
+ "required": true,
+ "schema": { "type": "integer", "title": "Graph Version" }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_postV2Execute_a_preset"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "additionalProperties": true,
+ "title": "Response Postv2Execute A Preset"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/library/agents": {
+ "get": {
+ "tags": ["v2", "library", "private"],
+ "summary": "List Library Agents",
+ "description": "Get all agents in the user's library (both created and saved).\n\nArgs:\n user_id: ID of the authenticated user.\n search_term: Optional search term to filter agents by name/description.\n filter_by: List of filters to apply (favorites, created by user).\n sort_by: List of sorting criteria (created date, updated date).\n page: Page number to retrieve.\n page_size: Number of agents per page.\n\nReturns:\n A LibraryAgentResponse containing agents and pagination metadata.\n\nRaises:\n HTTPException: If a server/database error occurs.",
+ "operationId": "getV2List library agents",
+ "parameters": [
+ {
+ "name": "search_term",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "description": "Search term to filter agents",
+ "title": "Search Term"
+ },
+ "description": "Search term to filter agents"
+ },
+ {
+ "name": "sort_by",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "$ref": "#/components/schemas/LibraryAgentSort",
+ "description": "Criteria to sort results by",
+ "default": "updatedAt"
+ },
+ "description": "Criteria to sort results by"
+ },
+ {
+ "name": "page",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "minimum": 1,
+ "description": "Page number to retrieve (must be >= 1)",
+ "default": 1,
+ "title": "Page"
+ },
+ "description": "Page number to retrieve (must be >= 1)"
+ },
+ {
+ "name": "page_size",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "minimum": 1,
+ "description": "Number of agents per page (must be >= 1)",
+ "default": 15,
+ "title": "Page Size"
+ },
+ "description": "Number of agents per page (must be >= 1)"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/LibraryAgentResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server error",
+ "content": { "application/json": {} }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": ["v2", "library", "private"],
+ "summary": "Add Marketplace Agent",
+ "description": "Add an agent from the marketplace to the user's library.\n\nArgs:\n store_listing_version_id: ID of the store listing version to add.\n user_id: ID of the authenticated user.\n\nReturns:\n library_model.LibraryAgent: Agent added to the library\n\nRaises:\n HTTPException(404): If the listing version is not found.\n HTTPException(500): If a server/database error occurs.",
+ "operationId": "postV2Add marketplace agent",
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_postV2Add_marketplace_agent"
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "Agent added successfully",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/LibraryAgent" }
+ }
+ }
+ },
+ "404": { "description": "Store listing version not found" },
+ "500": { "description": "Server error" },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/library/agents/{library_agent_id}": {
+ "get": {
+ "tags": ["v2", "library", "private"],
+ "summary": "Get Library Agent",
+ "operationId": "getV2Get library agent",
+ "parameters": [
+ {
+ "name": "library_agent_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Library Agent Id" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/LibraryAgent" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ },
+ "put": {
+ "tags": ["v2", "library", "private"],
+ "summary": "Update Library Agent",
+ "description": "Update the library agent with the given fields.\n\nArgs:\n library_agent_id: ID of the library agent to update.\n payload: Fields to update (auto_update_version, is_favorite, etc.).\n user_id: ID of the authenticated user.\n\nReturns:\n 204 (No Content) on success.\n\nRaises:\n HTTPException(500): If a server/database error occurs.",
+ "operationId": "putV2Update library agent",
+ "parameters": [
+ {
+ "name": "library_agent_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Library Agent Id" }
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/LibraryAgentUpdateRequest"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": { "description": "Agent updated successfully" },
+ "500": { "description": "Server error" },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/library/agents/marketplace/{store_listing_version_id}": {
+ "get": {
+ "tags": ["v2", "library", "private", "store, library"],
+ "summary": "Get Agent By Store ID",
+ "description": "Get Library Agent from Store Listing Version ID.",
+ "operationId": "getV2Get agent by store id",
+ "parameters": [
+ {
+ "name": "store_listing_version_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Store Listing Version Id" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "anyOf": [
+ { "$ref": "#/components/schemas/LibraryAgent" },
+ { "type": "null" }
+ ],
+ "title": "Response Getv2Get Agent By Store Id"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/library/agents/{library_agent_id}/fork": {
+ "post": {
+ "tags": ["v2", "library", "private"],
+ "summary": "Fork Library Agent",
+ "operationId": "postV2Fork library agent",
+ "parameters": [
+ {
+ "name": "library_agent_id",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "title": "Library Agent Id" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/LibraryAgent" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/otto/ask": {
+ "post": {
+ "tags": ["v2", "otto"],
+ "summary": "Proxy Otto Chat Request",
+ "description": "Proxy requests to Otto API while adding necessary security headers and logging.\nRequires an authenticated user.",
+ "operationId": "postV2Proxy otto chat request",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/ChatRequest" }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/ApiResponse" }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/turnstile/verify": {
+ "post": {
+ "tags": ["v2", "turnstile"],
+ "summary": "Verify Turnstile Token",
+ "description": "Verify a Cloudflare Turnstile token.\nThis endpoint verifies a token returned by the Cloudflare Turnstile challenge\non the client side. It returns whether the verification was successful.",
+ "operationId": "postV2Verify turnstile token",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TurnstileVerifyRequest"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TurnstileVerifyResponse"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/email/unsubscribe": {
+ "post": {
+ "tags": ["v1", "email"],
+ "summary": "One Click Email Unsubscribe",
+ "operationId": "postV1One click email unsubscribe",
+ "parameters": [
+ {
+ "name": "token",
+ "in": "query",
+ "required": true,
+ "schema": { "type": "string", "title": "Token" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": { "application/json": { "schema": {} } }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/email/": {
+ "post": {
+ "tags": ["v1", "email"],
+ "summary": "Handle Postmark Email Webhooks",
+ "operationId": "postV1Handle postmark email webhooks",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "oneOf": [
+ { "$ref": "#/components/schemas/PostmarkDeliveryWebhook" },
+ { "$ref": "#/components/schemas/PostmarkBounceWebhook" },
+ {
+ "$ref": "#/components/schemas/PostmarkSpamComplaintWebhook"
+ },
+ { "$ref": "#/components/schemas/PostmarkOpenWebhook" },
+ { "$ref": "#/components/schemas/PostmarkClickWebhook" },
+ {
+ "$ref": "#/components/schemas/PostmarkSubscriptionChangeWebhook"
+ }
+ ],
+ "title": "Webhook",
+ "discriminator": {
+ "propertyName": "RecordType",
+ "mapping": {
+ "Delivery": "#/components/schemas/PostmarkDeliveryWebhook",
+ "Bounce": "#/components/schemas/PostmarkBounceWebhook",
+ "SpamComplaint": "#/components/schemas/PostmarkSpamComplaintWebhook",
+ "Open": "#/components/schemas/PostmarkOpenWebhook",
+ "Click": "#/components/schemas/PostmarkClickWebhook",
+ "SubscriptionChange": "#/components/schemas/PostmarkSubscriptionChangeWebhook"
+ }
+ }
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": { "application/json": { "schema": {} } }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/HTTPValidationError" }
+ }
+ }
+ }
+ },
+ "security": [{ "APIKeyHeader": [] }]
+ }
+ },
+ "/health": {
+ "get": {
+ "tags": ["health"],
+ "summary": "Health",
+ "operationId": "getHealthHealth",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": { "application/json": { "schema": {} } }
+ }
+ }
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "APIKeyCredentials": {
+ "properties": {
+ "id": { "type": "string", "title": "Id" },
+ "provider": { "type": "string", "title": "Provider" },
+ "title": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Title"
+ },
+ "type": {
+ "type": "string",
+ "const": "api_key",
+ "title": "Type",
+ "default": "api_key"
+ },
+ "api_key": {
+ "type": "string",
+ "format": "password",
+ "title": "Api Key",
+ "writeOnly": true
+ },
+ "expires_at": {
+ "anyOf": [{ "type": "integer" }, { "type": "null" }],
+ "title": "Expires At",
+ "description": "Unix timestamp (seconds) indicating when the API key expires (if at all)"
+ }
+ },
+ "type": "object",
+ "required": ["provider", "api_key"],
+ "title": "APIKeyCredentials"
+ },
+ "APIKeyPermission": {
+ "type": "string",
+ "enum": ["EXECUTE_GRAPH", "READ_GRAPH", "EXECUTE_BLOCK", "READ_BLOCK"],
+ "title": "APIKeyPermission"
+ },
+ "APIKeyStatus": {
+ "type": "string",
+ "enum": ["ACTIVE", "REVOKED", "SUSPENDED"],
+ "title": "APIKeyStatus"
+ },
+ "APIKeyWithoutHash": {
+ "properties": {
+ "id": { "type": "string", "title": "Id" },
+ "name": { "type": "string", "title": "Name" },
+ "prefix": { "type": "string", "title": "Prefix" },
+ "postfix": { "type": "string", "title": "Postfix" },
+ "status": { "$ref": "#/components/schemas/APIKeyStatus" },
+ "permissions": {
+ "items": { "$ref": "#/components/schemas/APIKeyPermission" },
+ "type": "array",
+ "title": "Permissions"
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Created At"
+ },
+ "last_used_at": {
+ "anyOf": [
+ { "type": "string", "format": "date-time" },
+ { "type": "null" }
+ ],
+ "title": "Last Used At"
+ },
+ "revoked_at": {
+ "anyOf": [
+ { "type": "string", "format": "date-time" },
+ { "type": "null" }
+ ],
+ "title": "Revoked At"
+ },
+ "description": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Description"
+ },
+ "user_id": { "type": "string", "title": "User Id" }
+ },
+ "type": "object",
+ "required": [
+ "id",
+ "name",
+ "prefix",
+ "postfix",
+ "status",
+ "permissions",
+ "created_at",
+ "last_used_at",
+ "revoked_at",
+ "description",
+ "user_id"
+ ],
+ "title": "APIKeyWithoutHash"
+ },
+ "AddUserCreditsResponse": {
+ "properties": {
+ "new_balance": { "type": "integer", "title": "New Balance" },
+ "transaction_key": { "type": "string", "title": "Transaction Key" }
+ },
+ "type": "object",
+ "required": ["new_balance", "transaction_key"],
+ "title": "AddUserCreditsResponse"
+ },
+ "AgentExecutionStatus": {
+ "type": "string",
+ "enum": [
+ "INCOMPLETE",
+ "QUEUED",
+ "RUNNING",
+ "COMPLETED",
+ "TERMINATED",
+ "FAILED"
+ ],
+ "title": "AgentExecutionStatus"
+ },
+ "ApiResponse": {
+ "properties": {
+ "answer": { "type": "string", "title": "Answer" },
+ "documents": {
+ "items": { "$ref": "#/components/schemas/Document" },
+ "type": "array",
+ "title": "Documents"
+ },
+ "success": { "type": "boolean", "title": "Success" }
+ },
+ "type": "object",
+ "required": ["answer", "documents", "success"],
+ "title": "ApiResponse"
+ },
+ "AutoTopUpConfig": {
+ "properties": {
+ "amount": { "type": "integer", "title": "Amount" },
+ "threshold": { "type": "integer", "title": "Threshold" }
+ },
+ "type": "object",
+ "required": ["amount", "threshold"],
+ "title": "AutoTopUpConfig"
+ },
+ "BaseGraph-Input": {
+ "properties": {
+ "id": { "type": "string", "title": "Id" },
+ "version": { "type": "integer", "title": "Version", "default": 1 },
+ "is_active": {
+ "type": "boolean",
+ "title": "Is Active",
+ "default": true
+ },
+ "name": { "type": "string", "title": "Name" },
+ "description": { "type": "string", "title": "Description" },
+ "nodes": {
+ "items": { "$ref": "#/components/schemas/Node" },
+ "type": "array",
+ "title": "Nodes",
+ "default": []
+ },
+ "links": {
+ "items": { "$ref": "#/components/schemas/Link" },
+ "type": "array",
+ "title": "Links",
+ "default": []
+ },
+ "forked_from_id": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Forked From Id"
+ },
+ "forked_from_version": {
+ "anyOf": [{ "type": "integer" }, { "type": "null" }],
+ "title": "Forked From Version"
+ }
+ },
+ "type": "object",
+ "required": ["name", "description"],
+ "title": "BaseGraph"
+ },
+ "BaseGraph-Output": {
+ "properties": {
+ "id": { "type": "string", "title": "Id" },
+ "version": { "type": "integer", "title": "Version", "default": 1 },
+ "is_active": {
+ "type": "boolean",
+ "title": "Is Active",
+ "default": true
+ },
+ "name": { "type": "string", "title": "Name" },
+ "description": { "type": "string", "title": "Description" },
+ "nodes": {
+ "items": { "$ref": "#/components/schemas/Node" },
+ "type": "array",
+ "title": "Nodes",
+ "default": []
+ },
+ "links": {
+ "items": { "$ref": "#/components/schemas/Link" },
+ "type": "array",
+ "title": "Links",
+ "default": []
+ },
+ "forked_from_id": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Forked From Id"
+ },
+ "forked_from_version": {
+ "anyOf": [{ "type": "integer" }, { "type": "null" }],
+ "title": "Forked From Version"
+ },
+ "input_schema": {
+ "additionalProperties": true,
+ "type": "object",
+ "title": "Input Schema",
+ "readOnly": true
+ },
+ "output_schema": {
+ "additionalProperties": true,
+ "type": "object",
+ "title": "Output Schema",
+ "readOnly": true
+ }
+ },
+ "type": "object",
+ "required": ["name", "description", "input_schema", "output_schema"],
+ "title": "BaseGraph"
+ },
+ "Body_postV1Callback": {
+ "properties": {
+ "code": {
+ "type": "string",
+ "title": "Authorization code acquired by user login"
+ },
+ "state_token": { "type": "string", "title": "Anti-CSRF nonce" }
+ },
+ "type": "object",
+ "required": ["code", "state_token"],
+ "title": "Body_postV1Callback"
+ },
+ "Body_postV1Execute_graph_agent": {
+ "properties": {
+ "inputs": {
+ "additionalProperties": true,
+ "type": "object",
+ "title": "Inputs"
+ },
+ "credentials_inputs": {
+ "additionalProperties": {
+ "$ref": "#/components/schemas/CredentialsMetaInput"
+ },
+ "type": "object",
+ "title": "Credentials Inputs"
+ }
+ },
+ "type": "object",
+ "title": "Body_postV1Execute graph agent"
+ },
+ "Body_postV1LogRawAnalytics": {
+ "properties": {
+ "type": { "type": "string", "title": "Type" },
+ "data": {
+ "additionalProperties": true,
+ "type": "object",
+ "title": "Data",
+ "description": "The data to log"
+ },
+ "data_index": {
+ "type": "string",
+ "title": "Data Index",
+ "description": "Indexable field for any count based analytical measures like page order clicking, tutorial step completion, etc."
+ }
+ },
+ "type": "object",
+ "required": ["type", "data", "data_index"],
+ "title": "Body_postV1LogRawAnalytics"
+ },
+ "Body_postV1LogRawMetric": {
+ "properties": {
+ "metric_name": { "type": "string", "title": "Metric Name" },
+ "metric_value": { "type": "number", "title": "Metric Value" },
+ "data_string": { "type": "string", "title": "Data String" }
+ },
+ "type": "object",
+ "required": ["metric_name", "metric_value", "data_string"],
+ "title": "Body_postV1LogRawMetric"
+ },
+ "Body_postV2Add_credits_to_user": {
+ "properties": {
+ "user_id": { "type": "string", "title": "User Id" },
+ "amount": { "type": "integer", "title": "Amount" },
+ "comments": { "type": "string", "title": "Comments" }
+ },
+ "type": "object",
+ "required": ["user_id", "amount", "comments"],
+ "title": "Body_postV2Add credits to user"
+ },
+ "Body_postV2Add_marketplace_agent": {
+ "properties": {
+ "store_listing_version_id": {
+ "type": "string",
+ "title": "Store Listing Version Id"
+ }
+ },
+ "type": "object",
+ "required": ["store_listing_version_id"],
+ "title": "Body_postV2Add marketplace agent"
+ },
+ "Body_postV2Execute_a_preset": {
+ "properties": {
+ "node_input": {
+ "additionalProperties": true,
+ "type": "object",
+ "title": "Node Input"
+ }
+ },
+ "type": "object",
+ "title": "Body_postV2Execute a preset"
+ },
+ "Body_postV2Upload_submission_media": {
+ "properties": {
+ "file": { "type": "string", "format": "binary", "title": "File" }
+ },
+ "type": "object",
+ "required": ["file"],
+ "title": "Body_postV2Upload submission media"
+ },
+ "ChatRequest": {
+ "properties": {
+ "query": { "type": "string", "title": "Query" },
+ "conversation_history": {
+ "items": { "$ref": "#/components/schemas/Message" },
+ "type": "array",
+ "title": "Conversation History"
+ },
+ "message_id": { "type": "string", "title": "Message Id" },
+ "include_graph_data": {
+ "type": "boolean",
+ "title": "Include Graph Data",
+ "default": false
+ },
+ "graph_id": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Graph Id"
+ }
+ },
+ "type": "object",
+ "required": ["query", "conversation_history", "message_id"],
+ "title": "ChatRequest"
+ },
+ "CreateAPIKeyRequest": {
+ "properties": {
+ "name": { "type": "string", "title": "Name" },
+ "permissions": {
+ "items": { "$ref": "#/components/schemas/APIKeyPermission" },
+ "type": "array",
+ "title": "Permissions"
+ },
+ "description": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Description"
+ }
+ },
+ "type": "object",
+ "required": ["name", "permissions"],
+ "title": "CreateAPIKeyRequest"
+ },
+ "CreateAPIKeyResponse": {
+ "properties": {
+ "api_key": { "$ref": "#/components/schemas/APIKeyWithoutHash" },
+ "plain_text_key": { "type": "string", "title": "Plain Text Key" }
+ },
+ "type": "object",
+ "required": ["api_key", "plain_text_key"],
+ "title": "CreateAPIKeyResponse"
+ },
+ "CreateGraph": {
+ "properties": { "graph": { "$ref": "#/components/schemas/Graph" } },
+ "type": "object",
+ "required": ["graph"],
+ "title": "CreateGraph"
+ },
+ "Creator": {
+ "properties": {
+ "name": { "type": "string", "title": "Name" },
+ "username": { "type": "string", "title": "Username" },
+ "description": { "type": "string", "title": "Description" },
+ "avatar_url": { "type": "string", "title": "Avatar Url" },
+ "num_agents": { "type": "integer", "title": "Num Agents" },
+ "agent_rating": { "type": "number", "title": "Agent Rating" },
+ "agent_runs": { "type": "integer", "title": "Agent Runs" },
+ "is_featured": { "type": "boolean", "title": "Is Featured" }
+ },
+ "type": "object",
+ "required": [
+ "name",
+ "username",
+ "description",
+ "avatar_url",
+ "num_agents",
+ "agent_rating",
+ "agent_runs",
+ "is_featured"
+ ],
+ "title": "Creator"
+ },
+ "CreatorDetails": {
+ "properties": {
+ "name": { "type": "string", "title": "Name" },
+ "username": { "type": "string", "title": "Username" },
+ "description": { "type": "string", "title": "Description" },
+ "links": {
+ "items": { "type": "string" },
+ "type": "array",
+ "title": "Links"
+ },
+ "avatar_url": { "type": "string", "title": "Avatar Url" },
+ "agent_rating": { "type": "number", "title": "Agent Rating" },
+ "agent_runs": { "type": "integer", "title": "Agent Runs" },
+ "top_categories": {
+ "items": { "type": "string" },
+ "type": "array",
+ "title": "Top Categories"
+ }
+ },
+ "type": "object",
+ "required": [
+ "name",
+ "username",
+ "description",
+ "links",
+ "avatar_url",
+ "agent_rating",
+ "agent_runs",
+ "top_categories"
+ ],
+ "title": "CreatorDetails"
+ },
+ "CreatorsResponse": {
+ "properties": {
+ "creators": {
+ "items": { "$ref": "#/components/schemas/Creator" },
+ "type": "array",
+ "title": "Creators"
+ },
+ "pagination": { "$ref": "#/components/schemas/Pagination" }
+ },
+ "type": "object",
+ "required": ["creators", "pagination"],
+ "title": "CreatorsResponse"
+ },
+ "CredentialsDeletionNeedsConfirmationResponse": {
+ "properties": {
+ "deleted": {
+ "type": "boolean",
+ "const": false,
+ "title": "Deleted",
+ "default": false
+ },
+ "need_confirmation": {
+ "type": "boolean",
+ "const": true,
+ "title": "Need Confirmation",
+ "default": true
+ },
+ "message": { "type": "string", "title": "Message" }
+ },
+ "type": "object",
+ "required": ["message"],
+ "title": "CredentialsDeletionNeedsConfirmationResponse"
+ },
+ "CredentialsDeletionResponse": {
+ "properties": {
+ "deleted": {
+ "type": "boolean",
+ "const": true,
+ "title": "Deleted",
+ "default": true
+ },
+ "revoked": {
+ "anyOf": [{ "type": "boolean" }, { "type": "null" }],
+ "title": "Revoked",
+ "description": "Indicates whether the credentials were also revoked by their provider. `None`/`null` if not applicable, e.g. when deleting non-revocable credentials such as API keys."
+ }
+ },
+ "type": "object",
+ "required": ["revoked"],
+ "title": "CredentialsDeletionResponse"
+ },
+ "CredentialsMetaInput": {
+ "properties": {
+ "id": { "type": "string", "title": "Id" },
+ "title": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Title"
+ },
+ "provider": { "$ref": "#/components/schemas/ProviderName" },
+ "type": {
+ "type": "string",
+ "enum": ["api_key", "oauth2", "user_password"],
+ "title": "Type"
+ }
+ },
+ "type": "object",
+ "required": ["id", "provider", "type"],
+ "title": "CredentialsMetaInput",
+ "credentials_provider": [],
+ "credentials_types": []
+ },
+ "CredentialsMetaResponse": {
+ "properties": {
+ "id": { "type": "string", "title": "Id" },
+ "provider": { "type": "string", "title": "Provider" },
+ "type": {
+ "type": "string",
+ "enum": ["api_key", "oauth2", "user_password"],
+ "title": "Type"
+ },
+ "title": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Title"
+ },
+ "scopes": {
+ "anyOf": [
+ { "items": { "type": "string" }, "type": "array" },
+ { "type": "null" }
+ ],
+ "title": "Scopes"
+ },
+ "username": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Username"
+ }
+ },
+ "type": "object",
+ "required": ["id", "provider", "type", "title", "scopes", "username"],
+ "title": "CredentialsMetaResponse"
+ },
+ "CreditTransactionType": {
+ "type": "string",
+ "enum": ["TOP_UP", "USAGE", "GRANT", "REFUND", "CARD_CHECK"],
+ "title": "CreditTransactionType"
+ },
+ "DeleteGraphResponse": {
+ "properties": {
+ "version_counts": { "type": "integer", "title": "Version Counts" }
+ },
+ "type": "object",
+ "required": ["version_counts"],
+ "title": "DeleteGraphResponse"
+ },
+ "Document": {
+ "properties": {
+ "url": { "type": "string", "title": "Url" },
+ "relevance_score": { "type": "number", "title": "Relevance Score" }
+ },
+ "type": "object",
+ "required": ["url", "relevance_score"],
+ "title": "Document"
+ },
+ "ExecuteGraphResponse": {
+ "properties": {
+ "graph_exec_id": { "type": "string", "title": "Graph Exec Id" }
+ },
+ "type": "object",
+ "required": ["graph_exec_id"],
+ "title": "ExecuteGraphResponse"
+ },
+ "Graph": {
+ "properties": {
+ "id": { "type": "string", "title": "Id" },
+ "version": { "type": "integer", "title": "Version", "default": 1 },
+ "is_active": {
+ "type": "boolean",
+ "title": "Is Active",
+ "default": true
+ },
+ "name": { "type": "string", "title": "Name" },
+ "description": { "type": "string", "title": "Description" },
+ "nodes": {
+ "items": { "$ref": "#/components/schemas/Node" },
+ "type": "array",
+ "title": "Nodes",
+ "default": []
+ },
+ "links": {
+ "items": { "$ref": "#/components/schemas/Link" },
+ "type": "array",
+ "title": "Links",
+ "default": []
+ },
+ "forked_from_id": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Forked From Id"
+ },
+ "forked_from_version": {
+ "anyOf": [{ "type": "integer" }, { "type": "null" }],
+ "title": "Forked From Version"
+ },
+ "sub_graphs": {
+ "items": { "$ref": "#/components/schemas/BaseGraph-Input" },
+ "type": "array",
+ "title": "Sub Graphs",
+ "default": []
+ }
+ },
+ "type": "object",
+ "required": ["name", "description"],
+ "title": "Graph"
+ },
+ "GraphExecution": {
+ "properties": {
+ "id": { "type": "string", "title": "Id" },
+ "user_id": { "type": "string", "title": "User Id" },
+ "graph_id": { "type": "string", "title": "Graph Id" },
+ "graph_version": { "type": "integer", "title": "Graph Version" },
+ "preset_id": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Preset Id"
+ },
+ "status": { "$ref": "#/components/schemas/AgentExecutionStatus" },
+ "started_at": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Started At"
+ },
+ "ended_at": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Ended At"
+ },
+ "stats": {
+ "anyOf": [
+ { "$ref": "#/components/schemas/Stats" },
+ { "type": "null" }
+ ]
+ },
+ "inputs": {
+ "additionalProperties": true,
+ "type": "object",
+ "title": "Inputs"
+ },
+ "outputs": {
+ "additionalProperties": { "items": {}, "type": "array" },
+ "type": "object",
+ "title": "Outputs"
+ }
+ },
+ "type": "object",
+ "required": [
+ "user_id",
+ "graph_id",
+ "graph_version",
+ "status",
+ "started_at",
+ "ended_at",
+ "stats",
+ "inputs",
+ "outputs"
+ ],
+ "title": "GraphExecution"
+ },
+ "GraphExecutionJobInfo": {
+ "properties": {
+ "graph_id": { "type": "string", "title": "Graph Id" },
+ "input_data": {
+ "additionalProperties": true,
+ "type": "object",
+ "title": "Input Data"
+ },
+ "user_id": { "type": "string", "title": "User Id" },
+ "graph_version": { "type": "integer", "title": "Graph Version" },
+ "cron": { "type": "string", "title": "Cron" },
+ "id": { "type": "string", "title": "Id" },
+ "name": { "type": "string", "title": "Name" },
+ "next_run_time": { "type": "string", "title": "Next Run Time" }
+ },
+ "type": "object",
+ "required": [
+ "graph_id",
+ "input_data",
+ "user_id",
+ "graph_version",
+ "cron",
+ "id",
+ "name",
+ "next_run_time"
+ ],
+ "title": "GraphExecutionJobInfo"
+ },
+ "GraphExecutionMeta": {
+ "properties": {
+ "id": { "type": "string", "title": "Id" },
+ "user_id": { "type": "string", "title": "User Id" },
+ "graph_id": { "type": "string", "title": "Graph Id" },
+ "graph_version": { "type": "integer", "title": "Graph Version" },
+ "preset_id": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Preset Id"
+ },
+ "status": { "$ref": "#/components/schemas/AgentExecutionStatus" },
+ "started_at": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Started At"
+ },
+ "ended_at": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Ended At"
+ },
+ "stats": {
+ "anyOf": [
+ { "$ref": "#/components/schemas/Stats" },
+ { "type": "null" }
+ ]
+ }
+ },
+ "type": "object",
+ "required": [
+ "user_id",
+ "graph_id",
+ "graph_version",
+ "status",
+ "started_at",
+ "ended_at",
+ "stats"
+ ],
+ "title": "GraphExecutionMeta"
+ },
+ "GraphExecutionWithNodes": {
+ "properties": {
+ "id": { "type": "string", "title": "Id" },
+ "user_id": { "type": "string", "title": "User Id" },
+ "graph_id": { "type": "string", "title": "Graph Id" },
+ "graph_version": { "type": "integer", "title": "Graph Version" },
+ "preset_id": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Preset Id"
+ },
+ "status": { "$ref": "#/components/schemas/AgentExecutionStatus" },
+ "started_at": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Started At"
+ },
+ "ended_at": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Ended At"
+ },
+ "stats": {
+ "anyOf": [
+ { "$ref": "#/components/schemas/Stats" },
+ { "type": "null" }
+ ]
+ },
+ "inputs": {
+ "additionalProperties": true,
+ "type": "object",
+ "title": "Inputs"
+ },
+ "outputs": {
+ "additionalProperties": { "items": {}, "type": "array" },
+ "type": "object",
+ "title": "Outputs"
+ },
+ "node_executions": {
+ "items": { "$ref": "#/components/schemas/NodeExecutionResult" },
+ "type": "array",
+ "title": "Node Executions"
+ }
+ },
+ "type": "object",
+ "required": [
+ "user_id",
+ "graph_id",
+ "graph_version",
+ "status",
+ "started_at",
+ "ended_at",
+ "stats",
+ "inputs",
+ "outputs",
+ "node_executions"
+ ],
+ "title": "GraphExecutionWithNodes"
+ },
+ "GraphModel": {
+ "properties": {
+ "id": { "type": "string", "title": "Id" },
+ "version": { "type": "integer", "title": "Version", "default": 1 },
+ "is_active": {
+ "type": "boolean",
+ "title": "Is Active",
+ "default": true
+ },
+ "name": { "type": "string", "title": "Name" },
+ "description": { "type": "string", "title": "Description" },
+ "nodes": {
+ "items": { "$ref": "#/components/schemas/NodeModel" },
+ "type": "array",
+ "title": "Nodes",
+ "default": []
+ },
+ "links": {
+ "items": { "$ref": "#/components/schemas/Link" },
+ "type": "array",
+ "title": "Links",
+ "default": []
+ },
+ "forked_from_id": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Forked From Id"
+ },
+ "forked_from_version": {
+ "anyOf": [{ "type": "integer" }, { "type": "null" }],
+ "title": "Forked From Version"
+ },
+ "sub_graphs": {
+ "items": { "$ref": "#/components/schemas/BaseGraph-Output" },
+ "type": "array",
+ "title": "Sub Graphs",
+ "default": []
+ },
+ "user_id": { "type": "string", "title": "User Id" },
+ "input_schema": {
+ "additionalProperties": true,
+ "type": "object",
+ "title": "Input Schema",
+ "readOnly": true
+ },
+ "output_schema": {
+ "additionalProperties": true,
+ "type": "object",
+ "title": "Output Schema",
+ "readOnly": true
+ },
+ "credentials_input_schema": {
+ "additionalProperties": true,
+ "type": "object",
+ "title": "Credentials Input Schema",
+ "readOnly": true
+ },
+ "has_webhook_trigger": {
+ "type": "boolean",
+ "title": "Has Webhook Trigger",
+ "readOnly": true
+ }
+ },
+ "type": "object",
+ "required": [
+ "name",
+ "description",
+ "user_id",
+ "input_schema",
+ "output_schema",
+ "credentials_input_schema",
+ "has_webhook_trigger"
+ ],
+ "title": "GraphModel"
+ },
+ "HTTPValidationError": {
+ "properties": {
+ "detail": {
+ "items": { "$ref": "#/components/schemas/ValidationError" },
+ "type": "array",
+ "title": "Detail"
+ }
+ },
+ "type": "object",
+ "title": "HTTPValidationError"
+ },
+ "LibraryAgent": {
+ "properties": {
+ "id": { "type": "string", "title": "Id" },
+ "graph_id": { "type": "string", "title": "Graph Id" },
+ "graph_version": { "type": "integer", "title": "Graph Version" },
+ "image_url": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Image Url"
+ },
+ "creator_name": { "type": "string", "title": "Creator Name" },
+ "creator_image_url": {
+ "type": "string",
+ "title": "Creator Image Url"
+ },
+ "status": { "$ref": "#/components/schemas/LibraryAgentStatus" },
+ "updated_at": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Updated At"
+ },
+ "name": { "type": "string", "title": "Name" },
+ "description": { "type": "string", "title": "Description" },
+ "input_schema": {
+ "additionalProperties": true,
+ "type": "object",
+ "title": "Input Schema"
+ },
+ "new_output": { "type": "boolean", "title": "New Output" },
+ "can_access_graph": {
+ "type": "boolean",
+ "title": "Can Access Graph"
+ },
+ "is_latest_version": {
+ "type": "boolean",
+ "title": "Is Latest Version"
+ }
+ },
+ "type": "object",
+ "required": [
+ "id",
+ "graph_id",
+ "graph_version",
+ "image_url",
+ "creator_name",
+ "creator_image_url",
+ "status",
+ "updated_at",
+ "name",
+ "description",
+ "input_schema",
+ "new_output",
+ "can_access_graph",
+ "is_latest_version"
+ ],
+ "title": "LibraryAgent",
+ "description": "Represents an agent in the library, including metadata for display and\nuser interaction within the system."
+ },
+ "LibraryAgentPreset": {
+ "properties": {
+ "graph_id": { "type": "string", "title": "Graph Id" },
+ "graph_version": { "type": "integer", "title": "Graph Version" },
+ "inputs": {
+ "additionalProperties": true,
+ "type": "object",
+ "title": "Inputs"
+ },
+ "name": { "type": "string", "title": "Name" },
+ "description": { "type": "string", "title": "Description" },
+ "is_active": {
+ "type": "boolean",
+ "title": "Is Active",
+ "default": true
+ },
+ "id": { "type": "string", "title": "Id" },
+ "updated_at": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Updated At"
+ }
+ },
+ "type": "object",
+ "required": [
+ "graph_id",
+ "graph_version",
+ "inputs",
+ "name",
+ "description",
+ "id",
+ "updated_at"
+ ],
+ "title": "LibraryAgentPreset",
+ "description": "Represents a preset configuration for a library agent."
+ },
+ "LibraryAgentPresetCreatable": {
+ "properties": {
+ "graph_id": { "type": "string", "title": "Graph Id" },
+ "graph_version": { "type": "integer", "title": "Graph Version" },
+ "inputs": {
+ "additionalProperties": true,
+ "type": "object",
+ "title": "Inputs"
+ },
+ "name": { "type": "string", "title": "Name" },
+ "description": { "type": "string", "title": "Description" },
+ "is_active": {
+ "type": "boolean",
+ "title": "Is Active",
+ "default": true
+ }
+ },
+ "type": "object",
+ "required": [
+ "graph_id",
+ "graph_version",
+ "inputs",
+ "name",
+ "description"
+ ],
+ "title": "LibraryAgentPresetCreatable",
+ "description": "Request model used when creating a new preset for a library agent."
+ },
+ "LibraryAgentPresetCreatableFromGraphExecution": {
+ "properties": {
+ "graph_execution_id": {
+ "type": "string",
+ "title": "Graph Execution Id"
+ },
+ "name": { "type": "string", "title": "Name" },
+ "description": { "type": "string", "title": "Description" },
+ "is_active": {
+ "type": "boolean",
+ "title": "Is Active",
+ "default": true
+ }
+ },
+ "type": "object",
+ "required": ["graph_execution_id", "name", "description"],
+ "title": "LibraryAgentPresetCreatableFromGraphExecution",
+ "description": "Request model used when creating a new preset for a library agent."
+ },
+ "LibraryAgentPresetResponse": {
+ "properties": {
+ "presets": {
+ "items": { "$ref": "#/components/schemas/LibraryAgentPreset" },
+ "type": "array",
+ "title": "Presets"
+ },
+ "pagination": { "$ref": "#/components/schemas/Pagination" }
+ },
+ "type": "object",
+ "required": ["presets", "pagination"],
+ "title": "LibraryAgentPresetResponse",
+ "description": "Response schema for a list of agent presets and pagination info."
+ },
+ "LibraryAgentPresetUpdatable": {
+ "properties": {
+ "inputs": {
+ "anyOf": [
+ { "additionalProperties": true, "type": "object" },
+ { "type": "null" }
+ ],
+ "title": "Inputs"
+ },
+ "name": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Name"
+ },
+ "description": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Description"
+ },
+ "is_active": {
+ "anyOf": [{ "type": "boolean" }, { "type": "null" }],
+ "title": "Is Active"
+ }
+ },
+ "type": "object",
+ "title": "LibraryAgentPresetUpdatable",
+ "description": "Request model used when updating a preset for a library agent."
+ },
+ "LibraryAgentResponse": {
+ "properties": {
+ "agents": {
+ "items": { "$ref": "#/components/schemas/LibraryAgent" },
+ "type": "array",
+ "title": "Agents"
+ },
+ "pagination": { "$ref": "#/components/schemas/Pagination" }
+ },
+ "type": "object",
+ "required": ["agents", "pagination"],
+ "title": "LibraryAgentResponse",
+ "description": "Response schema for a list of library agents and pagination info."
+ },
+ "LibraryAgentSort": {
+ "type": "string",
+ "enum": ["createdAt", "updatedAt"],
+ "title": "LibraryAgentSort",
+ "description": "Possible sort options for sorting library agents."
+ },
+ "LibraryAgentStatus": {
+ "type": "string",
+ "enum": ["COMPLETED", "HEALTHY", "WAITING", "ERROR"],
+ "title": "LibraryAgentStatus"
+ },
+ "LibraryAgentUpdateRequest": {
+ "properties": {
+ "auto_update_version": {
+ "anyOf": [{ "type": "boolean" }, { "type": "null" }],
+ "title": "Auto Update Version",
+ "description": "Auto-update the agent version"
+ },
+ "is_favorite": {
+ "anyOf": [{ "type": "boolean" }, { "type": "null" }],
+ "title": "Is Favorite",
+ "description": "Mark the agent as a favorite"
+ },
+ "is_archived": {
+ "anyOf": [{ "type": "boolean" }, { "type": "null" }],
+ "title": "Is Archived",
+ "description": "Archive the agent"
+ },
+ "is_deleted": {
+ "anyOf": [{ "type": "boolean" }, { "type": "null" }],
+ "title": "Is Deleted",
+ "description": "Delete the agent"
+ }
+ },
+ "type": "object",
+ "title": "LibraryAgentUpdateRequest",
+ "description": "Schema for updating a library agent via PUT.\n\nIncludes flags for auto-updating version, marking as favorite,\narchiving, or deleting."
+ },
+ "Link": {
+ "properties": {
+ "id": { "type": "string", "title": "Id" },
+ "source_id": { "type": "string", "title": "Source Id" },
+ "sink_id": { "type": "string", "title": "Sink Id" },
+ "source_name": { "type": "string", "title": "Source Name" },
+ "sink_name": { "type": "string", "title": "Sink Name" },
+ "is_static": {
+ "type": "boolean",
+ "title": "Is Static",
+ "default": false
+ }
+ },
+ "type": "object",
+ "required": ["source_id", "sink_id", "source_name", "sink_name"],
+ "title": "Link"
+ },
+ "LoginResponse": {
+ "properties": {
+ "login_url": { "type": "string", "title": "Login Url" },
+ "state_token": { "type": "string", "title": "State Token" }
+ },
+ "type": "object",
+ "required": ["login_url", "state_token"],
+ "title": "LoginResponse"
+ },
+ "Message": {
+ "properties": {
+ "query": { "type": "string", "title": "Query" },
+ "response": { "type": "string", "title": "Response" }
+ },
+ "type": "object",
+ "required": ["query", "response"],
+ "title": "Message"
+ },
+ "MyAgent": {
+ "properties": {
+ "agent_id": { "type": "string", "title": "Agent Id" },
+ "agent_version": { "type": "integer", "title": "Agent Version" },
+ "agent_name": { "type": "string", "title": "Agent Name" },
+ "agent_image": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Agent Image"
+ },
+ "description": { "type": "string", "title": "Description" },
+ "last_edited": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Last Edited"
+ }
+ },
+ "type": "object",
+ "required": [
+ "agent_id",
+ "agent_version",
+ "agent_name",
+ "description",
+ "last_edited"
+ ],
+ "title": "MyAgent"
+ },
+ "MyAgentsResponse": {
+ "properties": {
+ "agents": {
+ "items": { "$ref": "#/components/schemas/MyAgent" },
+ "type": "array",
+ "title": "Agents"
+ },
+ "pagination": { "$ref": "#/components/schemas/Pagination" }
+ },
+ "type": "object",
+ "required": ["agents", "pagination"],
+ "title": "MyAgentsResponse"
+ },
+ "Node": {
+ "properties": {
+ "id": { "type": "string", "title": "Id" },
+ "block_id": { "type": "string", "title": "Block Id" },
+ "input_default": {
+ "additionalProperties": true,
+ "type": "object",
+ "title": "Input Default",
+ "default": {}
+ },
+ "metadata": {
+ "additionalProperties": true,
+ "type": "object",
+ "title": "Metadata",
+ "default": {}
+ },
+ "input_links": {
+ "items": { "$ref": "#/components/schemas/Link" },
+ "type": "array",
+ "title": "Input Links",
+ "default": []
+ },
+ "output_links": {
+ "items": { "$ref": "#/components/schemas/Link" },
+ "type": "array",
+ "title": "Output Links",
+ "default": []
+ }
+ },
+ "type": "object",
+ "required": ["block_id"],
+ "title": "Node"
+ },
+ "NodeExecutionResult": {
+ "properties": {
+ "user_id": { "type": "string", "title": "User Id" },
+ "graph_id": { "type": "string", "title": "Graph Id" },
+ "graph_version": { "type": "integer", "title": "Graph Version" },
+ "graph_exec_id": { "type": "string", "title": "Graph Exec Id" },
+ "node_exec_id": { "type": "string", "title": "Node Exec Id" },
+ "node_id": { "type": "string", "title": "Node Id" },
+ "block_id": { "type": "string", "title": "Block Id" },
+ "status": { "$ref": "#/components/schemas/AgentExecutionStatus" },
+ "input_data": {
+ "additionalProperties": true,
+ "type": "object",
+ "title": "Input Data"
+ },
+ "output_data": {
+ "additionalProperties": { "items": {}, "type": "array" },
+ "type": "object",
+ "title": "Output Data"
+ },
+ "add_time": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Add Time"
+ },
+ "queue_time": {
+ "anyOf": [
+ { "type": "string", "format": "date-time" },
+ { "type": "null" }
+ ],
+ "title": "Queue Time"
+ },
+ "start_time": {
+ "anyOf": [
+ { "type": "string", "format": "date-time" },
+ { "type": "null" }
+ ],
+ "title": "Start Time"
+ },
+ "end_time": {
+ "anyOf": [
+ { "type": "string", "format": "date-time" },
+ { "type": "null" }
+ ],
+ "title": "End Time"
+ }
+ },
+ "type": "object",
+ "required": [
+ "user_id",
+ "graph_id",
+ "graph_version",
+ "graph_exec_id",
+ "node_exec_id",
+ "node_id",
+ "block_id",
+ "status",
+ "input_data",
+ "output_data",
+ "add_time",
+ "queue_time",
+ "start_time",
+ "end_time"
+ ],
+ "title": "NodeExecutionResult"
+ },
+ "NodeModel": {
+ "properties": {
+ "id": { "type": "string", "title": "Id" },
+ "block_id": { "type": "string", "title": "Block Id" },
+ "input_default": {
+ "additionalProperties": true,
+ "type": "object",
+ "title": "Input Default",
+ "default": {}
+ },
+ "metadata": {
+ "additionalProperties": true,
+ "type": "object",
+ "title": "Metadata",
+ "default": {}
+ },
+ "input_links": {
+ "items": { "$ref": "#/components/schemas/Link" },
+ "type": "array",
+ "title": "Input Links",
+ "default": []
+ },
+ "output_links": {
+ "items": { "$ref": "#/components/schemas/Link" },
+ "type": "array",
+ "title": "Output Links",
+ "default": []
+ },
+ "graph_id": { "type": "string", "title": "Graph Id" },
+ "graph_version": { "type": "integer", "title": "Graph Version" },
+ "webhook_id": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Webhook Id"
+ },
+ "webhook": {
+ "anyOf": [
+ { "$ref": "#/components/schemas/Webhook" },
+ { "type": "null" }
+ ]
+ }
+ },
+ "type": "object",
+ "required": ["block_id", "graph_id", "graph_version"],
+ "title": "NodeModel"
+ },
+ "NotificationPreference": {
+ "properties": {
+ "user_id": { "type": "string", "title": "User Id" },
+ "email": { "type": "string", "format": "email", "title": "Email" },
+ "preferences": {
+ "additionalProperties": { "type": "boolean" },
+ "propertyNames": {
+ "$ref": "#/components/schemas/NotificationType"
+ },
+ "type": "object",
+ "title": "Preferences",
+ "description": "Which notifications the user wants"
+ },
+ "daily_limit": {
+ "type": "integer",
+ "title": "Daily Limit",
+ "default": 10
+ },
+ "emails_sent_today": {
+ "type": "integer",
+ "title": "Emails Sent Today",
+ "default": 0
+ },
+ "last_reset_date": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Last Reset Date"
+ }
+ },
+ "type": "object",
+ "required": ["user_id", "email"],
+ "title": "NotificationPreference"
+ },
+ "NotificationPreferenceDTO": {
+ "properties": {
+ "email": {
+ "type": "string",
+ "format": "email",
+ "title": "Email",
+ "description": "User's email address"
+ },
+ "preferences": {
+ "additionalProperties": { "type": "boolean" },
+ "propertyNames": {
+ "$ref": "#/components/schemas/NotificationType"
+ },
+ "type": "object",
+ "title": "Preferences",
+ "description": "Which notifications the user wants"
+ },
+ "daily_limit": {
+ "type": "integer",
+ "title": "Daily Limit",
+ "description": "Max emails per day"
+ }
+ },
+ "type": "object",
+ "required": ["email", "preferences", "daily_limit"],
+ "title": "NotificationPreferenceDTO"
+ },
+ "NotificationType": {
+ "type": "string",
+ "enum": [
+ "AGENT_RUN",
+ "ZERO_BALANCE",
+ "LOW_BALANCE",
+ "BLOCK_EXECUTION_FAILED",
+ "CONTINUOUS_AGENT_ERROR",
+ "DAILY_SUMMARY",
+ "WEEKLY_SUMMARY",
+ "MONTHLY_SUMMARY",
+ "REFUND_REQUEST",
+ "REFUND_PROCESSED"
+ ],
+ "title": "NotificationType"
+ },
+ "OAuth2Credentials": {
+ "properties": {
+ "id": { "type": "string", "title": "Id" },
+ "provider": { "type": "string", "title": "Provider" },
+ "title": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Title"
+ },
+ "type": {
+ "type": "string",
+ "const": "oauth2",
+ "title": "Type",
+ "default": "oauth2"
+ },
+ "username": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Username"
+ },
+ "access_token": {
+ "type": "string",
+ "format": "password",
+ "title": "Access Token",
+ "writeOnly": true
+ },
+ "access_token_expires_at": {
+ "anyOf": [{ "type": "integer" }, { "type": "null" }],
+ "title": "Access Token Expires At"
+ },
+ "refresh_token": {
+ "anyOf": [
+ { "type": "string", "format": "password", "writeOnly": true },
+ { "type": "null" }
+ ],
+ "title": "Refresh Token"
+ },
+ "refresh_token_expires_at": {
+ "anyOf": [{ "type": "integer" }, { "type": "null" }],
+ "title": "Refresh Token Expires At"
+ },
+ "scopes": {
+ "items": { "type": "string" },
+ "type": "array",
+ "title": "Scopes"
+ },
+ "metadata": {
+ "additionalProperties": true,
+ "type": "object",
+ "title": "Metadata"
+ }
+ },
+ "type": "object",
+ "required": ["provider", "access_token", "scopes"],
+ "title": "OAuth2Credentials"
+ },
+ "OnboardingStep": {
+ "type": "string",
+ "enum": [
+ "WELCOME",
+ "USAGE_REASON",
+ "INTEGRATIONS",
+ "AGENT_CHOICE",
+ "AGENT_NEW_RUN",
+ "AGENT_INPUT",
+ "CONGRATS",
+ "GET_RESULTS",
+ "MARKETPLACE_VISIT",
+ "MARKETPLACE_ADD_AGENT",
+ "MARKETPLACE_RUN_AGENT",
+ "BUILDER_OPEN",
+ "BUILDER_SAVE_AGENT",
+ "BUILDER_RUN_AGENT"
+ ],
+ "title": "OnboardingStep"
+ },
+ "Pagination": {
+ "properties": {
+ "total_items": {
+ "type": "integer",
+ "title": "Total Items",
+ "description": "Total number of items.",
+ "examples": [42]
+ },
+ "total_pages": {
+ "type": "integer",
+ "title": "Total Pages",
+ "description": "Total number of pages.",
+ "examples": [2]
+ },
+ "current_page": {
+ "type": "integer",
+ "title": "Current Page",
+ "description": "Current_page page number.",
+ "examples": [1]
+ },
+ "page_size": {
+ "type": "integer",
+ "title": "Page Size",
+ "description": "Number of items per page.",
+ "examples": [25]
+ }
+ },
+ "type": "object",
+ "required": ["total_items", "total_pages", "current_page", "page_size"],
+ "title": "Pagination"
+ },
+ "PostmarkBounceEnum": {
+ "type": "integer",
+ "enum": [
+ 1, 2, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384,
+ 100000, 100001, 100002, 100003, 100006, 100007, 100008, 100009, 100010
+ ],
+ "title": "PostmarkBounceEnum"
+ },
+ "PostmarkBounceWebhook": {
+ "properties": {
+ "RecordType": {
+ "type": "string",
+ "const": "Bounce",
+ "title": "Recordtype",
+ "default": "Bounce"
+ },
+ "ID": { "type": "integer", "title": "Id" },
+ "Type": { "type": "string", "title": "Type" },
+ "TypeCode": { "$ref": "#/components/schemas/PostmarkBounceEnum" },
+ "Tag": { "type": "string", "title": "Tag" },
+ "MessageID": { "type": "string", "title": "Messageid" },
+ "Details": { "type": "string", "title": "Details" },
+ "Email": { "type": "string", "title": "Email" },
+ "From": { "type": "string", "title": "From" },
+ "BouncedAt": { "type": "string", "title": "Bouncedat" },
+ "Inactive": { "type": "boolean", "title": "Inactive" },
+ "DumpAvailable": { "type": "boolean", "title": "Dumpavailable" },
+ "CanActivate": { "type": "boolean", "title": "Canactivate" },
+ "Subject": { "type": "string", "title": "Subject" },
+ "ServerID": { "type": "integer", "title": "Serverid" },
+ "MessageStream": { "type": "string", "title": "Messagestream" },
+ "Content": { "type": "string", "title": "Content" },
+ "Name": { "type": "string", "title": "Name" },
+ "Description": { "type": "string", "title": "Description" },
+ "Metadata": {
+ "additionalProperties": { "type": "string" },
+ "type": "object",
+ "title": "Metadata"
+ }
+ },
+ "type": "object",
+ "required": [
+ "ID",
+ "Type",
+ "TypeCode",
+ "Tag",
+ "MessageID",
+ "Details",
+ "Email",
+ "From",
+ "BouncedAt",
+ "Inactive",
+ "DumpAvailable",
+ "CanActivate",
+ "Subject",
+ "ServerID",
+ "MessageStream",
+ "Content",
+ "Name",
+ "Description",
+ "Metadata"
+ ],
+ "title": "PostmarkBounceWebhook"
+ },
+ "PostmarkClickWebhook": {
+ "properties": {
+ "RecordType": {
+ "type": "string",
+ "const": "Click",
+ "title": "Recordtype",
+ "default": "Click"
+ },
+ "MessageStream": { "type": "string", "title": "Messagestream" },
+ "Metadata": {
+ "additionalProperties": { "type": "string" },
+ "type": "object",
+ "title": "Metadata"
+ },
+ "Recipient": { "type": "string", "title": "Recipient" },
+ "MessageID": { "type": "string", "title": "Messageid" },
+ "ReceivedAt": { "type": "string", "title": "Receivedat" },
+ "Platform": { "type": "string", "title": "Platform" },
+ "ClickLocation": { "type": "string", "title": "Clicklocation" },
+ "OriginalLink": { "type": "string", "title": "Originallink" },
+ "Tag": { "type": "string", "title": "Tag" },
+ "UserAgent": { "type": "string", "title": "Useragent" },
+ "OS": {
+ "additionalProperties": { "type": "string" },
+ "type": "object",
+ "title": "Os"
+ },
+ "Client": {
+ "additionalProperties": { "type": "string" },
+ "type": "object",
+ "title": "Client"
+ },
+ "Geo": {
+ "additionalProperties": { "type": "string" },
+ "type": "object",
+ "title": "Geo"
+ }
+ },
+ "type": "object",
+ "required": [
+ "MessageStream",
+ "Metadata",
+ "Recipient",
+ "MessageID",
+ "ReceivedAt",
+ "Platform",
+ "ClickLocation",
+ "OriginalLink",
+ "Tag",
+ "UserAgent",
+ "OS",
+ "Client",
+ "Geo"
+ ],
+ "title": "PostmarkClickWebhook"
+ },
+ "PostmarkDeliveryWebhook": {
+ "properties": {
+ "RecordType": {
+ "type": "string",
+ "const": "Delivery",
+ "title": "Recordtype",
+ "default": "Delivery"
+ },
+ "ServerID": { "type": "integer", "title": "Serverid" },
+ "MessageStream": { "type": "string", "title": "Messagestream" },
+ "MessageID": { "type": "string", "title": "Messageid" },
+ "Recipient": { "type": "string", "title": "Recipient" },
+ "Tag": { "type": "string", "title": "Tag" },
+ "DeliveredAt": { "type": "string", "title": "Deliveredat" },
+ "Details": { "type": "string", "title": "Details" },
+ "Metadata": {
+ "additionalProperties": { "type": "string" },
+ "type": "object",
+ "title": "Metadata"
+ }
+ },
+ "type": "object",
+ "required": [
+ "ServerID",
+ "MessageStream",
+ "MessageID",
+ "Recipient",
+ "Tag",
+ "DeliveredAt",
+ "Details",
+ "Metadata"
+ ],
+ "title": "PostmarkDeliveryWebhook"
+ },
+ "PostmarkOpenWebhook": {
+ "properties": {
+ "RecordType": {
+ "type": "string",
+ "const": "Open",
+ "title": "Recordtype",
+ "default": "Open"
+ },
+ "MessageStream": { "type": "string", "title": "Messagestream" },
+ "Metadata": {
+ "additionalProperties": { "type": "string" },
+ "type": "object",
+ "title": "Metadata"
+ },
+ "FirstOpen": { "type": "boolean", "title": "Firstopen" },
+ "Recipient": { "type": "string", "title": "Recipient" },
+ "MessageID": { "type": "string", "title": "Messageid" },
+ "ReceivedAt": { "type": "string", "title": "Receivedat" },
+ "Platform": { "type": "string", "title": "Platform" },
+ "ReadSeconds": { "type": "integer", "title": "Readseconds" },
+ "Tag": { "type": "string", "title": "Tag" },
+ "UserAgent": { "type": "string", "title": "Useragent" },
+ "OS": {
+ "additionalProperties": { "type": "string" },
+ "type": "object",
+ "title": "Os"
+ },
+ "Client": {
+ "additionalProperties": { "type": "string" },
+ "type": "object",
+ "title": "Client"
+ },
+ "Geo": {
+ "additionalProperties": { "type": "string" },
+ "type": "object",
+ "title": "Geo"
+ }
+ },
+ "type": "object",
+ "required": [
+ "MessageStream",
+ "Metadata",
+ "FirstOpen",
+ "Recipient",
+ "MessageID",
+ "ReceivedAt",
+ "Platform",
+ "ReadSeconds",
+ "Tag",
+ "UserAgent",
+ "OS",
+ "Client",
+ "Geo"
+ ],
+ "title": "PostmarkOpenWebhook"
+ },
+ "PostmarkSpamComplaintWebhook": {
+ "properties": {
+ "RecordType": {
+ "type": "string",
+ "const": "SpamComplaint",
+ "title": "Recordtype",
+ "default": "SpamComplaint"
+ },
+ "ID": { "type": "integer", "title": "Id" },
+ "Type": { "type": "string", "title": "Type" },
+ "TypeCode": { "type": "integer", "title": "Typecode" },
+ "Tag": { "type": "string", "title": "Tag" },
+ "MessageID": { "type": "string", "title": "Messageid" },
+ "Details": { "type": "string", "title": "Details" },
+ "Email": { "type": "string", "title": "Email" },
+ "From": { "type": "string", "title": "From" },
+ "BouncedAt": { "type": "string", "title": "Bouncedat" },
+ "Inactive": { "type": "boolean", "title": "Inactive" },
+ "DumpAvailable": { "type": "boolean", "title": "Dumpavailable" },
+ "CanActivate": { "type": "boolean", "title": "Canactivate" },
+ "Subject": { "type": "string", "title": "Subject" },
+ "ServerID": { "type": "integer", "title": "Serverid" },
+ "MessageStream": { "type": "string", "title": "Messagestream" },
+ "Content": { "type": "string", "title": "Content" },
+ "Name": { "type": "string", "title": "Name" },
+ "Description": { "type": "string", "title": "Description" },
+ "Metadata": {
+ "additionalProperties": { "type": "string" },
+ "type": "object",
+ "title": "Metadata"
+ }
+ },
+ "type": "object",
+ "required": [
+ "ID",
+ "Type",
+ "TypeCode",
+ "Tag",
+ "MessageID",
+ "Details",
+ "Email",
+ "From",
+ "BouncedAt",
+ "Inactive",
+ "DumpAvailable",
+ "CanActivate",
+ "Subject",
+ "ServerID",
+ "MessageStream",
+ "Content",
+ "Name",
+ "Description",
+ "Metadata"
+ ],
+ "title": "PostmarkSpamComplaintWebhook"
+ },
+ "PostmarkSubscriptionChangeWebhook": {
+ "properties": {
+ "RecordType": {
+ "type": "string",
+ "const": "SubscriptionChange",
+ "title": "Recordtype",
+ "default": "SubscriptionChange"
+ },
+ "MessageID": { "type": "string", "title": "Messageid" },
+ "ServerID": { "type": "integer", "title": "Serverid" },
+ "MessageStream": { "type": "string", "title": "Messagestream" },
+ "ChangedAt": { "type": "string", "title": "Changedat" },
+ "Recipient": { "type": "string", "title": "Recipient" },
+ "Origin": { "type": "string", "title": "Origin" },
+ "SuppressSending": { "type": "boolean", "title": "Suppresssending" },
+ "SuppressionReason": {
+ "type": "string",
+ "title": "Suppressionreason"
+ },
+ "Tag": { "type": "string", "title": "Tag" },
+ "Metadata": {
+ "additionalProperties": { "type": "string" },
+ "type": "object",
+ "title": "Metadata"
+ }
+ },
+ "type": "object",
+ "required": [
+ "MessageID",
+ "ServerID",
+ "MessageStream",
+ "ChangedAt",
+ "Recipient",
+ "Origin",
+ "SuppressSending",
+ "SuppressionReason",
+ "Tag",
+ "Metadata"
+ ],
+ "title": "PostmarkSubscriptionChangeWebhook"
+ },
+ "Profile": {
+ "properties": {
+ "name": { "type": "string", "title": "Name" },
+ "username": { "type": "string", "title": "Username" },
+ "description": { "type": "string", "title": "Description" },
+ "links": {
+ "items": { "type": "string" },
+ "type": "array",
+ "title": "Links"
+ },
+ "avatar_url": { "type": "string", "title": "Avatar Url" },
+ "is_featured": {
+ "type": "boolean",
+ "title": "Is Featured",
+ "default": false
+ }
+ },
+ "type": "object",
+ "required": ["name", "username", "description", "links", "avatar_url"],
+ "title": "Profile"
+ },
+ "ProfileDetails": {
+ "properties": {
+ "name": { "type": "string", "title": "Name" },
+ "username": { "type": "string", "title": "Username" },
+ "description": { "type": "string", "title": "Description" },
+ "links": {
+ "items": { "type": "string" },
+ "type": "array",
+ "title": "Links"
+ },
+ "avatar_url": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Avatar Url"
+ }
+ },
+ "type": "object",
+ "required": ["name", "username", "description", "links"],
+ "title": "ProfileDetails"
+ },
+ "ProviderName": {
+ "type": "string",
+ "enum": [
+ "aiml_api",
+ "anthropic",
+ "apollo",
+ "compass",
+ "discord",
+ "d_id",
+ "e2b",
+ "exa",
+ "fal",
+ "generic_webhook",
+ "github",
+ "google",
+ "google_maps",
+ "groq",
+ "hubspot",
+ "ideogram",
+ "jina",
+ "linear",
+ "llama_api",
+ "medium",
+ "mem0",
+ "notion",
+ "nvidia",
+ "ollama",
+ "openai",
+ "openweathermap",
+ "open_router",
+ "pinecone",
+ "reddit",
+ "replicate",
+ "revid",
+ "screenshotone",
+ "slant3d",
+ "smartlead",
+ "smtp",
+ "twitter",
+ "todoist",
+ "unreal_speech",
+ "zerobounce"
+ ],
+ "title": "ProviderName"
+ },
+ "RefundRequest": {
+ "properties": {
+ "id": { "type": "string", "title": "Id" },
+ "user_id": { "type": "string", "title": "User Id" },
+ "transaction_key": { "type": "string", "title": "Transaction Key" },
+ "amount": { "type": "integer", "title": "Amount" },
+ "reason": { "type": "string", "title": "Reason" },
+ "result": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Result"
+ },
+ "status": { "type": "string", "title": "Status" },
+ "created_at": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Created At"
+ },
+ "updated_at": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Updated At"
+ }
+ },
+ "type": "object",
+ "required": [
+ "id",
+ "user_id",
+ "transaction_key",
+ "amount",
+ "reason",
+ "status",
+ "created_at",
+ "updated_at"
+ ],
+ "title": "RefundRequest"
+ },
+ "RequestTopUp": {
+ "properties": {
+ "credit_amount": { "type": "integer", "title": "Credit Amount" }
+ },
+ "type": "object",
+ "required": ["credit_amount"],
+ "title": "RequestTopUp"
+ },
+ "ReviewSubmissionRequest": {
+ "properties": {
+ "store_listing_version_id": {
+ "type": "string",
+ "title": "Store Listing Version Id"
+ },
+ "is_approved": { "type": "boolean", "title": "Is Approved" },
+ "comments": { "type": "string", "title": "Comments" },
+ "internal_comments": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Internal Comments"
+ }
+ },
+ "type": "object",
+ "required": ["store_listing_version_id", "is_approved", "comments"],
+ "title": "ReviewSubmissionRequest"
+ },
+ "ScheduleCreationRequest": {
+ "properties": {
+ "cron": { "type": "string", "title": "Cron" },
+ "input_data": {
+ "additionalProperties": true,
+ "type": "object",
+ "title": "Input Data"
+ },
+ "graph_id": { "type": "string", "title": "Graph Id" },
+ "graph_version": { "type": "integer", "title": "Graph Version" }
+ },
+ "type": "object",
+ "required": ["cron", "input_data", "graph_id", "graph_version"],
+ "title": "ScheduleCreationRequest"
+ },
+ "SetGraphActiveVersion": {
+ "properties": {
+ "active_graph_version": {
+ "type": "integer",
+ "title": "Active Graph Version"
+ }
+ },
+ "type": "object",
+ "required": ["active_graph_version"],
+ "title": "SetGraphActiveVersion"
+ },
+ "Stats": {
+ "properties": {
+ "cost": {
+ "type": "integer",
+ "title": "Cost",
+ "description": "Execution cost (cents)",
+ "default": 0
+ },
+ "duration": {
+ "type": "number",
+ "title": "Duration",
+ "description": "Seconds from start to end of run",
+ "default": 0
+ },
+ "duration_cpu_only": {
+ "type": "number",
+ "title": "Duration Cpu Only",
+ "description": "CPU sec of duration",
+ "default": 0
+ },
+ "node_exec_time": {
+ "type": "number",
+ "title": "Node Exec Time",
+ "description": "Seconds of total node runtime",
+ "default": 0
+ },
+ "node_exec_time_cpu_only": {
+ "type": "number",
+ "title": "Node Exec Time Cpu Only",
+ "description": "CPU sec of node_exec_time",
+ "default": 0
+ },
+ "node_exec_count": {
+ "type": "integer",
+ "title": "Node Exec Count",
+ "description": "Number of node executions",
+ "default": 0
+ },
+ "node_error_count": {
+ "type": "integer",
+ "title": "Node Error Count",
+ "description": "Number of node errors",
+ "default": 0
+ },
+ "error": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Error",
+ "description": "Error message if any"
+ }
+ },
+ "additionalProperties": true,
+ "type": "object",
+ "title": "Stats"
+ },
+ "StoreAgent": {
+ "properties": {
+ "slug": { "type": "string", "title": "Slug" },
+ "agent_name": { "type": "string", "title": "Agent Name" },
+ "agent_image": { "type": "string", "title": "Agent Image" },
+ "creator": { "type": "string", "title": "Creator" },
+ "creator_avatar": { "type": "string", "title": "Creator Avatar" },
+ "sub_heading": { "type": "string", "title": "Sub Heading" },
+ "description": { "type": "string", "title": "Description" },
+ "runs": { "type": "integer", "title": "Runs" },
+ "rating": { "type": "number", "title": "Rating" }
+ },
+ "type": "object",
+ "required": [
+ "slug",
+ "agent_name",
+ "agent_image",
+ "creator",
+ "creator_avatar",
+ "sub_heading",
+ "description",
+ "runs",
+ "rating"
+ ],
+ "title": "StoreAgent"
+ },
+ "StoreAgentDetails": {
+ "properties": {
+ "store_listing_version_id": {
+ "type": "string",
+ "title": "Store Listing Version Id"
+ },
+ "slug": { "type": "string", "title": "Slug" },
+ "agent_name": { "type": "string", "title": "Agent Name" },
+ "agent_video": { "type": "string", "title": "Agent Video" },
+ "agent_image": {
+ "items": { "type": "string" },
+ "type": "array",
+ "title": "Agent Image"
+ },
+ "creator": { "type": "string", "title": "Creator" },
+ "creator_avatar": { "type": "string", "title": "Creator Avatar" },
+ "sub_heading": { "type": "string", "title": "Sub Heading" },
+ "description": { "type": "string", "title": "Description" },
+ "categories": {
+ "items": { "type": "string" },
+ "type": "array",
+ "title": "Categories"
+ },
+ "runs": { "type": "integer", "title": "Runs" },
+ "rating": { "type": "number", "title": "Rating" },
+ "versions": {
+ "items": { "type": "string" },
+ "type": "array",
+ "title": "Versions"
+ },
+ "last_updated": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Last Updated"
+ },
+ "active_version_id": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Active Version Id"
+ },
+ "has_approved_version": {
+ "type": "boolean",
+ "title": "Has Approved Version",
+ "default": false
+ }
+ },
+ "type": "object",
+ "required": [
+ "store_listing_version_id",
+ "slug",
+ "agent_name",
+ "agent_video",
+ "agent_image",
+ "creator",
+ "creator_avatar",
+ "sub_heading",
+ "description",
+ "categories",
+ "runs",
+ "rating",
+ "versions",
+ "last_updated"
+ ],
+ "title": "StoreAgentDetails"
+ },
+ "StoreAgentsResponse": {
+ "properties": {
+ "agents": {
+ "items": { "$ref": "#/components/schemas/StoreAgent" },
+ "type": "array",
+ "title": "Agents"
+ },
+ "pagination": { "$ref": "#/components/schemas/Pagination" }
+ },
+ "type": "object",
+ "required": ["agents", "pagination"],
+ "title": "StoreAgentsResponse"
+ },
+ "StoreListingWithVersions": {
+ "properties": {
+ "listing_id": { "type": "string", "title": "Listing Id" },
+ "slug": { "type": "string", "title": "Slug" },
+ "agent_id": { "type": "string", "title": "Agent Id" },
+ "agent_version": { "type": "integer", "title": "Agent Version" },
+ "active_version_id": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Active Version Id"
+ },
+ "has_approved_version": {
+ "type": "boolean",
+ "title": "Has Approved Version",
+ "default": false
+ },
+ "creator_email": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Creator Email"
+ },
+ "latest_version": {
+ "anyOf": [
+ { "$ref": "#/components/schemas/StoreSubmission" },
+ { "type": "null" }
+ ]
+ },
+ "versions": {
+ "items": { "$ref": "#/components/schemas/StoreSubmission" },
+ "type": "array",
+ "title": "Versions",
+ "default": []
+ }
+ },
+ "type": "object",
+ "required": ["listing_id", "slug", "agent_id", "agent_version"],
+ "title": "StoreListingWithVersions",
+ "description": "A store listing with its version history"
+ },
+ "StoreListingsWithVersionsResponse": {
+ "properties": {
+ "listings": {
+ "items": {
+ "$ref": "#/components/schemas/StoreListingWithVersions"
+ },
+ "type": "array",
+ "title": "Listings"
+ },
+ "pagination": { "$ref": "#/components/schemas/Pagination" }
+ },
+ "type": "object",
+ "required": ["listings", "pagination"],
+ "title": "StoreListingsWithVersionsResponse",
+ "description": "Response model for listings with version history"
+ },
+ "StoreReview": {
+ "properties": {
+ "score": { "type": "integer", "title": "Score" },
+ "comments": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Comments"
+ }
+ },
+ "type": "object",
+ "required": ["score"],
+ "title": "StoreReview"
+ },
+ "StoreReviewCreate": {
+ "properties": {
+ "store_listing_version_id": {
+ "type": "string",
+ "title": "Store Listing Version Id"
+ },
+ "score": { "type": "integer", "title": "Score" },
+ "comments": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Comments"
+ }
+ },
+ "type": "object",
+ "required": ["store_listing_version_id", "score"],
+ "title": "StoreReviewCreate"
+ },
+ "StoreSubmission": {
+ "properties": {
+ "agent_id": { "type": "string", "title": "Agent Id" },
+ "agent_version": { "type": "integer", "title": "Agent Version" },
+ "name": { "type": "string", "title": "Name" },
+ "sub_heading": { "type": "string", "title": "Sub Heading" },
+ "slug": { "type": "string", "title": "Slug" },
+ "description": { "type": "string", "title": "Description" },
+ "image_urls": {
+ "items": { "type": "string" },
+ "type": "array",
+ "title": "Image Urls"
+ },
+ "date_submitted": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Date Submitted"
+ },
+ "status": { "$ref": "#/components/schemas/SubmissionStatus" },
+ "runs": { "type": "integer", "title": "Runs" },
+ "rating": { "type": "number", "title": "Rating" },
+ "store_listing_version_id": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Store Listing Version Id"
+ },
+ "version": {
+ "anyOf": [{ "type": "integer" }, { "type": "null" }],
+ "title": "Version"
+ },
+ "reviewer_id": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Reviewer Id"
+ },
+ "review_comments": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Review Comments"
+ },
+ "internal_comments": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Internal Comments"
+ },
+ "reviewed_at": {
+ "anyOf": [
+ { "type": "string", "format": "date-time" },
+ { "type": "null" }
+ ],
+ "title": "Reviewed At"
+ },
+ "changes_summary": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Changes Summary"
+ }
+ },
+ "type": "object",
+ "required": [
+ "agent_id",
+ "agent_version",
+ "name",
+ "sub_heading",
+ "slug",
+ "description",
+ "image_urls",
+ "date_submitted",
+ "status",
+ "runs",
+ "rating"
+ ],
+ "title": "StoreSubmission"
+ },
+ "StoreSubmissionRequest": {
+ "properties": {
+ "agent_id": { "type": "string", "title": "Agent Id" },
+ "agent_version": { "type": "integer", "title": "Agent Version" },
+ "slug": { "type": "string", "title": "Slug" },
+ "name": { "type": "string", "title": "Name" },
+ "sub_heading": { "type": "string", "title": "Sub Heading" },
+ "video_url": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Video Url"
+ },
+ "image_urls": {
+ "items": { "type": "string" },
+ "type": "array",
+ "title": "Image Urls",
+ "default": []
+ },
+ "description": {
+ "type": "string",
+ "title": "Description",
+ "default": ""
+ },
+ "categories": {
+ "items": { "type": "string" },
+ "type": "array",
+ "title": "Categories",
+ "default": []
+ },
+ "changes_summary": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Changes Summary"
+ }
+ },
+ "type": "object",
+ "required": [
+ "agent_id",
+ "agent_version",
+ "slug",
+ "name",
+ "sub_heading"
+ ],
+ "title": "StoreSubmissionRequest"
+ },
+ "StoreSubmissionsResponse": {
+ "properties": {
+ "submissions": {
+ "items": { "$ref": "#/components/schemas/StoreSubmission" },
+ "type": "array",
+ "title": "Submissions"
+ },
+ "pagination": { "$ref": "#/components/schemas/Pagination" }
+ },
+ "type": "object",
+ "required": ["submissions", "pagination"],
+ "title": "StoreSubmissionsResponse"
+ },
+ "SubmissionStatus": {
+ "type": "string",
+ "enum": ["DRAFT", "PENDING", "APPROVED", "REJECTED"],
+ "title": "SubmissionStatus"
+ },
+ "TransactionHistory": {
+ "properties": {
+ "transactions": {
+ "items": { "$ref": "#/components/schemas/UserTransaction" },
+ "type": "array",
+ "title": "Transactions"
+ },
+ "next_transaction_time": {
+ "anyOf": [
+ { "type": "string", "format": "date-time" },
+ { "type": "null" }
+ ],
+ "title": "Next Transaction Time"
+ }
+ },
+ "type": "object",
+ "required": ["transactions", "next_transaction_time"],
+ "title": "TransactionHistory"
+ },
+ "TurnstileVerifyRequest": {
+ "properties": {
+ "token": {
+ "type": "string",
+ "title": "Token",
+ "description": "The Turnstile token to verify"
+ },
+ "action": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Action",
+ "description": "The action that the user is attempting to perform"
+ }
+ },
+ "type": "object",
+ "required": ["token"],
+ "title": "TurnstileVerifyRequest",
+ "description": "Request model for verifying a Turnstile token."
+ },
+ "TurnstileVerifyResponse": {
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "title": "Success",
+ "description": "Whether the token verification was successful"
+ },
+ "error": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Error",
+ "description": "Error message if verification failed"
+ },
+ "challenge_timestamp": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Challenge Timestamp",
+ "description": "Timestamp of the challenge (ISO format)"
+ },
+ "hostname": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Hostname",
+ "description": "Hostname of the site where the challenge was solved"
+ },
+ "action": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Action",
+ "description": "The action associated with this verification"
+ }
+ },
+ "type": "object",
+ "required": ["success"],
+ "title": "TurnstileVerifyResponse",
+ "description": "Response model for the Turnstile verification endpoint."
+ },
+ "UpdatePermissionsRequest": {
+ "properties": {
+ "permissions": {
+ "items": { "$ref": "#/components/schemas/APIKeyPermission" },
+ "type": "array",
+ "title": "Permissions"
+ }
+ },
+ "type": "object",
+ "required": ["permissions"],
+ "title": "UpdatePermissionsRequest"
+ },
+ "UserHistoryResponse": {
+ "properties": {
+ "history": {
+ "items": { "$ref": "#/components/schemas/UserTransaction" },
+ "type": "array",
+ "title": "History"
+ },
+ "pagination": { "$ref": "#/components/schemas/Pagination" }
+ },
+ "type": "object",
+ "required": ["history", "pagination"],
+ "title": "UserHistoryResponse",
+ "description": "Response model for listings with version history"
+ },
+ "UserOnboardingUpdate": {
+ "properties": {
+ "completedSteps": {
+ "anyOf": [
+ {
+ "items": { "$ref": "#/components/schemas/OnboardingStep" },
+ "type": "array"
+ },
+ { "type": "null" }
+ ],
+ "title": "Completedsteps"
+ },
+ "notificationDot": {
+ "anyOf": [{ "type": "boolean" }, { "type": "null" }],
+ "title": "Notificationdot"
+ },
+ "notified": {
+ "anyOf": [
+ {
+ "items": { "$ref": "#/components/schemas/OnboardingStep" },
+ "type": "array"
+ },
+ { "type": "null" }
+ ],
+ "title": "Notified"
+ },
+ "usageReason": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Usagereason"
+ },
+ "integrations": {
+ "anyOf": [
+ { "items": { "type": "string" }, "type": "array" },
+ { "type": "null" }
+ ],
+ "title": "Integrations"
+ },
+ "otherIntegrations": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Otherintegrations"
+ },
+ "selectedStoreListingVersionId": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Selectedstorelistingversionid"
+ },
+ "agentInput": {
+ "anyOf": [
+ { "additionalProperties": true, "type": "object" },
+ { "type": "null" }
+ ],
+ "title": "Agentinput"
+ },
+ "onboardingAgentExecutionId": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Onboardingagentexecutionid"
+ },
+ "agentRuns": {
+ "anyOf": [{ "type": "integer" }, { "type": "null" }],
+ "title": "Agentruns"
+ }
+ },
+ "type": "object",
+ "title": "UserOnboardingUpdate"
+ },
+ "UserPasswordCredentials": {
+ "properties": {
+ "id": { "type": "string", "title": "Id" },
+ "provider": { "type": "string", "title": "Provider" },
+ "title": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Title"
+ },
+ "type": {
+ "type": "string",
+ "const": "user_password",
+ "title": "Type",
+ "default": "user_password"
+ },
+ "username": {
+ "type": "string",
+ "format": "password",
+ "title": "Username",
+ "writeOnly": true
+ },
+ "password": {
+ "type": "string",
+ "format": "password",
+ "title": "Password",
+ "writeOnly": true
+ }
+ },
+ "type": "object",
+ "required": ["provider", "username", "password"],
+ "title": "UserPasswordCredentials"
+ },
+ "UserTransaction": {
+ "properties": {
+ "transaction_key": {
+ "type": "string",
+ "title": "Transaction Key",
+ "default": ""
+ },
+ "transaction_time": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Transaction Time",
+ "default": "0001-01-01T00:00:00Z"
+ },
+ "transaction_type": {
+ "$ref": "#/components/schemas/CreditTransactionType",
+ "default": "USAGE"
+ },
+ "amount": { "type": "integer", "title": "Amount", "default": 0 },
+ "running_balance": {
+ "type": "integer",
+ "title": "Running Balance",
+ "default": 0
+ },
+ "current_balance": {
+ "type": "integer",
+ "title": "Current Balance",
+ "default": 0
+ },
+ "description": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Description"
+ },
+ "usage_graph_id": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Usage Graph Id"
+ },
+ "usage_execution_id": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Usage Execution Id"
+ },
+ "usage_node_count": {
+ "type": "integer",
+ "title": "Usage Node Count",
+ "default": 0
+ },
+ "usage_start_time": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Usage Start Time",
+ "default": "9999-12-31T23:59:59.999999Z"
+ },
+ "user_id": { "type": "string", "title": "User Id" },
+ "user_email": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "User Email"
+ },
+ "reason": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Reason"
+ },
+ "admin_email": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Admin Email"
+ },
+ "extra_data": {
+ "anyOf": [{ "type": "string" }, { "type": "null" }],
+ "title": "Extra Data"
+ }
+ },
+ "type": "object",
+ "required": ["user_id"],
+ "title": "UserTransaction"
+ },
+ "ValidationError": {
+ "properties": {
+ "loc": {
+ "items": { "anyOf": [{ "type": "string" }, { "type": "integer" }] },
+ "type": "array",
+ "title": "Location"
+ },
+ "msg": { "type": "string", "title": "Message" },
+ "type": { "type": "string", "title": "Error Type" }
+ },
+ "type": "object",
+ "required": ["loc", "msg", "type"],
+ "title": "ValidationError"
+ },
+ "Webhook": {
+ "properties": {
+ "id": { "type": "string", "title": "Id" },
+ "user_id": { "type": "string", "title": "User Id" },
+ "provider": { "$ref": "#/components/schemas/ProviderName" },
+ "credentials_id": { "type": "string", "title": "Credentials Id" },
+ "webhook_type": { "type": "string", "title": "Webhook Type" },
+ "resource": { "type": "string", "title": "Resource" },
+ "events": {
+ "items": { "type": "string" },
+ "type": "array",
+ "title": "Events"
+ },
+ "config": {
+ "additionalProperties": true,
+ "type": "object",
+ "title": "Config"
+ },
+ "secret": { "type": "string", "title": "Secret" },
+ "provider_webhook_id": {
+ "type": "string",
+ "title": "Provider Webhook Id"
+ },
+ "attached_nodes": {
+ "anyOf": [
+ {
+ "items": { "$ref": "#/components/schemas/NodeModel" },
+ "type": "array"
+ },
+ { "type": "null" }
+ ],
+ "title": "Attached Nodes"
+ },
+ "url": { "type": "string", "title": "Url", "readOnly": true }
+ },
+ "type": "object",
+ "required": [
+ "user_id",
+ "provider",
+ "credentials_id",
+ "webhook_type",
+ "resource",
+ "events",
+ "secret",
+ "provider_webhook_id",
+ "url"
+ ],
+ "title": "Webhook"
+ }
+ },
+ "securitySchemes": {
+ "APIKeyHeader": {
+ "type": "apiKey",
+ "in": "header",
+ "name": "X-Postmark-Webhook-Token"
+ }
+ }
+ }
+}
diff --git a/autogpt_platform/frontend/src/api/transformers/fix-tags.mjs b/autogpt_platform/frontend/src/api/transformers/fix-tags.mjs
new file mode 100644
index 0000000000..e1bc2c4267
--- /dev/null
+++ b/autogpt_platform/frontend/src/api/transformers/fix-tags.mjs
@@ -0,0 +1,57 @@
+/**
+ * Transformer function for orval that fixes tags in OpenAPI spec.
+ * 1. Create a set of tags so we have unique values
+ * 2. Then remove public, private, v1, and v2 tags from tags array
+ * 3. Then arrange remaining tags alphabetically and only keep the first one
+ *
+ * @param {OpenAPIObject} inputSchema
+ * @return {OpenAPIObject}
+ */
+
+export const tagTransformer = (inputSchema) => {
+ const processedPaths = Object.entries(inputSchema.paths || {}).reduce(
+ (acc, [path, pathItem]) => ({
+ ...acc,
+ [path]: Object.entries(pathItem || {}).reduce(
+ (pathItemAcc, [verb, operation]) => {
+ if (typeof operation === "object" && operation !== null) {
+ // 1. Create a set of tags so we have unique values
+ const uniqueTags = Array.from(new Set(operation.tags || []));
+
+ // 2. Remove public, private, v1, and v2 tags from tags array
+ const filteredTags = uniqueTags.filter(
+ (tag) =>
+ !["public", "private"].includes(tag.toLowerCase()) &&
+ !/^v[12]$/i.test(tag),
+ );
+
+ // 3. Arrange tags alphabetically and only keep the first one
+ const sortedTags = filteredTags.sort((a, b) => a.localeCompare(b));
+ const firstTag = sortedTags.length > 0 ? [sortedTags[0]] : [];
+
+ return {
+ ...pathItemAcc,
+ [verb]: {
+ ...operation,
+ tags: firstTag,
+ },
+ };
+ }
+ return {
+ ...pathItemAcc,
+ [verb]: operation,
+ };
+ },
+ {},
+ ),
+ }),
+ {},
+ );
+
+ return {
+ ...inputSchema,
+ paths: processedPaths,
+ };
+};
+
+export default tagTransformer;
diff --git a/autogpt_platform/frontend/src/app/(no-navbar)/onboarding/3-services/page.tsx b/autogpt_platform/frontend/src/app/(no-navbar)/onboarding/3-services/page.tsx
index 92623301d8..a7867aca50 100644
--- a/autogpt_platform/frontend/src/app/(no-navbar)/onboarding/3-services/page.tsx
+++ b/autogpt_platform/frontend/src/app/(no-navbar)/onboarding/3-services/page.tsx
@@ -9,7 +9,6 @@ import { OnboardingText } from "@/components/onboarding/OnboardingText";
import { OnboardingGrid } from "@/components/onboarding/OnboardingGrid";
import { useCallback } from "react";
import OnboardingInput from "@/components/onboarding/OnboardingInput";
-import { isEmptyOrWhitespace } from "@/lib/utils";
import { useOnboarding } from "@/components/onboarding/onboarding-provider";
const services = [
diff --git a/autogpt_platform/frontend/src/app/(no-navbar)/onboarding/5-run/page.tsx b/autogpt_platform/frontend/src/app/(no-navbar)/onboarding/5-run/page.tsx
index 5ea5e3adf2..7769e0c48a 100644
--- a/autogpt_platform/frontend/src/app/(no-navbar)/onboarding/5-run/page.tsx
+++ b/autogpt_platform/frontend/src/app/(no-navbar)/onboarding/5-run/page.tsx
@@ -49,6 +49,7 @@ export default function Page() {
.getAgentMetaByStoreListingVersionId(state?.selectedStoreListingVersionId)
.then((agent) => {
setAgent(agent);
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
const update: { [key: string]: any } = {};
// Set default values from schema
Object.entries(agent.input_schema.properties).forEach(
diff --git a/autogpt_platform/frontend/src/app/(platform)/admin/layout.tsx b/autogpt_platform/frontend/src/app/(platform)/admin/layout.tsx
index cb72daee73..bfb2b2695d 100644
--- a/autogpt_platform/frontend/src/app/(platform)/admin/layout.tsx
+++ b/autogpt_platform/frontend/src/app/(platform)/admin/layout.tsx
@@ -1,6 +1,5 @@
-import { ShoppingBag } from "lucide-react";
import { Sidebar } from "@/components/agptui/Sidebar";
-import { Users, DollarSign, LogOut } from "lucide-react";
+import { Users, DollarSign } from "lucide-react";
import { IconSliders } from "@/components/ui/icons";
diff --git a/autogpt_platform/frontend/src/app/(platform)/admin/marketplace/actions.ts b/autogpt_platform/frontend/src/app/(platform)/admin/marketplace/actions.ts
index ad7f48f24c..480e79e669 100644
--- a/autogpt_platform/frontend/src/app/(platform)/admin/marketplace/actions.ts
+++ b/autogpt_platform/frontend/src/app/(platform)/admin/marketplace/actions.ts
@@ -3,9 +3,7 @@
import { revalidatePath } from "next/cache";
import BackendApi from "@/lib/autogpt-server-api";
import {
- NotificationPreferenceDTO,
StoreListingsWithVersionsResponse,
- StoreSubmissionsResponse,
SubmissionStatus,
} from "@/lib/autogpt-server-api/types";
diff --git a/autogpt_platform/frontend/src/app/(platform)/admin/spending/actions.ts b/autogpt_platform/frontend/src/app/(platform)/admin/spending/actions.ts
index b6ef75a599..ea4a194acd 100644
--- a/autogpt_platform/frontend/src/app/(platform)/admin/spending/actions.ts
+++ b/autogpt_platform/frontend/src/app/(platform)/admin/spending/actions.ts
@@ -29,6 +29,7 @@ export async function getUsersTransactionHistory(
search?: string,
transactionType?: CreditTransactionType,
): Promise {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
const data: Record = {
page,
page_size: pageSize,
diff --git a/autogpt_platform/frontend/src/app/(platform)/auth/callback/route.ts b/autogpt_platform/frontend/src/app/(platform)/auth/callback/route.ts
index 54db111dfd..62e324761e 100644
--- a/autogpt_platform/frontend/src/app/(platform)/auth/callback/route.ts
+++ b/autogpt_platform/frontend/src/app/(platform)/auth/callback/route.ts
@@ -11,13 +11,25 @@ async function shouldShowOnboarding() {
);
}
+// Validate redirect URL to prevent open redirect attacks
+function validateRedirectUrl(url: string): string {
+ // Only allow relative URLs that start with /
+ if (url.startsWith("/") && !url.startsWith("//")) {
+ return url;
+ }
+ // Default to home page for any invalid URLs
+ return "/";
+}
+
// Handle the callback to complete the user session login
export async function GET(request: Request) {
const { searchParams, origin } = new URL(request.url);
const code = searchParams.get("code");
// if "next" is in param, use it as the redirect URL
- let next = searchParams.get("next") ?? "/";
+ const nextParam = searchParams.get("next") ?? "/";
+ // Validate redirect URL to prevent open redirect attacks
+ let next = validateRedirectUrl(nextParam);
if (code) {
const supabase = await getServerSupabase();
@@ -26,7 +38,7 @@ export async function GET(request: Request) {
return NextResponse.redirect(`${origin}/error`);
}
- const { data, error } = await supabase.auth.exchangeCodeForSession(code);
+ const { error } = await supabase.auth.exchangeCodeForSession(code);
// data.session?.refresh_token is available if you need to store it for later use
if (!error) {
try {
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 5d4100d48e..18e74369df 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
@@ -5,7 +5,7 @@ import { NextResponse } from "next/server";
// controlled by the CredentialsInput component. The CredentialsInput opens the login
// page in a pop-up window, which then redirects to this route to close the loop.
export async function GET(request: Request) {
- const { searchParams, origin } = new URL(request.url);
+ const { searchParams } = new URL(request.url);
const code = searchParams.get("code");
const state = searchParams.get("state");
diff --git a/autogpt_platform/frontend/src/app/(platform)/build/actions.ts b/autogpt_platform/frontend/src/app/(platform)/build/actions.ts
index 16c577d16c..7907d919f4 100644
--- a/autogpt_platform/frontend/src/app/(platform)/build/actions.ts
+++ b/autogpt_platform/frontend/src/app/(platform)/build/actions.ts
@@ -1,6 +1,5 @@
"use server";
-import { revalidatePath } from "next/cache";
import BackendAPI from "@/lib/autogpt-server-api/client";
import { OttoQuery, OttoResponse } from "@/lib/autogpt-server-api/types";
diff --git a/autogpt_platform/frontend/src/app/(platform)/marketplace/creator/[creator]/page.tsx b/autogpt_platform/frontend/src/app/(platform)/marketplace/creator/[creator]/page.tsx
index b462cdb704..484022f151 100644
--- a/autogpt_platform/frontend/src/app/(platform)/marketplace/creator/[creator]/page.tsx
+++ b/autogpt_platform/frontend/src/app/(platform)/marketplace/creator/[creator]/page.tsx
@@ -92,7 +92,7 @@ export default async function Page({
);
- } catch (error) {
+ } catch {
return (
Creator not found
diff --git a/autogpt_platform/frontend/src/app/(platform)/marketplace/search/page.tsx b/autogpt_platform/frontend/src/app/(platform)/marketplace/search/page.tsx
index 88f620f6ab..d9209b2c4a 100644
--- a/autogpt_platform/frontend/src/app/(platform)/marketplace/search/page.tsx
+++ b/autogpt_platform/frontend/src/app/(platform)/marketplace/search/page.tsx
@@ -8,6 +8,7 @@ import { Separator } from "@/components/ui/separator";
import { SearchFilterChips } from "@/components/agptui/SearchFilterChips";
import { SortDropdown } from "@/components/agptui/SortDropdown";
import { useBackendAPI } from "@/lib/autogpt-server-api/context";
+import { Creator, StoreAgent } from "@/lib/autogpt-server-api";
type MarketplaceSearchPageSearchParams = { searchTerm?: string; sort?: string };
@@ -33,8 +34,8 @@ function SearchResults({
}): React.ReactElement {
const [showAgents, setShowAgents] = useState(true);
const [showCreators, setShowCreators] = useState(true);
- const [agents, setAgents] = useState
([]);
- const [creators, setCreators] = useState([]);
+ const [agents, setAgents] = useState([]);
+ const [creators, setCreators] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const api = useBackendAPI();
diff --git a/autogpt_platform/frontend/src/app/(platform)/profile/(user)/dashboard/page.tsx b/autogpt_platform/frontend/src/app/(platform)/profile/(user)/dashboard/page.tsx
index e2cface85c..5c86d99f21 100644
--- a/autogpt_platform/frontend/src/app/(platform)/profile/(user)/dashboard/page.tsx
+++ b/autogpt_platform/frontend/src/app/(platform)/profile/(user)/dashboard/page.tsx
@@ -14,7 +14,7 @@ import {
import { useSupabase } from "@/lib/supabase/hooks/useSupabase";
import { useBackendAPI } from "@/lib/autogpt-server-api/context";
-export default function Page({}: {}) {
+export default function Page() {
const { supabase } = useSupabase();
const api = useBackendAPI();
const [submissions, setSubmissions] = useState();
diff --git a/autogpt_platform/frontend/src/app/layout.tsx b/autogpt_platform/frontend/src/app/layout.tsx
index 9df9c1b671..d99e0b15d2 100644
--- a/autogpt_platform/frontend/src/app/layout.tsx
+++ b/autogpt_platform/frontend/src/app/layout.tsx
@@ -1,4 +1,4 @@
-import React, { Suspense } from "react";
+import React from "react";
import type { Metadata } from "next";
import { fonts } from "@/components/styles/fonts";
@@ -8,6 +8,7 @@ import { Toaster } from "@/components/ui/toaster";
import { Providers } from "@/app/providers";
import TallyPopupSimple from "@/components/TallyPopup";
import { GoogleAnalytics } from "@/components/analytics/google-analytics";
+import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
export const metadata: Metadata = {
title: "AutoGPT Platform",
@@ -41,6 +42,14 @@ export default async function RootLayout({
{children}
+
+ {/* React Query DevTools is only available in development */}
+ {process.env.NEXT_PUBLIC_REACT_QUERY_DEVTOOL && (
+
+ )}
diff --git a/autogpt_platform/frontend/src/app/providers.tsx b/autogpt_platform/frontend/src/app/providers.tsx
index db9725d3f2..45f9fa5cc3 100644
--- a/autogpt_platform/frontend/src/app/providers.tsx
+++ b/autogpt_platform/frontend/src/app/providers.tsx
@@ -8,19 +8,24 @@ import { TooltipProvider } from "@/components/ui/tooltip";
import CredentialsProvider from "@/components/integrations/credentials-provider";
import { LaunchDarklyProvider } from "@/components/feature-flag/feature-flag-provider";
import OnboardingProvider from "@/components/onboarding/onboarding-provider";
+import { QueryClientProvider } from "@tanstack/react-query";
+import { getQueryClient } from "@/lib/react-query/queryClient";
export function Providers({ children, ...props }: ThemeProviderProps) {
+ const queryClient = getQueryClient();
return (
-
-
-
-
-
- {children}
-
-
-
-
-
+
+
+
+
+
+
+ {children}
+
+
+
+
+
+
);
}
diff --git a/autogpt_platform/frontend/src/components/ConnectionLine.tsx b/autogpt_platform/frontend/src/components/ConnectionLine.tsx
index 2111a7b253..0a790aedd4 100644
--- a/autogpt_platform/frontend/src/components/ConnectionLine.tsx
+++ b/autogpt_platform/frontend/src/components/ConnectionLine.tsx
@@ -17,8 +17,8 @@ export default function ConnectionLine({
}: ConnectionLineComponentProps) {
const sourceX =
fromPosition === Position.Right
- ? fromX + (fromHandle?.width! / 2 - 5)
- : fromX - (fromHandle?.width! / 2 - 5);
+ ? fromX + ((fromHandle?.width ?? 0) / 2 - 5)
+ : fromX - ((fromHandle?.width ?? 0) / 2 - 5);
const [path] = getBezierPath({
sourceX: sourceX,
diff --git a/autogpt_platform/frontend/src/components/CustomEdge.tsx b/autogpt_platform/frontend/src/components/CustomEdge.tsx
index bb620b2e6f..ecc9249fb2 100644
--- a/autogpt_platform/frontend/src/components/CustomEdge.tsx
+++ b/autogpt_platform/frontend/src/components/CustomEdge.tsx
@@ -93,7 +93,7 @@ export function CustomEdge({
return;
}
- const beadUp = data?.beadUp!;
+ const beadUp: number = data?.beadUp ?? 0;
// Add beads
setBeads(({ beads, created, destroyed }) => {
@@ -114,10 +114,8 @@ export function CustomEdge({
const newBeads = beads
.map((bead) => ({ ...bead }))
.filter((bead, index) => {
- const beadDown = data?.beadDown!;
-
- // Remove always one less bead in case of static edge, so it stays at the connection point
- const removeCount = beadDown - destroyed - (data?.isStatic ? 1 : 0);
+ const beadDown: number = data?.beadDown ?? 0;
+ const removeCount = beadDown - destroyed;
if (bead.t >= bead.targetT && index < removeCount) {
destroyedCount++;
return false;
@@ -153,10 +151,8 @@ export function CustomEdge({
};
})
.filter((bead, index) => {
- const beadDown = data?.beadDown!;
-
- // Remove always one less bead in case of static edge, so it stays at the connection point
- const removeCount = beadDown - destroyed - (data?.isStatic ? 1 : 0);
+ const beadDown: number = data?.beadDown ?? 0;
+ const removeCount = beadDown - destroyed;
if (bead.t >= bead.targetT && index < removeCount) {
destroyedCount++;
return false;
diff --git a/autogpt_platform/frontend/src/components/CustomNode.tsx b/autogpt_platform/frontend/src/components/CustomNode.tsx
index 0658ba9f7b..aa87ba30e2 100644
--- a/autogpt_platform/frontend/src/components/CustomNode.tsx
+++ b/autogpt_platform/frontend/src/components/CustomNode.tsx
@@ -27,6 +27,7 @@ import {
cn,
getValue,
hasNonNullNonObjectValue,
+ isObject,
parseKeys,
setNestedProperty,
} from "@/lib/utils";
@@ -94,13 +95,7 @@ export type CustomNodeData = {
export type CustomNode = XYNode;
export const CustomNode = React.memo(
- function CustomNode({
- data,
- id,
- width,
- height,
- selected,
- }: NodeProps) {
+ function CustomNode({ data, id, height, selected }: NodeProps) {
const [isOutputOpen, setIsOutputOpen] = useState(
data.isOutputOpen || false,
);
@@ -198,10 +193,6 @@ export const CustomNode = React.memo(
[id, updateNodeData],
);
- const toggleOutput = (checked: boolean) => {
- setIsOutputOpen(checked);
- };
-
const toggleAdvancedSettings = (checked: boolean) => {
setIsAdvancedOpen(checked);
};
@@ -255,7 +246,7 @@ export const CustomNode = React.memo(
nodeType: BlockUIType,
) => {
if (!schema?.properties) return null;
- let keys = Object.entries(schema.properties);
+ const keys = Object.entries(schema.properties);
switch (nodeType) {
case BlockUIType.NOTE:
// For NOTE blocks, don't render any input handles
@@ -435,8 +426,15 @@ export const CustomNode = React.memo(
if (activeKey) {
try {
const parsedValue = JSON.parse(value);
- handleInputChange(activeKey, parsedValue);
- } catch (error) {
+ // Validate that the parsed value is safe before using it
+ if (isObject(parsedValue) || Array.isArray(parsedValue)) {
+ handleInputChange(activeKey, parsedValue);
+ } else {
+ // For primitive values, use the original string
+ handleInputChange(activeKey, value);
+ }
+ } catch {
+ // If JSON parsing fails, treat as plain text
handleInputChange(activeKey, value);
}
}
diff --git a/autogpt_platform/frontend/src/components/DataTable.tsx b/autogpt_platform/frontend/src/components/DataTable.tsx
index aba62af6c2..b7bb83c80a 100644
--- a/autogpt_platform/frontend/src/components/DataTable.tsx
+++ b/autogpt_platform/frontend/src/components/DataTable.tsx
@@ -1,6 +1,8 @@
-import React from "react";
import { beautifyString } from "@/lib/utils";
+import { Clipboard } from "lucide-react";
+import React from "react";
import { Button } from "./ui/button";
+import { ContentRenderer } from "./ui/render";
import {
Table,
TableBody,
@@ -9,9 +11,7 @@ import {
TableHeader,
TableRow,
} from "./ui/table";
-import { Clipboard } from "lucide-react";
import { useToast } from "./ui/use-toast";
-import { ContentRenderer } from "./ui/render";
type DataTableProps = {
title?: string;
@@ -25,7 +25,6 @@ export default function DataTable({
data,
}: DataTableProps) {
const { toast } = useToast();
- const maxChars = 100;
const copyData = (pin: string, data: string) => {
navigator.clipboard.writeText(data).then(() => {
diff --git a/autogpt_platform/frontend/src/components/Flow.tsx b/autogpt_platform/frontend/src/components/Flow.tsx
index ece3239580..345fc60b5a 100644
--- a/autogpt_platform/frontend/src/components/Flow.tsx
+++ b/autogpt_platform/frontend/src/components/Flow.tsx
@@ -90,9 +90,7 @@ const FlowEditor: React.FC<{
} = useReactFlow();
const [nodeId, setNodeId] = useState(1);
const [isAnyModalOpen, setIsAnyModalOpen] = useState(false);
- const [visualizeBeads, setVisualizeBeads] = useState<
- "no" | "static" | "animate"
- >("animate");
+ const [visualizeBeads] = useState<"no" | "static" | "animate">("animate");
const [flowExecutionID, setFlowExecutionID] = useState<
GraphExecutionID | undefined
>();
@@ -366,10 +364,7 @@ const FlowEditor: React.FC<{
replaceEdges = edgeChanges.filter(
(change) => change.type === "replace",
),
- removedEdges = edgeChanges.filter((change) => change.type === "remove"),
- selectedEdges = edgeChanges.filter(
- (change) => change.type === "select",
- );
+ removedEdges = edgeChanges.filter((change) => change.type === "remove");
if (addedEdges.length > 0 || removedEdges.length > 0) {
setNodes((nds) => {
diff --git a/autogpt_platform/frontend/src/components/NodeOutputs.tsx b/autogpt_platform/frontend/src/components/NodeOutputs.tsx
index fcedf1f408..1a6ad26e0a 100644
--- a/autogpt_platform/frontend/src/components/NodeOutputs.tsx
+++ b/autogpt_platform/frontend/src/components/NodeOutputs.tsx
@@ -26,15 +26,23 @@ export default function NodeOutputs({
Data:
- {dataArray.map((item, index) => (
+ {dataArray.slice(0, 10).map((item, index) => (
- {index < dataArray.length - 1 && ", "}
+ {index < Math.min(dataArray.length, 10) - 1 && ", "}
))}
+ {dataArray.length > 10 && (
+
+
+ ⋮
+
+ and {dataArray.length - 10} more
+
+ )}
diff --git a/autogpt_platform/frontend/src/components/OttoChatWidget.tsx b/autogpt_platform/frontend/src/components/OttoChatWidget.tsx
index 3e111165a8..3eaf75951d 100644
--- a/autogpt_platform/frontend/src/components/OttoChatWidget.tsx
+++ b/autogpt_platform/frontend/src/components/OttoChatWidget.tsx
@@ -212,7 +212,7 @@ export default function OttoChatWidget({
{children}
),
code(props) {
- const { children, className, node, ...rest } = props;
+ const { children, className, node: _, ...rest } = props;
const match = /language-(\w+)/.exec(className || "");
return match ? (
diff --git a/autogpt_platform/frontend/src/components/RunnerUIWrapper.tsx b/autogpt_platform/frontend/src/components/RunnerUIWrapper.tsx
index 5fef2152f2..2f72754205 100644
--- a/autogpt_platform/frontend/src/components/RunnerUIWrapper.tsx
+++ b/autogpt_platform/frontend/src/components/RunnerUIWrapper.tsx
@@ -104,7 +104,10 @@ const RunnerUIWrapper = forwardRef(
(node.data.hardcodedValues as any).description ||
"Output from the agent",
},
- result: (node.data.executionResults as any)?.at(-1)?.data?.output,
+ result:
+ (node.data.executionResults as any)
+ ?.map((result: any) => result?.data?.output)
+ .join("\n--\n") || "No output yet",
}) satisfies BlockOutput,
);
diff --git a/autogpt_platform/frontend/src/components/SchemaTooltip.tsx b/autogpt_platform/frontend/src/components/SchemaTooltip.tsx
index 313b55cb6b..b4010287bc 100644
--- a/autogpt_platform/frontend/src/components/SchemaTooltip.tsx
+++ b/autogpt_platform/frontend/src/components/SchemaTooltip.tsx
@@ -22,7 +22,7 @@ const SchemaTooltip: React.FC<{ description?: string }> = ({ description }) => {
(
+ a: ({ node: _, ...props }) => (
{
setIsAddMoneyDialogOpen(false);
try {
diff --git a/autogpt_platform/frontend/src/components/admin/spending/admin-grant-history-data-table.tsx b/autogpt_platform/frontend/src/components/admin/spending/admin-grant-history-data-table.tsx
index 818d385d04..80695b803c 100644
--- a/autogpt_platform/frontend/src/components/admin/spending/admin-grant-history-data-table.tsx
+++ b/autogpt_platform/frontend/src/components/admin/spending/admin-grant-history-data-table.tsx
@@ -48,7 +48,7 @@ export async function AdminUserGrantHistory({
const isPurchased = type === CreditTransactionType.TOP_UP;
const isSpent = type === CreditTransactionType.USAGE;
- let displayText = type;
+ const displayText = type;
let bgColor = "";
if (isGrant) {
diff --git a/autogpt_platform/frontend/src/components/admin/spending/search-filter-form.tsx b/autogpt_platform/frontend/src/components/admin/spending/search-filter-form.tsx
index 5e0160cbdd..f301461071 100644
--- a/autogpt_platform/frontend/src/components/admin/spending/search-filter-form.tsx
+++ b/autogpt_platform/frontend/src/components/admin/spending/search-filter-form.tsx
@@ -15,7 +15,6 @@ import {
} from "@/components/ui/select";
export function SearchAndFilterAdminSpending({
- initialStatus,
initialSearch,
}: {
initialStatus?: CreditTransactionType;
@@ -74,7 +73,7 @@ export function SearchAndFilterAdminSpending({